Skip to content
This repository was archived by the owner on Jun 19, 2024. It is now read-only.

Commit 2d15f8e

Browse files
authored
Merge pull request #55 from LabyMod/improvement/generated-method-calls
Databind performance improvements
2 parents 20d155d + cec3b51 commit 2d15f8e

15 files changed

Lines changed: 898 additions & 85 deletions

File tree

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ subprojects {
9191
apply plugin: "net.minecrell.licenser"
9292
apply plugin: "signing"
9393

94+
sourceCompatibility = 1.8
95+
targetCompatibility = 1.8
96+
9497
license {
9598
header = rootProject.file("LICENSE_HEADER")
9699

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ rootProject.name = 'ultralight-java'
33
include 'ultralight-java-base'
44
include 'ultralight-java-native'
55
include 'ultralight-java-databind'
6+
include 'ultralight-java-databind-codegen'
67

78
include 'ultralight-java-gpu'
89
include 'ultralight-java-gpu-native'
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
plugins {
2+
id 'java-library'
3+
id 'maven-publish'
4+
}
5+
6+
group 'com.labymedia'
7+
8+
jar {
9+
manifest {
10+
attributes(
11+
'Automatic-Module-Name': 'com.labymedia.ultralight.databind.codegen'
12+
)
13+
}
14+
}
15+
16+
repositories {
17+
mavenCentral()
18+
}
19+
20+
dependencies {
21+
implementation project(':ultralight-java-base')
22+
implementation project(':ultralight-java-databind')
23+
implementation group: 'org.javassist', name: 'javassist', version: '3.27.0-GA'
24+
}
25+
26+
commonPublish(project) {
27+
pom {
28+
name = "UltralightJava Databind Codegen"
29+
description = "Optional Codegen for UltralightJava Databind"
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Ultralight Java - Java wrapper for the Ultralight web engine
3+
* Copyright (C) 2020 - 2021 LabyMedia and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18+
*/
19+
20+
package com.labymedia.ultralight.databind.codegen.call.property;
21+
22+
/**
23+
* Exception thrown when there was a problem generating a new {@link SingleGeneratedPropertyCaller}.
24+
*/
25+
public class CallerGenerationException extends RuntimeException {
26+
27+
/**
28+
* {@inheritDoc}
29+
*/
30+
public CallerGenerationException(String message, Throwable cause) {
31+
super(message, cause);
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Ultralight Java - Java wrapper for the Ultralight web engine
3+
* Copyright (C) 2020 - 2021 LabyMedia and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18+
*/
19+
20+
package com.labymedia.ultralight.databind.codegen.call.property;
21+
22+
import com.labymedia.ultralight.databind.call.property.PropertyCaller;
23+
import com.labymedia.ultralight.databind.call.property.ReflectivePropertyCaller;
24+
import com.labymedia.ultralight.javascript.interop.JavascriptInteropException;
25+
import javassist.CannotCompileException;
26+
import javassist.NotFoundException;
27+
28+
import java.io.IOException;
29+
import java.lang.reflect.Constructor;
30+
import java.lang.reflect.Field;
31+
import java.lang.reflect.InvocationTargetException;
32+
import java.lang.reflect.Method;
33+
import java.util.HashMap;
34+
import java.util.Map;
35+
36+
/**
37+
* Calls properties on java objects or classes via lazy-bytecode-generated {@link SingleGeneratedPropertyCaller}s.
38+
* This implementation is recommended if there are a lot of calls in a short time on the same property.
39+
* Although this implementation is faster than {@link ReflectivePropertyCaller},
40+
* the first call might be slower because of the lazy generation.
41+
*/
42+
public class GeneratedPropertyCaller implements PropertyCaller {
43+
44+
/**
45+
* All already generated {@link SingleGeneratedPropertyCaller}s for methods.
46+
*/
47+
private final Map<Method, SingleGeneratedPropertyCaller> methodCallers;
48+
/**
49+
* All already generated {@link SingleGeneratedPropertyCaller}s for constructors.
50+
*/
51+
private final Map<Constructor<?>, SingleGeneratedPropertyCaller> constructorCallers;
52+
/**
53+
* All already generated {@link SingleGeneratedPropertyCaller}s for fields.
54+
*/
55+
private final Map<Field, SingleGeneratedPropertyCaller> fieldCallers;
56+
57+
/**
58+
* Generator for new {@link SingleGeneratedPropertyCaller}s.
59+
*/
60+
private final PropertyCallerGenerator callerGenerator;
61+
62+
private GeneratedPropertyCaller() {
63+
this.methodCallers = new HashMap<>();
64+
this.constructorCallers = new HashMap<>();
65+
this.fieldCallers = new HashMap<>();
66+
67+
this.callerGenerator = new PropertyCallerGenerator();
68+
}
69+
70+
/**
71+
* {@inheritDoc}
72+
*/
73+
@Override
74+
public Object callMethod(Object instance, Method method, Object[] parameters) throws JavascriptInteropException {
75+
SingleGeneratedPropertyCaller propertyCaller = this.methodCallers.computeIfAbsent(method, key -> {
76+
try {
77+
return this.callerGenerator.generateMethodCaller(method);
78+
} catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | IOException exception) {
79+
throw new CallerGenerationException("Failed to generate caller for method " + method.getName(), exception);
80+
}
81+
});
82+
83+
try {
84+
return propertyCaller.callProperty(instance, parameters);
85+
} catch (Exception exception) {
86+
throw new JavascriptInteropException(method.getName() + " threw an exception", exception);
87+
}
88+
}
89+
90+
/**
91+
* {@inheritDoc}
92+
*/
93+
@Override
94+
public Object callConstructor(Constructor<?> constructor, Object[] parameters) throws JavascriptInteropException {
95+
SingleGeneratedPropertyCaller propertyCaller = this.constructorCallers.computeIfAbsent(constructor, key -> {
96+
try {
97+
return this.callerGenerator.generateConstructorCaller(key);
98+
} catch (NotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | IOException | CannotCompileException exception) {
99+
throw new CallerGenerationException("Failed to generate caller for constructor", exception);
100+
}
101+
});
102+
103+
try {
104+
return propertyCaller.callProperty(null, parameters);
105+
} catch (Exception exception) {
106+
throw new JavascriptInteropException("Constructor call threw an exception", exception);
107+
}
108+
}
109+
110+
/**
111+
* {@inheritDoc}
112+
*/
113+
@Override
114+
public Object callFieldGet(Object instance, Field field) throws JavascriptInteropException {
115+
SingleGeneratedPropertyCaller propertyCaller = this.fieldCallers.computeIfAbsent(field, key -> {
116+
try {
117+
return this.callerGenerator.generateFieldCaller(key);
118+
} catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | IOException exception) {
119+
throw new CallerGenerationException("Failed to generate caller for field " + field.getName(), exception);
120+
}
121+
});
122+
123+
try {
124+
return propertyCaller.callProperty(instance, null);
125+
} catch (Exception exception) {
126+
throw new JavascriptInteropException("Field call for " + field.getName() + " threw an exception", exception);
127+
}
128+
}
129+
130+
/**
131+
* {@inheritDoc}
132+
*/
133+
@Override
134+
public void callFieldSet(Object instance, Field field, Object value) throws JavascriptInteropException {
135+
SingleGeneratedPropertyCaller propertyCaller = this.fieldCallers.computeIfAbsent(field, key -> {
136+
try {
137+
return this.callerGenerator.generateFieldCaller(key);
138+
} catch (NotFoundException | CannotCompileException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException | IOException exception) {
139+
throw new CallerGenerationException("Failed to generate caller for field " + field.getName(), exception);
140+
}
141+
});
142+
143+
try {
144+
propertyCaller.callProperty(instance, new Object[]{value});
145+
} catch (Exception exception) {
146+
throw new JavascriptInteropException("Field call for " + field.getName() + " threw an exception", exception);
147+
}
148+
}
149+
150+
/**
151+
* Factory for {@link GeneratedPropertyCaller}.
152+
*/
153+
public static class Factory implements PropertyCaller.Factory {
154+
155+
/**
156+
* @return A new {@link GeneratedPropertyCaller} instance
157+
*/
158+
@Override
159+
public GeneratedPropertyCaller create() {
160+
return new GeneratedPropertyCaller();
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)