entry : methodInjectors.entrySet()) {
+ renderer.addInjector(entry.getKey(), entry.getValue());
+ }
try {
for (RendererListener listener : rendererListeners) {
listener.begin(renderer, target);
diff --git a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
index fc0f2cfbc..2acbda0af 100644
--- a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
+++ b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
@@ -18,6 +18,7 @@ package org.teavm.vm.spi;
import java.util.Properties;
import org.teavm.dependency.DependencyListener;
import org.teavm.javascript.ni.Generator;
+import org.teavm.javascript.ni.Injector;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.MethodReference;
import org.teavm.vm.TeaVM;
@@ -36,6 +37,8 @@ public interface TeaVMHost {
void add(MethodReference methodRef, Generator generator);
+ void add(MethodReference methodRef, Injector injector);
+
void add(RendererListener listener);
/**
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
index 7b50dfe88..3524b52d9 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
@@ -15,10 +15,7 @@
*/
package org.teavm.platform.metadata;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
/**
* Marks a valid resource interface. Resource interface is an interface, that has get* and set* methods,
@@ -33,5 +30,7 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
+@Inherited
+@Documented
public @interface Resource {
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java
index 6589f4c8b..ad16bfc25 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformPlugin.java
@@ -26,5 +26,8 @@ public class PlatformPlugin implements TeaVMPlugin {
@Override
public void install(TeaVMHost host) {
host.add(new MetadataProviderTransformer());
+ host.add(new ResourceTransformer());
+ host.add(new ResourceAccessorTransformer(host));
+ host.add(new ResourceAccessorDependencyListener());
}
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
new file mode 100644
index 000000000..e91ca89c2
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.plugin;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+final class ResourceAccessor {
+ public static native Object get(Object obj, String propertyName);
+
+ public static native void put(Object obj, String propertyName, Object elem);
+
+ public static native Object get(Object obj, int index);
+
+ public static native Object add(Object obj, Object elem);
+
+ public static native boolean has(Object obj, String key);
+
+ public static native boolean size(Object obj);
+
+ public static native int castToInt(Object obj);
+
+ public static native Integer castToIntWrapper(Object obj);
+
+ public static native short castToShort(Object obj);
+
+ public static native Short castToShortWrapper(Object obj);
+
+ public static native byte castToByte(Object obj);
+
+ public static native Byte castToByteWrapper(Object obj);
+
+ public static native boolean castToBoolean(Object obj);
+
+ public static native Boolean castToBooleanWrapper(Object obj);
+
+ public static native float castToFloat(Object obj);
+
+ public static native Float castToFloatWrapper(Object obj);
+
+ public static native double castToDouble(Object obj);
+
+ public static native Double castToDoubleWrapper(Object obj);
+
+ public static native String castToString(Object obj);
+
+ public static native Object castFromInt(int value);
+
+ public static native Object castFromIntWrapper(Integer value);
+
+ public static native Object castFromShort(short value);
+
+ public static native Object castFromShortWrapper(Short value);
+
+ public static native Object castFromByte(byte value);
+
+ public static native Object castFromByteWrapper(Byte value);
+
+ public static native Object castFromBoolean(boolean value);
+
+ public static native Object castFromBooleanWrapper(Boolean value);
+
+ public static native Object castFromFloat(float value);
+
+ public static native Object castFromFloatWrapper(Float value);
+
+ public static native Object castFromDouble(double value);
+
+ public static native Object castFromDoubleWrapper(Double value);
+
+ public static native Object castFromString(String value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java
new file mode 100644
index 000000000..98345dbd1
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.plugin;
+
+import org.teavm.dependency.DependencyAgent;
+import org.teavm.dependency.DependencyListener;
+import org.teavm.dependency.FieldDependency;
+import org.teavm.dependency.MethodDependency;
+import org.teavm.model.MethodReference;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+class ResourceAccessorDependencyListener implements DependencyListener {
+ @Override
+ public void started(DependencyAgent agent) {
+ }
+
+ @Override
+ public void classAchieved(DependencyAgent agent, String className) {
+ }
+
+ @Override
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
+ switch (method.getReference().getName()) {
+ case "castToIntWrapper":
+ castToWrapper(agent, method, Integer.class, int.class);
+ break;
+ case "castToShortWrapper":
+ castToWrapper(agent, method, Short.class, short.class);
+ break;
+ case "castToByteWrapper":
+ castToWrapper(agent, method, Byte.class, byte.class);
+ break;
+ case "castToBooleanWrapper":
+ castToWrapper(agent, method, Boolean.class, boolean.class);
+ break;
+ case "castToFloatWrapper":
+ castToWrapper(agent, method, Float.class, float.class);
+ break;
+ case "castToDoubleWrapper":
+ castToWrapper(agent, method, Double.class, double.class);
+ break;
+ case "castFromIntegerWrapper":
+ castFromWrapper(agent, method, Integer.class, int.class);
+ break;
+ case "castFromShortWrapper":
+ castFromWrapper(agent, method, Short.class, short.class);
+ break;
+ case "castFromByteWrapper":
+ castFromWrapper(agent, method, Byte.class, byte.class);
+ break;
+ case "castFromBooleanWrapper":
+ castFromWrapper(agent, method, Boolean.class, boolean.class);
+ break;
+ case "castFromFloatWrapper":
+ castFromWrapper(agent, method, Float.class, float.class);
+ break;
+ case "castFromDoubleWrapper":
+ castFromWrapper(agent, method, Double.class, double.class);
+ break;
+ case "castToString":
+ method.getResult().propagate("java.lang.String");
+ break;
+ }
+ }
+
+ private void castToWrapper(DependencyAgent agent, MethodDependency method, Class> wrapper, Class> primitive) {
+ method.getResult().propagate(wrapper.getName());
+ agent.linkMethod(new MethodReference(wrapper, "valueOf", primitive, wrapper), method.getStack()).use();
+ }
+
+ private void castFromWrapper(DependencyAgent agent, MethodDependency method, Class> wrapper, Class> primitive) {
+ String primitiveName = primitive.getName();
+ agent.linkMethod(new MethodReference(wrapper, primitiveName + "Value", primitive), method.getStack()).use();
+ }
+
+ @Override
+ public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
+ }
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
new file mode 100644
index 000000000..5e8d7542d
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.plugin;
+
+import java.io.IOException;
+import org.teavm.javascript.ast.ConstantExpr;
+import org.teavm.javascript.ast.Expr;
+import org.teavm.javascript.ni.Injector;
+import org.teavm.javascript.ni.InjectorContext;
+import org.teavm.model.MethodReference;
+import org.teavm.model.ValueType;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+class ResourceAccessorGenerator implements Injector {
+ @Override
+ public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
+ switch (methodRef.getName()) {
+ case "get":
+ if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append('[');
+ context.writeExpr(context.getArgument(2));
+ context.getWriter().append(']');
+ } else {
+ context.writeExpr(context.getArgument(1));
+ writePropertyAccessor(context, context.getArgument(2));
+ }
+ break;
+ case "put":
+ context.getWriter().append('(');
+ if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append('[');
+ context.writeExpr(context.getArgument(2));
+ } else {
+ context.writeExpr(context.getArgument(1));
+ writePropertyAccessor(context, context.getArgument(2));
+ }
+ context.getWriter().append(']').ws().append('=').ws();
+ context.writeExpr(context.getArgument(3));
+ context.getWriter().append(')');
+ break;
+ case "add":
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(".push(");
+ context.writeExpr(context.getArgument(2));
+ context.getWriter().append(')');
+ break;
+ case "has":
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(".hasOwnProperty(");
+ writeStringExpr(context, context.getArgument(2));
+ context.getWriter().append(')');
+ break;
+ case "size":
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(".length");
+ break;
+ case "castToInt":
+ case "castToShort":
+ case "castToByte":
+ case "castToBoolean":
+ case "castToFloat":
+ case "castToDouble":
+ case "castFromInt":
+ case "castFromShort":
+ case "castFromByte":
+ case "castFromBoolean":
+ case "castFromFloat":
+ case "castFromDouble":
+ context.writeExpr(context.getArgument(1));
+ break;
+ case "castToIntWrapper":
+ castToWrapper(context, Integer.class, int.class);
+ break;
+ case "castToShortWrapper":
+ castToWrapper(context, Short.class, short.class);
+ break;
+ case "castToByteWrapper":
+ castToWrapper(context, Byte.class, byte.class);
+ break;
+ case "castToBooleanWrapper":
+ castToWrapper(context, Boolean.class, boolean.class);
+ break;
+ case "castToFloatWrapper":
+ castToWrapper(context, Float.class, float.class);
+ break;
+ case "castToDoubleWrapper":
+ castToWrapper(context, Double.class, double.class);
+ break;
+ case "castFromIntWrapper":
+ castFromWrapper(context, Integer.class, int.class);
+ break;
+ case "castFromShortWrapper":
+ castFromWrapper(context, Short.class, short.class);
+ break;
+ case "castFromByteWrapper":
+ castFromWrapper(context, Byte.class, byte.class);
+ break;
+ case "castFromBooleanWrapper":
+ castFromWrapper(context, Boolean.class, boolean.class);
+ break;
+ case "castFromFloatWrapper":
+ castFromWrapper(context, Float.class, float.class);
+ break;
+ case "castFromDoubleWrapper":
+ castFromWrapper(context, Double.class, double.class);
+ break;
+ case "castToString":
+ context.getWriter().append("$rt_str(");
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(")");
+ break;
+ case "castFromString":
+ context.getWriter().append("$rt_ustr(");
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(")");
+ break;
+ }
+ }
+
+ private void castToWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
+ context.getWriter().appendMethodBody(new MethodReference(wrapper, "valueOf", primitive, wrapper)).append('(');
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(')');
+ }
+
+ private void castFromWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
+ String primitiveName = primitive.getName();
+ context.getWriter().appendMethodBody(new MethodReference(wrapper, primitiveName + "Value", primitive))
+ .append('(');
+ context.writeExpr(context.getArgument(1));
+ context.getWriter().append(')');
+ }
+
+ private void writePropertyAccessor(InjectorContext context, Expr property) throws IOException {
+ if (property instanceof ConstantExpr) {
+ String str = (String)((ConstantExpr)property).getValue();
+ if (str.isEmpty()) {
+ context.getWriter().append("[\"\"]");
+ return;
+ }
+ if (isValidIndentifier(str)) {
+ context.getWriter().append(".").append(str);
+ return;
+ }
+ }
+ context.getWriter().append("[$rt_ustr(");
+ context.writeExpr(property);
+ context.getWriter().append(")]");
+ }
+
+ private void writeStringExpr(InjectorContext context, Expr expr) throws IOException {
+ if (expr instanceof ConstantExpr) {
+ String str = (String)((ConstantExpr)expr).getValue();
+ context.getWriter().append('"');
+ context.writeEscaped(str);
+ context.getWriter().append('"');
+ return;
+ }
+ context.getWriter().append("$rt_ustr(");
+ context.writeExpr(expr);
+ context.getWriter().append(")");
+ }
+
+ private boolean isValidIndentifier(String str) {
+ if (!Character.isJavaIdentifierStart(str.charAt(0))) {
+ return false;
+ }
+ for (int i = 1; i < str.length(); ++i) {
+ if (!Character.isJavaIdentifierPart(str.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java
new file mode 100644
index 000000000..bb0ae0c26
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.plugin;
+
+import org.teavm.model.ClassHolder;
+import org.teavm.model.ClassHolderTransformer;
+import org.teavm.model.ClassReaderSource;
+import org.teavm.model.MethodHolder;
+import org.teavm.vm.spi.TeaVMHost;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+class ResourceAccessorTransformer implements ClassHolderTransformer {
+ private TeaVMHost vm;
+
+ public ResourceAccessorTransformer(TeaVMHost vm) {
+ this.vm = vm;
+ }
+
+ @Override
+ public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
+ ResourceAccessorGenerator generator = new ResourceAccessorGenerator();
+ if (cls.getName().equals(ResourceAccessor.class)) {
+ for (MethodHolder method : cls.getMethods()) {
+ vm.add(method.getReference(), generator);
+ }
+ }
+ }
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
new file mode 100644
index 000000000..cbb343123
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.plugin;
+
+import org.teavm.model.ClassHolder;
+import org.teavm.model.ClassHolderTransformer;
+import org.teavm.model.ClassReaderSource;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+class ResourceTransformer implements ClassHolderTransformer {
+ @Override
+ public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
+ }
+}
From 7e3d62a85d0717b2500056923595ef11b1abc70e Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Thu, 5 Jun 2014 17:22:02 +0400
Subject: [PATCH 06/16] Starts implementation of resource access transformer
---
.../platform/plugin/ResourceTransformer.java | 117 +++++++++++++++++-
1 file changed, 114 insertions(+), 3 deletions(-)
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
index cbb343123..c767f169d 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -15,9 +15,15 @@
*/
package org.teavm.platform.plugin;
-import org.teavm.model.ClassHolder;
-import org.teavm.model.ClassHolderTransformer;
-import org.teavm.model.ClassReaderSource;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.teavm.model.*;
+import org.teavm.model.instructions.EmptyInstruction;
+import org.teavm.model.instructions.InvocationType;
+import org.teavm.model.instructions.InvokeInstruction;
+import org.teavm.model.instructions.StringConstantInstruction;
+import org.teavm.platform.metadata.Resource;
/**
*
@@ -26,5 +32,110 @@ import org.teavm.model.ClassReaderSource;
class ResourceTransformer implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
+ for (MethodHolder method : cls.getMethods()) {
+ Program program = method.getProgram();
+ if (program != null) {
+ transformProgram(innerSource, program);
+ }
+ }
+ }
+
+ private void transformProgram(ClassReaderSource innerSource, Program program) {
+ for (int i = 0; i < program.basicBlockCount(); ++i) {
+ transformBasicBlock(innerSource, program.basicBlockAt(i));
+ }
+ }
+
+ private void transformBasicBlock(ClassReaderSource innerSource, BasicBlock block) {
+ List instructions = block.getInstructions();
+ for (int i = 0; i < instructions.size(); ++i) {
+ Instruction insn = instructions.get(i);
+ if (insn instanceof InvokeInstruction) {
+ InvokeInstruction invoke = (InvokeInstruction)insn;
+ List replacement = transformInvoke(innerSource, invoke);
+ if (replacement != null) {
+ instructions.set(i, new EmptyInstruction());
+ instructions.addAll(i, replacement);
+ i += replacement.size();
+ }
+ }
+ }
+ }
+
+ private List transformInvoke(ClassReaderSource innerSource, InvokeInstruction insn) {
+ if (insn.getType() != InvocationType.VIRTUAL) {
+ return null;
+ }
+ MethodReference method = insn.getMethod();
+ ClassReader iface = innerSource.get(method.getClassName());
+ if (iface.getAnnotations().get(Resource.class.getName()) == null) {
+ return null;
+ }
+ if (method.getName().startsWith("get")) {
+ if (method.getName().length() > 3) {
+ return transformGetterInvocation(insn, method.getName().substring(3));
+ }
+ } else if (method.getName().startsWith("is")) {
+ if (method.getName().length() > 2) {
+ return transformGetterInvocation(insn, method.getName().substring(2));
+ }
+ } else if (method.getName().startsWith("set")) {
+ if (method.getName().length() > 3) {
+ return transformSetterInvocation(insn, method.getName().substring(3));
+ }
+ }
+ return null;
+ }
+
+ private List transformGetterInvocation(InvokeInstruction insn, String property) {
+ if (insn.getReceiver() == null) {
+ return Collections.emptyList();
+ }
+ ValueType type = insn.getMethod().getDescriptor().getResultType();
+ Program program = insn.getProgram();
+ List instructions = new ArrayList<>();
+ if (type instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive)type).getKind()) {
+ case BOOLEAN:
+ Variable nameVar = program.createVariable();
+ Variable resultVar = program.createVariable();
+ StringConstantInstruction nameInsn = new StringConstantInstruction();
+ nameInsn.setConstant(property);
+ nameInsn.setReceiver(nameVar);
+ instructions.add(nameInsn);
+ InvokeInstruction accessorInvoke = new InvokeInstruction();
+ accessorInvoke.setType(InvocationType.SPECIAL);
+ accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
+ Object.class, String.class, Object.class));
+ accessorInvoke.getArguments().add(insn.getInstance());
+ accessorInvoke.getArguments().add(nameVar);
+ accessorInvoke.setReceiver(resultVar);
+ instructions.add(accessorInvoke);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToBoolean", Object.class,
+ boolean.class));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ return instructions;
+ }
+ } else if (type instanceof ValueType.Object) {
+
+ }
+ return null;
+ }
+
+ private List transformSetterInvocation(InvokeInstruction insn, String property) {
+ return null;
+ }
+
+ private String getPropertyName(String name) {
+ if (name.length() == 1) {
+ return name;
+ }
+ if (Character.isUpperCase(name.charAt(1))) {
+ return name;
+ }
+ return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
}
From 8956e8b8d0546da58d77d3145cc9ebee62ce83d4 Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Fri, 6 Jun 2014 17:02:34 +0400
Subject: [PATCH 07/16] Implements transformer that substitutes all invocations
of resources with ResourcesAccessor
---
.../platform/plugin/ResourceAccessor.java | 4 +-
.../platform/plugin/ResourceTransformer.java | 151 ++++++++++++++----
2 files changed, 124 insertions(+), 31 deletions(-)
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
index e91ca89c2..7c399174b 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
@@ -26,11 +26,11 @@ final class ResourceAccessor {
public static native Object get(Object obj, int index);
- public static native Object add(Object obj, Object elem);
+ public static native void add(Object obj, Object elem);
public static native boolean has(Object obj, String key);
- public static native boolean size(Object obj);
+ public static native int size(Object obj);
public static native int castToInt(Object obj);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
index c767f169d..ee4d82b4d 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -16,14 +16,14 @@
package org.teavm.platform.plugin;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.teavm.model.*;
-import org.teavm.model.instructions.EmptyInstruction;
-import org.teavm.model.instructions.InvocationType;
-import org.teavm.model.instructions.InvokeInstruction;
-import org.teavm.model.instructions.StringConstantInstruction;
+import org.teavm.model.instructions.*;
import org.teavm.platform.metadata.Resource;
+import org.teavm.platform.metadata.ResourceArray;
+import org.teavm.platform.metadata.ResourceMap;
/**
*
@@ -67,21 +67,35 @@ class ResourceTransformer implements ClassHolderTransformer {
return null;
}
MethodReference method = insn.getMethod();
+ if (method.getClassName().equals(ResourceArray.class.getName()) ||
+ method.getClassName().equals(ResourceMap.class.getName())) {
+ InvokeInstruction accessInsn = new InvokeInstruction();
+ accessInsn.setType(InvocationType.SPECIAL);
+ ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
+ types[0] = ValueType.object("java.lang.Object");
+ System.arraycopy(method.getDescriptor().getSignature(), 0, types, 1,
+ method.getDescriptor().parameterCount() + 1);
+ accessInsn.setMethod(new MethodReference(ResourceAccessor.class.getName(), method.getName(), types));
+ accessInsn.getArguments().add(insn.getInstance());
+ accessInsn.getArguments().addAll(insn.getArguments());
+ accessInsn.setReceiver(insn.getReceiver());
+ return Arrays.asList(accessInsn);
+ }
ClassReader iface = innerSource.get(method.getClassName());
if (iface.getAnnotations().get(Resource.class.getName()) == null) {
return null;
}
if (method.getName().startsWith("get")) {
if (method.getName().length() > 3) {
- return transformGetterInvocation(insn, method.getName().substring(3));
+ return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3)));
}
} else if (method.getName().startsWith("is")) {
if (method.getName().length() > 2) {
- return transformGetterInvocation(insn, method.getName().substring(2));
+ return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2)));
}
} else if (method.getName().startsWith("set")) {
if (method.getName().length() > 3) {
- return transformSetterInvocation(insn, method.getName().substring(3));
+ return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3)));
}
}
return null;
@@ -92,39 +106,118 @@ class ResourceTransformer implements ClassHolderTransformer {
return Collections.emptyList();
}
ValueType type = insn.getMethod().getDescriptor().getResultType();
- Program program = insn.getProgram();
List instructions = new ArrayList<>();
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive)type).getKind()) {
case BOOLEAN:
- Variable nameVar = program.createVariable();
- Variable resultVar = program.createVariable();
- StringConstantInstruction nameInsn = new StringConstantInstruction();
- nameInsn.setConstant(property);
- nameInsn.setReceiver(nameVar);
- instructions.add(nameInsn);
- InvokeInstruction accessorInvoke = new InvokeInstruction();
- accessorInvoke.setType(InvocationType.SPECIAL);
- accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
- Object.class, String.class, Object.class));
- accessorInvoke.getArguments().add(insn.getInstance());
- accessorInvoke.getArguments().add(nameVar);
- accessorInvoke.setReceiver(resultVar);
- instructions.add(accessorInvoke);
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToBoolean", Object.class,
- boolean.class));
- castInvoke.getArguments().add(resultVar);
- castInvoke.setReceiver(insn.getReceiver());
+ getAndCastProperty(insn, property, instructions, boolean.class);
return instructions;
+ case BYTE:
+ getAndCastProperty(insn, property, instructions, byte.class);
+ return instructions;
+ case SHORT:
+ getAndCastProperty(insn, property, instructions, short.class);
+ return instructions;
+ case INTEGER:
+ getAndCastProperty(insn, property, instructions, int.class);
+ return instructions;
+ case FLOAT:
+ getAndCastProperty(insn, property, instructions, float.class);
+ return instructions;
+ case DOUBLE:
+ getAndCastProperty(insn, property, instructions, double.class);
+ return instructions;
+ case CHARACTER:
+ case LONG:
+ break;
}
} else if (type instanceof ValueType.Object) {
-
+ switch (((ValueType.Object)type).getClassName()) {
+ case "java.lang.Boolean":
+ getAndCastPropertyToWrapper(insn, property, instructions, boolean.class, Boolean.class);
+ return instructions;
+ case "java.lang.Byte":
+ getAndCastPropertyToWrapper(insn, property, instructions, byte.class, Byte.class);
+ return instructions;
+ case "java.lang.Short":
+ getAndCastPropertyToWrapper(insn, property, instructions, short.class, Short.class);
+ return instructions;
+ case "java.lang.Integer":
+ getAndCastPropertyToWrapper(insn, property, instructions, int.class, Integer.class);
+ return instructions;
+ case "java.lang.Float":
+ getAndCastPropertyToWrapper(insn, property, instructions, float.class, Float.class);
+ return instructions;
+ case "java.lang.Double":
+ getAndCastPropertyToWrapper(insn, property, instructions, double.class, Double.class);
+ return instructions;
+ default: {
+ Variable resultVar = insn.getProgram().createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ CastInstruction castInsn = new CastInstruction();
+ castInsn.setReceiver(insn.getReceiver());
+ castInsn.setTargetType(type);
+ castInsn.setValue(resultVar);
+ instructions.add(castInsn);
+ return instructions;
+ }
+ }
}
return null;
}
+ private void getProperty(InvokeInstruction insn, String property, List instructions,
+ Variable resultVar) {
+ Program program = insn.getProgram();
+ Variable nameVar = program.createVariable();
+ StringConstantInstruction nameInsn = new StringConstantInstruction();
+ nameInsn.setConstant(property);
+ nameInsn.setReceiver(nameVar);
+ instructions.add(nameInsn);
+ InvokeInstruction accessorInvoke = new InvokeInstruction();
+ accessorInvoke.setType(InvocationType.SPECIAL);
+ accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
+ Object.class, String.class, Object.class));
+ accessorInvoke.getArguments().add(insn.getInstance());
+ accessorInvoke.getArguments().add(nameVar);
+ accessorInvoke.setReceiver(resultVar);
+ instructions.add(accessorInvoke);
+ }
+
+ private void getAndCastProperty(InvokeInstruction insn, String property, List instructions,
+ Class> primitive) {
+ Program program = insn.getProgram();
+ Variable resultVar = program.createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized,
+ Object.class, primitive));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ instructions.add(castInvoke);
+ }
+
+ private void getAndCastPropertyToWrapper(InvokeInstruction insn, String property, List instructions,
+ Class> primitive, Class> wrapper) {
+ Program program = insn.getProgram();
+ Variable resultVar = program.createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Primitive",
+ Object.class, wrapper));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ instructions.add(castInvoke);
+ }
+
private List transformSetterInvocation(InvokeInstruction insn, String property) {
return null;
}
From c6e7b30bedb40dff369ebfeba44d4cc234aacf18 Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Fri, 6 Jun 2014 18:18:52 +0400
Subject: [PATCH 08/16] Adds tests for metadata generators
---
pom.xml | 5 +
teavm-classlib/pom.xml | 22 +++++
.../metadata/DependentTestResource.java | 5 +-
.../metadata/MetadataGeneratorTest.java | 59 +++++++++++
.../teavm/platform/metadata/TestResource.java | 99 +++++++++++++++++++
.../metadata/TestResourceGenerator.java | 65 ++++++++++++
.../java/org/teavm/javascript/Decompiler.java | 1 +
.../MetadataProviderNativeGenerator.java | 2 +-
.../plugin/MetadataProviderTransformer.java | 5 +-
.../plugin/ResourceAccessorTransformer.java | 4 +-
.../platform/plugin/ResourceTransformer.java | 2 +-
.../teavm/platform/metadata/TestResource.java | 31 ------
12 files changed, 262 insertions(+), 38 deletions(-)
rename teavm-platform/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java => teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java (87%)
create mode 100644 teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
create mode 100644 teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
create mode 100644 teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
delete mode 100644 teavm-platform/src/test/java/org/teavm/platform/metadata/TestResource.java
diff --git a/pom.xml b/pom.xml
index c144930dc..6e0e1f8f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -178,6 +178,11 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.17
+
diff --git a/teavm-classlib/pom.xml b/teavm-classlib/pom.xml
index 199365cb0..57d85caa8 100644
--- a/teavm-classlib/pom.xml
+++ b/teavm-classlib/pom.xml
@@ -30,6 +30,12 @@
junit
test
+
+ org.teavm
+ teavm-platform
+ ${project.version}
+ test
+
org.teavm
teavm-core
@@ -51,6 +57,13 @@
org.teavm
teavm-maven-plugin
${project.version}
+
+
+ org.teavm
+ teavm-platform
+ ${project.version}
+
+
generate-javascript-tests
@@ -96,6 +109,15 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ org/teavm/platform/metadata/*.java
+
+
+
org.apache.maven.plugins
maven-source-plugin
diff --git a/teavm-platform/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
similarity index 87%
rename from teavm-platform/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
rename to teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
index 4f240dd36..3415d46a1 100644
--- a/teavm-platform/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
@@ -19,6 +19,9 @@ package org.teavm.platform.metadata;
*
* @author Alexey Andreev
*/
-public class MetadataGeneratorTest {
+@Resource
+public interface DependentTestResource {
+ String getBar();
+ void setBar(String bar);
}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
new file mode 100644
index 000000000..280ee32f5
--- /dev/null
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public class MetadataGeneratorTest {
+ @MetadataProvider(TestResourceGenerator.class)
+ private native TestResource getNull();
+
+ @Test
+ public void nullExposed() {
+ assertNull(getNull());
+ }
+
+ @MetadataProvider(TestResourceGenerator.class)
+ private native TestResource getInt();
+
+ @Test
+ public void intExposed() {
+ assertEquals(23, getInt());
+ }
+
+ @MetadataProvider(TestResourceGenerator.class)
+ private native TestResource getResource();
+
+ @Test
+ public void resourceObjectExposed() {
+ TestResource res = getResource();
+ assertEquals(23, res.getA());
+ assertFalse(res.getB());
+ assertEquals(24, res.getD());
+ assertEquals(25, res.getE());
+ assertEquals(3.14, res.getF(), 0.001);
+ assertEquals(2.72, res.getG(), 0.001);
+ assertEquals(Integer.valueOf(26), res.getH());
+ assertNull(res.getI());
+ assertEquals(Byte.valueOf((byte)27), res.getJ());
+ assertEquals(Short.valueOf((short)28), res.getK());
+ }
+}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
new file mode 100644
index 000000000..d64800bbd
--- /dev/null
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+@Resource
+public interface TestResource {
+ int getA();
+
+ void setA(int a);
+
+ boolean getB();
+
+ void setB(boolean b);
+
+ byte getD();
+
+ void setD(byte d);
+
+ short getE();
+
+ void setE(short e);
+
+ float getF();
+
+ void setF(float f);
+
+ double getG();
+
+ void setG(double g);
+
+ Integer getH();
+
+ void setH(Integer a);
+
+ Boolean getI();
+
+ void setI(Boolean i);
+
+ Byte getJ();
+
+ void setJ(Byte d);
+
+ Short getK();
+
+ void setK(Short k);
+
+ Float getL();
+
+ void setL(Float l);
+
+ Double getM();
+
+ void setM(Double g);
+
+ String getFoo();
+
+ void setFoo(String foo);
+
+ ResourceArray getArrayA();
+
+ void setArrayA(ResourceArray arrayA);
+
+ ResourceArray getArrayB();
+
+ void setArrayB(ResourceArray arrayB);
+
+ ResourceArray> getArrayC();
+
+ void setArrayC(ResourceArray> arrayC);
+
+ ResourceMap getMapA();
+
+ void setMapA(ResourceMap mapA);
+
+ ResourceMap getMapB();
+
+ void setMapB(ResourceMap mapB);
+
+ ResourceMap> getMapC();
+
+ void setMapC(ResourceMap> mapC);
+}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
new file mode 100644
index 000000000..6b787b37c
--- /dev/null
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+import org.teavm.model.MethodReference;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public class TestResourceGenerator implements MetadataGenerator {
+ @Override
+ public Object generateMetadata(MetadataGeneratorContext context, MethodReference method) {
+ switch (method.getName()) {
+ case "getNull":
+ return null;
+ case "getInt":
+ return 23;
+ case "getResource":
+ return getResource(context);
+ default:
+ throw new RuntimeException("Unsupported method: " + method);
+ }
+ }
+
+ private Object getResource(MetadataGeneratorContext context) {
+ TestResource resource = context.createResource(TestResource.class);
+ resource.setA(23);
+ resource.setB(false);
+ resource.setD((byte)24);
+ resource.setE((short)25);
+ resource.setF(3.14f);
+ resource.setG(2.72);
+ resource.setH(26);
+ resource.setI(null);
+ resource.setJ((byte)27);
+ resource.setK((short)28);
+ resource.setL(100f);
+ resource.setM(200.0);
+
+ ResourceArray array = context.createResourceArray();
+ array.add(2);
+ array.add(3);
+ resource.setArrayA(array);
+ DependentTestResource dep = context.createResource(DependentTestResource.class);
+ dep.setBar("baz");
+ ResourceArray resArray = context.createResourceArray();
+ resArray.add(dep);
+ resource.setArrayB(resArray);
+ return resource;
+ }
+}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
index 72f45cefc..35d7f5fdd 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
@@ -85,6 +85,7 @@ public class Decompiler {
@Override public void run() {
Decompiler copy = new Decompiler(classSource, classLoader, executor);
copy.generators = generators;
+ copy.methodsToPass = methodsToPass;
result.set(index, copy.decompile(classSource.get(className)));
}
});
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
index 2d43695e4..62497207d 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
@@ -74,7 +74,7 @@ public class MetadataProviderNativeGenerator implements Generator {
// Generate resource loader
Object resource = generator.generateMetadata(metadataContext, methodRef);
- writer.append("if (!").appendMethodBody(methodRef).append("$$resource === undefined").append(") {")
+ writer.append("if (!window.hasOwnProperty(\"").appendMethodBody(methodRef).append("$$resource\")) {")
.indent().softNewLine();
writer.appendMethodBody(methodRef).append("$$resource = ");
ResourceWriterHelper.write(writer, resource);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java
index 703052af3..f8d25aadf 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java
@@ -29,10 +29,11 @@ class MetadataProviderTransformer implements ClassHolderTransformer {
for (MethodHolder method : cls.getMethods()) {
AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName());
if (providerAnnot == null) {
- return;
+ continue;
}
AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName());
- genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(null)));
+ genAnnot.getValues().put("value", new AnnotationValue(ValueType.object(
+ MetadataProviderNativeGenerator.class.getName())));
method.getAnnotations().add(genAnnot);
}
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java
index bb0ae0c26..6a3819013 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java
@@ -34,8 +34,8 @@ class ResourceAccessorTransformer implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource) {
- ResourceAccessorGenerator generator = new ResourceAccessorGenerator();
- if (cls.getName().equals(ResourceAccessor.class)) {
+ if (cls.getName().equals(ResourceAccessor.class.getName())) {
+ ResourceAccessorGenerator generator = new ResourceAccessorGenerator();
for (MethodHolder method : cls.getMethods()) {
vm.add(method.getReference(), generator);
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
index ee4d82b4d..cf7f0b4af 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -211,7 +211,7 @@ class ResourceTransformer implements ClassHolderTransformer {
String primitiveCapitalized = primitive.getName();
primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
primitiveCapitalized.substring(1);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Primitive",
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
Object.class, wrapper));
castInvoke.getArguments().add(resultVar);
castInvoke.setReceiver(insn.getReceiver());
diff --git a/teavm-platform/src/test/java/org/teavm/platform/metadata/TestResource.java b/teavm-platform/src/test/java/org/teavm/platform/metadata/TestResource.java
deleted file mode 100644
index d75474deb..000000000
--- a/teavm-platform/src/test/java/org/teavm/platform/metadata/TestResource.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2014 Alexey Andreev.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.teavm.platform.metadata;
-
-/**
- *
- * @author Alexey Andreev
- */
-@Resource
-public interface TestResource {
- int getInt();
-
- void setInt(int value);
-
- String getString();
-
- void setString(String string);
-}
From 6992c81e8de07811968a94a0f10d88598c141be1 Mon Sep 17 00:00:00 2001
From: Alexey Andreev
Date: Sat, 7 Jun 2014 15:48:57 +0400
Subject: [PATCH 09/16] Makes all current metadata provider tests passing
---
.../metadata/MetadataGeneratorTest.java | 2 +-
.../java/org/teavm/javascript/Decompiler.java | 2 +-
.../plugin/BuildTimeResourceProxyBuilder.java | 16 +++++-
.../plugin/ResourceAccessorGenerator.java | 56 +++++++++++--------
.../platform/plugin/ResourceTransformer.java | 2 +-
.../teavm/platform/plugin/ResourceWriter.java | 2 +-
6 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
index 280ee32f5..49de83443 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
@@ -32,7 +32,7 @@ public class MetadataGeneratorTest {
}
@MetadataProvider(TestResourceGenerator.class)
- private native TestResource getInt();
+ private native int getInt();
@Test
public void intExposed() {
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
index 35d7f5fdd..9a0e8078e 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java
@@ -132,7 +132,7 @@ public class Decompiler {
continue;
}
if (method.getAnnotations().get(InjectedBy.class.getName()) != null ||
- methodsToPass.contains(method)) {
+ methodsToPass.contains(method.getReference())) {
continue;
}
MethodNode methodNode = decompile(method);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
index 0baf44b47..f288a4cfd 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
@@ -17,6 +17,7 @@ package org.teavm.platform.plugin;
import java.lang.reflect.Method;
import java.util.*;
+import org.teavm.codegen.SourceWriter;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
@@ -73,11 +74,22 @@ class BuildTimeResourceProxyBuilder {
" that is not an interface");
}
scanIface(rootIface);
+ Method writeMethod;
+ try {
+ writeMethod = ResourceWriter.class.getMethod("write", SourceWriter.class);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError("Method must exist", e);
+ }
+ String[] properties = new String[propertyIndexes.size()];
+ for (Map.Entry entry : propertyIndexes.entrySet()) {
+ properties[entry.getValue()] = entry.getKey();
+ }
+ methods.put(writeMethod, new BuildTimeResourceWriterMethod(properties));
return new BuildTimeResourceProxyFactory(methods, initialData);
}
private void scanIface(Class> iface) {
- if (iface.isAnnotationPresent(Resource.class)) {
+ if (!iface.isAnnotationPresent(Resource.class)) {
throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() +
". This type is not marked with the " + Resource.class.getName() + " annotation");
}
@@ -170,7 +182,7 @@ class BuildTimeResourceProxyBuilder {
}
private void scanSetter(Method method) {
- String propertyName = extractPropertyName(method.getName().substring(2));
+ String propertyName = extractPropertyName(method.getName().substring(3));
if (propertyName == null || !method.getReturnType().equals(void.class) ||
method.getParameterTypes().length != 1) {
throwInvalidMethod(method);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
index 5e8d7542d..746e3e9b7 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
@@ -33,43 +33,43 @@ class ResourceAccessorGenerator implements Injector {
switch (methodRef.getName()) {
case "get":
if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
context.getWriter().append('[');
- context.writeExpr(context.getArgument(2));
+ context.writeExpr(context.getArgument(1));
context.getWriter().append(']');
} else {
- context.writeExpr(context.getArgument(1));
- writePropertyAccessor(context, context.getArgument(2));
+ context.writeExpr(context.getArgument(0));
+ writePropertyAccessor(context, context.getArgument(1));
}
break;
case "put":
context.getWriter().append('(');
if (methodRef.getDescriptor().parameterType(1) == ValueType.INTEGER) {
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
context.getWriter().append('[');
- context.writeExpr(context.getArgument(2));
- } else {
context.writeExpr(context.getArgument(1));
- writePropertyAccessor(context, context.getArgument(2));
+ } else {
+ context.writeExpr(context.getArgument(0));
+ writePropertyAccessor(context, context.getArgument(1));
}
context.getWriter().append(']').ws().append('=').ws();
- context.writeExpr(context.getArgument(3));
- context.getWriter().append(')');
- break;
- case "add":
- context.writeExpr(context.getArgument(1));
- context.getWriter().append(".push(");
context.writeExpr(context.getArgument(2));
context.getWriter().append(')');
break;
- case "has":
+ case "add":
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().append(".push(");
context.writeExpr(context.getArgument(1));
+ context.getWriter().append(')');
+ break;
+ case "has":
+ context.writeExpr(context.getArgument(0));
context.getWriter().append(".hasOwnProperty(");
- writeStringExpr(context, context.getArgument(2));
+ writeStringExpr(context, context.getArgument(1));
context.getWriter().append(')');
break;
case "size":
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
context.getWriter().append(".length");
break;
case "castToInt":
@@ -84,7 +84,7 @@ class ResourceAccessorGenerator implements Injector {
case "castFromBoolean":
case "castFromFloat":
case "castFromDouble":
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
break;
case "castToIntWrapper":
castToWrapper(context, Integer.class, int.class);
@@ -124,29 +124,37 @@ class ResourceAccessorGenerator implements Injector {
break;
case "castToString":
context.getWriter().append("$rt_str(");
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
context.getWriter().append(")");
break;
case "castFromString":
context.getWriter().append("$rt_ustr(");
- context.writeExpr(context.getArgument(1));
+ context.writeExpr(context.getArgument(0));
context.getWriter().append(")");
break;
}
}
private void castToWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
+ context.getWriter().append('(');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().ws().append("==").ws().append("null").ws().append('?').ws().append("null")
+ .ws().append(':').ws();
context.getWriter().appendMethodBody(new MethodReference(wrapper, "valueOf", primitive, wrapper)).append('(');
- context.writeExpr(context.getArgument(1));
- context.getWriter().append(')');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().append("))");
}
private void castFromWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
+ context.getWriter().append('(');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().ws().append("==").ws().append("null").ws().append('?').ws().append("null")
+ .ws().append(':').ws();
String primitiveName = primitive.getName();
context.getWriter().appendMethodBody(new MethodReference(wrapper, primitiveName + "Value", primitive))
.append('(');
- context.writeExpr(context.getArgument(1));
- context.getWriter().append(')');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().append("))");
}
private void writePropertyAccessor(InjectorContext context, Expr property) throws IOException {
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
index cf7f0b4af..9e33c292f 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -224,7 +224,7 @@ class ResourceTransformer implements ClassHolderTransformer {
private String getPropertyName(String name) {
if (name.length() == 1) {
- return name;
+ return name.toLowerCase();
}
if (Character.isUpperCase(name.charAt(1))) {
return name;
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriter.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriter.java
index 5f1be5689..b457a5d70 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriter.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceWriter.java
@@ -22,6 +22,6 @@ import org.teavm.codegen.SourceWriter;
*
* @author Alexey Andreev
*/
-interface ResourceWriter {
+public interface ResourceWriter {
void write(SourceWriter writer) throws IOException;
}
From a5f9e4a0b4b4efac62995b38ac28c48ccf11c8d0 Mon Sep 17 00:00:00 2001
From: Alexey Andreev
Date: Sun, 8 Jun 2014 11:38:51 +0400
Subject: [PATCH 10/16] Bugfixes
---
.../metadata/MetadataGeneratorTest.java | 13 +
.../metadata/TestResourceGenerator.java | 1 +
.../main/java/org/teavm/model/ValueType.java | 21 +-
.../plugin/ResourceProgramTransformer.java | 295 ++++++++++++++++++
.../platform/plugin/ResourceTransformer.java | 202 +-----------
5 files changed, 330 insertions(+), 202 deletions(-)
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
index 49de83443..1c56755aa 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
@@ -51,9 +51,22 @@ public class MetadataGeneratorTest {
assertEquals(25, res.getE());
assertEquals(3.14, res.getF(), 0.001);
assertEquals(2.72, res.getG(), 0.001);
+
assertEquals(Integer.valueOf(26), res.getH());
assertNull(res.getI());
assertEquals(Byte.valueOf((byte)27), res.getJ());
assertEquals(Short.valueOf((short)28), res.getK());
+ assertEquals(100, res.getL().floatValue(), 0.1);
+ assertEquals(200, res.getM().doubleValue(), 0.1);
+
+ assertEquals("qwe", res.getFoo());
+
+ assertEquals(2, res.getArrayA().size());
+ assertEquals(Integer.valueOf(2), res.getArrayA().get(0));
+ assertEquals(Integer.valueOf(3), res.getArrayA().get(1));
+ assertEquals(1, res.getArrayB().size());
+ assertEquals("baz", res.getArrayB().get(0));
+ assertNull(res.getArrayC());
}
}
+
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
index 6b787b37c..2dbf1e392 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
@@ -50,6 +50,7 @@ public class TestResourceGenerator implements MetadataGenerator {
resource.setK((short)28);
resource.setL(100f);
resource.setM(200.0);
+ resource.setFoo("qwe");
ResourceArray array = context.createResourceArray();
array.add(2);
diff --git a/teavm-core/src/main/java/org/teavm/model/ValueType.java b/teavm-core/src/main/java/org/teavm/model/ValueType.java
index b4f7795ab..53547517b 100644
--- a/teavm-core/src/main/java/org/teavm/model/ValueType.java
+++ b/teavm-core/src/main/java/org/teavm/model/ValueType.java
@@ -191,7 +191,26 @@ public abstract class ValueType {
}
public static ValueType primitive(PrimitiveType type) {
- return new Primitive(type);
+ switch (type) {
+ case BOOLEAN:
+ return BOOLEAN;
+ case BYTE:
+ return BYTE;
+ case CHARACTER:
+ return CHARACTER;
+ case SHORT:
+ return SHORT;
+ case INTEGER:
+ return INTEGER;
+ case LONG:
+ return LONG;
+ case FLOAT:
+ return FLOAT;
+ case DOUBLE:
+ return DOUBLE;
+ default:
+ throw new AssertionError("Unknown primitive type " + type);
+ }
}
public static ValueType[] parseMany(String text) {
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
new file mode 100644
index 000000000..4b542a767
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
@@ -0,0 +1,295 @@
+package org.teavm.platform.plugin;
+
+import java.util.*;
+import org.teavm.model.*;
+import org.teavm.model.instructions.*;
+import org.teavm.platform.metadata.Resource;
+import org.teavm.platform.metadata.ResourceArray;
+import org.teavm.platform.metadata.ResourceMap;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+class ResourceProgramTransformer {
+ private ClassReaderSource innerSource;
+ private Program program;
+ private Set arrayItemsVars = new HashSet<>();
+
+ public ResourceProgramTransformer(ClassReaderSource innerSource, Program program) {
+ this.innerSource = innerSource;
+ this.program = program;
+ }
+
+ public void transformProgram() {
+ for (int i = 0; i < program.basicBlockCount(); ++i) {
+ transformBasicBlock(program.basicBlockAt(i));
+ }
+ if (!arrayItemsVars.isEmpty()) {
+ for (int i = 0; i < program.basicBlockCount(); ++i) {
+ postProcessBasicBlock(program.basicBlockAt(i));
+ }
+ }
+ }
+
+ private void transformBasicBlock(BasicBlock block) {
+ List instructions = block.getInstructions();
+ for (int i = 0; i < instructions.size(); ++i) {
+ Instruction insn = instructions.get(i);
+ if (insn instanceof InvokeInstruction) {
+ InvokeInstruction invoke = (InvokeInstruction)insn;
+ List replacement = transformInvoke(invoke);
+ if (replacement != null) {
+ instructions.set(i, new EmptyInstruction());
+ instructions.addAll(i, replacement);
+ i += replacement.size();
+ }
+ }
+ }
+ }
+
+ private void postProcessBasicBlock(BasicBlock block) {
+ List instructions = block.getInstructions();
+ for (int i = 0; i < instructions.size(); ++i) {
+ Instruction insn = instructions.get(i);
+ if (!(insn instanceof CastInstruction)) {
+ continue;
+ }
+ CastInstruction cast = (CastInstruction)insn;
+ if (!arrayItemsVars.contains(cast.getReceiver())) {
+ continue;
+ }
+ if (!(cast.getTargetType() instanceof ValueType.Object)) {
+ continue;
+ }
+ String targetTypeName = ((ValueType.Object)cast.getTargetType()).getClassName();
+ Variable var = cast.getValue();
+ Variable recv = cast.getReceiver();
+ switch (targetTypeName) {
+ case "java.lang.Integer":
+ instructions.set(i, castToWrapper(var, recv, int.class, Integer.class));
+ break;
+ case "java.lang.Boolean":
+ instructions.set(i, castToWrapper(var, recv, boolean.class, Boolean.class));
+ break;
+ case "java.lang.Byte":
+ instructions.set(i, castToWrapper(var, recv, byte.class, Byte.class));
+ break;
+ case "java.lang.Short":
+ instructions.set(i, castToWrapper(var, recv, short.class, Short.class));
+ break;
+ case "java.lang.Float":
+ instructions.set(i, castToWrapper(var, recv, float.class, Float.class));
+ break;
+ case "java.lang.Double":
+ instructions.set(i, castToWrapper(var, recv, double.class, Double.class));
+ break;
+ case "java.lang.String": {
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString",
+ Object.class, String.class));
+ castInvoke.getArguments().add(var);
+ castInvoke.setReceiver(recv);
+ instructions.set(i, castInvoke);
+ break;
+ }
+ }
+ }
+ }
+
+ private List transformInvoke(InvokeInstruction insn) {
+ if (insn.getType() != InvocationType.VIRTUAL) {
+ return null;
+ }
+ MethodReference method = insn.getMethod();
+ if (method.getClassName().equals(ResourceArray.class.getName()) ||
+ method.getClassName().equals(ResourceMap.class.getName())) {
+ if (method.getName().equals("get")) {
+ arrayItemsVars.add(insn.getReceiver());
+ }
+ InvokeInstruction accessInsn = new InvokeInstruction();
+ accessInsn.setType(InvocationType.SPECIAL);
+ ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
+ types[0] = ValueType.object("java.lang.Object");
+ System.arraycopy(method.getDescriptor().getSignature(), 0, types, 1,
+ method.getDescriptor().parameterCount() + 1);
+ accessInsn.setMethod(new MethodReference(ResourceAccessor.class.getName(), method.getName(), types));
+ accessInsn.getArguments().add(insn.getInstance());
+ accessInsn.getArguments().addAll(insn.getArguments());
+ accessInsn.setReceiver(insn.getReceiver());
+ return Arrays.asList(accessInsn);
+ }
+ ClassReader iface = innerSource.get(method.getClassName());
+ if (iface.getAnnotations().get(Resource.class.getName()) == null) {
+ return null;
+ }
+ if (method.getName().startsWith("get")) {
+ if (method.getName().length() > 3) {
+ return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3)));
+ }
+ } else if (method.getName().startsWith("is")) {
+ if (method.getName().length() > 2) {
+ return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2)));
+ }
+ } else if (method.getName().startsWith("set")) {
+ if (method.getName().length() > 3) {
+ return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3)));
+ }
+ }
+ return null;
+ }
+
+ private List transformGetterInvocation(InvokeInstruction insn, String property) {
+ if (insn.getReceiver() == null) {
+ return Collections.emptyList();
+ }
+ ValueType type = insn.getMethod().getDescriptor().getResultType();
+ List instructions = new ArrayList<>();
+ if (type instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive)type).getKind()) {
+ case BOOLEAN:
+ getAndCastProperty(insn, property, instructions, boolean.class);
+ return instructions;
+ case BYTE:
+ getAndCastProperty(insn, property, instructions, byte.class);
+ return instructions;
+ case SHORT:
+ getAndCastProperty(insn, property, instructions, short.class);
+ return instructions;
+ case INTEGER:
+ getAndCastProperty(insn, property, instructions, int.class);
+ return instructions;
+ case FLOAT:
+ getAndCastProperty(insn, property, instructions, float.class);
+ return instructions;
+ case DOUBLE:
+ getAndCastProperty(insn, property, instructions, double.class);
+ return instructions;
+ case CHARACTER:
+ case LONG:
+ break;
+ }
+ } else if (type instanceof ValueType.Object) {
+ switch (((ValueType.Object)type).getClassName()) {
+ case "java.lang.Boolean":
+ getAndCastPropertyToWrapper(insn, property, instructions, boolean.class, Boolean.class);
+ return instructions;
+ case "java.lang.Byte":
+ getAndCastPropertyToWrapper(insn, property, instructions, byte.class, Byte.class);
+ return instructions;
+ case "java.lang.Short":
+ getAndCastPropertyToWrapper(insn, property, instructions, short.class, Short.class);
+ return instructions;
+ case "java.lang.Integer":
+ getAndCastPropertyToWrapper(insn, property, instructions, int.class, Integer.class);
+ return instructions;
+ case "java.lang.Float":
+ getAndCastPropertyToWrapper(insn, property, instructions, float.class, Float.class);
+ return instructions;
+ case "java.lang.Double":
+ getAndCastPropertyToWrapper(insn, property, instructions, double.class, Double.class);
+ return instructions;
+ case "java.lang.String": {
+ Variable resultVar = insn.getProgram().createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString",
+ Object.class, String.class));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ instructions.add(castInvoke);
+ return instructions;
+ }
+ default: {
+ Variable resultVar = insn.getProgram().createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ CastInstruction castInsn = new CastInstruction();
+ castInsn.setReceiver(insn.getReceiver());
+ castInsn.setTargetType(type);
+ castInsn.setValue(resultVar);
+ instructions.add(castInsn);
+ return instructions;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void getProperty(InvokeInstruction insn, String property, List instructions,
+ Variable resultVar) {
+ Variable nameVar = program.createVariable();
+ StringConstantInstruction nameInsn = new StringConstantInstruction();
+ nameInsn.setConstant(property);
+ nameInsn.setReceiver(nameVar);
+ instructions.add(nameInsn);
+ InvokeInstruction accessorInvoke = new InvokeInstruction();
+ accessorInvoke.setType(InvocationType.SPECIAL);
+ accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
+ Object.class, String.class, Object.class));
+ accessorInvoke.getArguments().add(insn.getInstance());
+ accessorInvoke.getArguments().add(nameVar);
+ accessorInvoke.setReceiver(resultVar);
+ instructions.add(accessorInvoke);
+ }
+
+ private void getAndCastProperty(InvokeInstruction insn, String property, List instructions,
+ Class> primitive) {
+ Variable resultVar = program.createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized,
+ Object.class, primitive));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ instructions.add(castInvoke);
+ }
+
+ private Instruction castToWrapper(Variable var, Variable receiver, Class> primitive, Class> wrapper) {
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
+ Object.class, wrapper));
+ castInvoke.getArguments().add(var);
+ castInvoke.setReceiver(receiver);
+ return castInvoke;
+ }
+
+ private void getAndCastPropertyToWrapper(InvokeInstruction insn, String property, List instructions,
+ Class> primitive, Class> wrapper) {
+ Variable resultVar = program.createVariable();
+ getProperty(insn, property, instructions, resultVar);
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
+ Object.class, wrapper));
+ castInvoke.getArguments().add(resultVar);
+ castInvoke.setReceiver(insn.getReceiver());
+ instructions.add(castInvoke);
+ }
+
+ private List transformSetterInvocation(InvokeInstruction insn, String property) {
+ return null;
+ }
+
+ private String getPropertyName(String name) {
+ if (name.length() == 1) {
+ return name.toLowerCase();
+ }
+ if (Character.isUpperCase(name.charAt(1))) {
+ return name;
+ }
+ return Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
index 9e33c292f..f0b8854d2 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java
@@ -15,15 +15,7 @@
*/
package org.teavm.platform.plugin;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
import org.teavm.model.*;
-import org.teavm.model.instructions.*;
-import org.teavm.platform.metadata.Resource;
-import org.teavm.platform.metadata.ResourceArray;
-import org.teavm.platform.metadata.ResourceMap;
/**
*
@@ -35,200 +27,8 @@ class ResourceTransformer implements ClassHolderTransformer {
for (MethodHolder method : cls.getMethods()) {
Program program = method.getProgram();
if (program != null) {
- transformProgram(innerSource, program);
+ new ResourceProgramTransformer(innerSource, program).transformProgram();
}
}
}
-
- private void transformProgram(ClassReaderSource innerSource, Program program) {
- for (int i = 0; i < program.basicBlockCount(); ++i) {
- transformBasicBlock(innerSource, program.basicBlockAt(i));
- }
- }
-
- private void transformBasicBlock(ClassReaderSource innerSource, BasicBlock block) {
- List instructions = block.getInstructions();
- for (int i = 0; i < instructions.size(); ++i) {
- Instruction insn = instructions.get(i);
- if (insn instanceof InvokeInstruction) {
- InvokeInstruction invoke = (InvokeInstruction)insn;
- List replacement = transformInvoke(innerSource, invoke);
- if (replacement != null) {
- instructions.set(i, new EmptyInstruction());
- instructions.addAll(i, replacement);
- i += replacement.size();
- }
- }
- }
- }
-
- private List transformInvoke(ClassReaderSource innerSource, InvokeInstruction insn) {
- if (insn.getType() != InvocationType.VIRTUAL) {
- return null;
- }
- MethodReference method = insn.getMethod();
- if (method.getClassName().equals(ResourceArray.class.getName()) ||
- method.getClassName().equals(ResourceMap.class.getName())) {
- InvokeInstruction accessInsn = new InvokeInstruction();
- accessInsn.setType(InvocationType.SPECIAL);
- ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
- types[0] = ValueType.object("java.lang.Object");
- System.arraycopy(method.getDescriptor().getSignature(), 0, types, 1,
- method.getDescriptor().parameterCount() + 1);
- accessInsn.setMethod(new MethodReference(ResourceAccessor.class.getName(), method.getName(), types));
- accessInsn.getArguments().add(insn.getInstance());
- accessInsn.getArguments().addAll(insn.getArguments());
- accessInsn.setReceiver(insn.getReceiver());
- return Arrays.asList(accessInsn);
- }
- ClassReader iface = innerSource.get(method.getClassName());
- if (iface.getAnnotations().get(Resource.class.getName()) == null) {
- return null;
- }
- if (method.getName().startsWith("get")) {
- if (method.getName().length() > 3) {
- return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3)));
- }
- } else if (method.getName().startsWith("is")) {
- if (method.getName().length() > 2) {
- return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2)));
- }
- } else if (method.getName().startsWith("set")) {
- if (method.getName().length() > 3) {
- return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3)));
- }
- }
- return null;
- }
-
- private List transformGetterInvocation(InvokeInstruction insn, String property) {
- if (insn.getReceiver() == null) {
- return Collections.emptyList();
- }
- ValueType type = insn.getMethod().getDescriptor().getResultType();
- List instructions = new ArrayList<>();
- if (type instanceof ValueType.Primitive) {
- switch (((ValueType.Primitive)type).getKind()) {
- case BOOLEAN:
- getAndCastProperty(insn, property, instructions, boolean.class);
- return instructions;
- case BYTE:
- getAndCastProperty(insn, property, instructions, byte.class);
- return instructions;
- case SHORT:
- getAndCastProperty(insn, property, instructions, short.class);
- return instructions;
- case INTEGER:
- getAndCastProperty(insn, property, instructions, int.class);
- return instructions;
- case FLOAT:
- getAndCastProperty(insn, property, instructions, float.class);
- return instructions;
- case DOUBLE:
- getAndCastProperty(insn, property, instructions, double.class);
- return instructions;
- case CHARACTER:
- case LONG:
- break;
- }
- } else if (type instanceof ValueType.Object) {
- switch (((ValueType.Object)type).getClassName()) {
- case "java.lang.Boolean":
- getAndCastPropertyToWrapper(insn, property, instructions, boolean.class, Boolean.class);
- return instructions;
- case "java.lang.Byte":
- getAndCastPropertyToWrapper(insn, property, instructions, byte.class, Byte.class);
- return instructions;
- case "java.lang.Short":
- getAndCastPropertyToWrapper(insn, property, instructions, short.class, Short.class);
- return instructions;
- case "java.lang.Integer":
- getAndCastPropertyToWrapper(insn, property, instructions, int.class, Integer.class);
- return instructions;
- case "java.lang.Float":
- getAndCastPropertyToWrapper(insn, property, instructions, float.class, Float.class);
- return instructions;
- case "java.lang.Double":
- getAndCastPropertyToWrapper(insn, property, instructions, double.class, Double.class);
- return instructions;
- default: {
- Variable resultVar = insn.getProgram().createVariable();
- getProperty(insn, property, instructions, resultVar);
- CastInstruction castInsn = new CastInstruction();
- castInsn.setReceiver(insn.getReceiver());
- castInsn.setTargetType(type);
- castInsn.setValue(resultVar);
- instructions.add(castInsn);
- return instructions;
- }
- }
- }
- return null;
- }
-
- private void getProperty(InvokeInstruction insn, String property, List instructions,
- Variable resultVar) {
- Program program = insn.getProgram();
- Variable nameVar = program.createVariable();
- StringConstantInstruction nameInsn = new StringConstantInstruction();
- nameInsn.setConstant(property);
- nameInsn.setReceiver(nameVar);
- instructions.add(nameInsn);
- InvokeInstruction accessorInvoke = new InvokeInstruction();
- accessorInvoke.setType(InvocationType.SPECIAL);
- accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "get",
- Object.class, String.class, Object.class));
- accessorInvoke.getArguments().add(insn.getInstance());
- accessorInvoke.getArguments().add(nameVar);
- accessorInvoke.setReceiver(resultVar);
- instructions.add(accessorInvoke);
- }
-
- private void getAndCastProperty(InvokeInstruction insn, String property, List instructions,
- Class> primitive) {
- Program program = insn.getProgram();
- Variable resultVar = program.createVariable();
- getProperty(insn, property, instructions, resultVar);
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- String primitiveCapitalized = primitive.getName();
- primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
- primitiveCapitalized.substring(1);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized,
- Object.class, primitive));
- castInvoke.getArguments().add(resultVar);
- castInvoke.setReceiver(insn.getReceiver());
- instructions.add(castInvoke);
- }
-
- private void getAndCastPropertyToWrapper(InvokeInstruction insn, String property, List instructions,
- Class> primitive, Class> wrapper) {
- Program program = insn.getProgram();
- Variable resultVar = program.createVariable();
- getProperty(insn, property, instructions, resultVar);
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- String primitiveCapitalized = primitive.getName();
- primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
- primitiveCapitalized.substring(1);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
- Object.class, wrapper));
- castInvoke.getArguments().add(resultVar);
- castInvoke.setReceiver(insn.getReceiver());
- instructions.add(castInvoke);
- }
-
- private List transformSetterInvocation(InvokeInstruction insn, String property) {
- return null;
- }
-
- private String getPropertyName(String name) {
- if (name.length() == 1) {
- return name.toLowerCase();
- }
- if (Character.isUpperCase(name.charAt(1))) {
- return name;
- }
- return Character.toLowerCase(name.charAt(0)) + name.substring(1);
- }
}
From 0ee5ba52c47837c28e88568d633c6a69d12bc234 Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Mon, 9 Jun 2014 17:08:49 +0400
Subject: [PATCH 11/16] Removes primitive wrappers support from metadata
providers
---
.../metadata/DependentTestResource.java | 3 +-
.../metadata/MetadataGeneratorTest.java | 17 +--
.../teavm/platform/metadata/TestResource.java | 43 ++-----
.../metadata/TestResourceGenerator.java | 24 ++--
.../platform/metadata/BooleanResource.java | 26 +++++
.../teavm/platform/metadata/ByteResource.java | 26 +++++
.../platform/metadata/DoubleResource.java | 26 +++++
.../platform/metadata/FloatResource.java | 26 +++++
.../teavm/platform/metadata/IntResource.java | 26 +++++
.../platform/metadata/MetadataGenerator.java | 6 +-
.../metadata/MetadataGeneratorContext.java | 6 +-
.../org/teavm/platform/metadata/Resource.java | 8 +-
.../platform/metadata/ResourceArray.java | 2 +-
.../teavm/platform/metadata/ResourceMap.java | 2 +-
.../platform/metadata/ShortResource.java | 26 +++++
.../platform/metadata/StringResource.java | 26 +++++
.../plugin/BuildTimeResourceArray.java | 3 +-
.../platform/plugin/BuildTimeResourceMap.java | 3 +-
.../plugin/BuildTimeResourceProxyBuilder.java | 9 +-
.../DefaultMetadataGeneratorContext.java | 7 +-
.../MetadataProviderNativeGenerator.java | 3 +-
.../platform/plugin/ResourceAccessor.java | 30 +----
.../ResourceAccessorDependencyListener.java | 47 --------
.../plugin/ResourceAccessorGenerator.java | 58 ----------
.../plugin/ResourceProgramTransformer.java | 106 ------------------
25 files changed, 235 insertions(+), 324 deletions(-)
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/BooleanResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/ByteResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/DoubleResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/FloatResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/IntResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/ShortResource.java
create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/StringResource.java
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
index 3415d46a1..5b6fbd963 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/DependentTestResource.java
@@ -19,8 +19,7 @@ package org.teavm.platform.metadata;
*
* @author Alexey Andreev
*/
-@Resource
-public interface DependentTestResource {
+public interface DependentTestResource extends Resource {
String getBar();
void setBar(String bar);
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
index 1c56755aa..ad4bf808a 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
@@ -32,11 +32,11 @@ public class MetadataGeneratorTest {
}
@MetadataProvider(TestResourceGenerator.class)
- private native int getInt();
+ private native IntResource getInt();
@Test
public void intExposed() {
- assertEquals(23, getInt());
+ assertEquals(23, getInt().getValue());
}
@MetadataProvider(TestResourceGenerator.class)
@@ -52,20 +52,13 @@ public class MetadataGeneratorTest {
assertEquals(3.14, res.getF(), 0.001);
assertEquals(2.72, res.getG(), 0.001);
- assertEquals(Integer.valueOf(26), res.getH());
- assertNull(res.getI());
- assertEquals(Byte.valueOf((byte)27), res.getJ());
- assertEquals(Short.valueOf((short)28), res.getK());
- assertEquals(100, res.getL().floatValue(), 0.1);
- assertEquals(200, res.getM().doubleValue(), 0.1);
-
assertEquals("qwe", res.getFoo());
assertEquals(2, res.getArrayA().size());
- assertEquals(Integer.valueOf(2), res.getArrayA().get(0));
- assertEquals(Integer.valueOf(3), res.getArrayA().get(1));
+ assertEquals(2, res.getArrayA().get(0).getValue());
+ assertEquals(3, res.getArrayA().get(1).getValue());
assertEquals(1, res.getArrayB().size());
- assertEquals("baz", res.getArrayB().get(0));
+ assertEquals("baz", res.getArrayB().get(0).getBar());
assertNull(res.getArrayC());
}
}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
index d64800bbd..60c4ab2b4 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResource.java
@@ -19,8 +19,7 @@ package org.teavm.platform.metadata;
*
* @author Alexey Andreev
*/
-@Resource
-public interface TestResource {
+public interface TestResource extends Resource {
int getA();
void setA(int a);
@@ -45,55 +44,31 @@ public interface TestResource {
void setG(double g);
- Integer getH();
-
- void setH(Integer a);
-
- Boolean getI();
-
- void setI(Boolean i);
-
- Byte getJ();
-
- void setJ(Byte d);
-
- Short getK();
-
- void setK(Short k);
-
- Float getL();
-
- void setL(Float l);
-
- Double getM();
-
- void setM(Double g);
-
String getFoo();
void setFoo(String foo);
- ResourceArray getArrayA();
+ ResourceArray getArrayA();
- void setArrayA(ResourceArray arrayA);
+ void setArrayA(ResourceArray arrayA);
ResourceArray getArrayB();
void setArrayB(ResourceArray arrayB);
- ResourceArray> getArrayC();
+ ResourceArray> getArrayC();
- void setArrayC(ResourceArray> arrayC);
+ void setArrayC(ResourceArray> arrayC);
- ResourceMap getMapA();
+ ResourceMap getMapA();
- void setMapA(ResourceMap mapA);
+ void setMapA(ResourceMap mapA);
ResourceMap getMapB();
void setMapB(ResourceMap mapB);
- ResourceMap> getMapC();
+ ResourceMap> getMapC();
- void setMapC(ResourceMap> mapC);
+ void setMapC(ResourceMap> mapC);
}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
index 2dbf1e392..6edf353ce 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
@@ -23,12 +23,12 @@ import org.teavm.model.MethodReference;
*/
public class TestResourceGenerator implements MetadataGenerator {
@Override
- public Object generateMetadata(MetadataGeneratorContext context, MethodReference method) {
+ public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
switch (method.getName()) {
case "getNull":
return null;
case "getInt":
- return 23;
+ return createInt(context, 23);
case "getResource":
return getResource(context);
default:
@@ -36,7 +36,7 @@ public class TestResourceGenerator implements MetadataGenerator {
}
}
- private Object getResource(MetadataGeneratorContext context) {
+ private Resource getResource(MetadataGeneratorContext context) {
TestResource resource = context.createResource(TestResource.class);
resource.setA(23);
resource.setB(false);
@@ -44,17 +44,11 @@ public class TestResourceGenerator implements MetadataGenerator {
resource.setE((short)25);
resource.setF(3.14f);
resource.setG(2.72);
- resource.setH(26);
- resource.setI(null);
- resource.setJ((byte)27);
- resource.setK((short)28);
- resource.setL(100f);
- resource.setM(200.0);
resource.setFoo("qwe");
- ResourceArray array = context.createResourceArray();
- array.add(2);
- array.add(3);
+ ResourceArray array = context.createResourceArray();
+ array.add(createInt(context, 2));
+ array.add(createInt(context, 3));
resource.setArrayA(array);
DependentTestResource dep = context.createResource(DependentTestResource.class);
dep.setBar("baz");
@@ -63,4 +57,10 @@ public class TestResourceGenerator implements MetadataGenerator {
resource.setArrayB(resArray);
return resource;
}
+
+ private IntResource createInt(MetadataGeneratorContext context, int value) {
+ IntResource res = context.createResource(IntResource.class);
+ res.setValue(value);
+ return res;
+ }
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/BooleanResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/BooleanResource.java
new file mode 100644
index 000000000..ebf4bf6f7
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/BooleanResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface BooleanResource extends Resource {
+ boolean getValue();
+
+ void setValue(boolean value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ByteResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ByteResource.java
new file mode 100644
index 000000000..582cda32b
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ByteResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface ByteResource extends Resource {
+ byte getValue();
+
+ void setValue(byte value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/DoubleResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/DoubleResource.java
new file mode 100644
index 000000000..2d728fdf5
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/DoubleResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface DoubleResource extends Resource {
+ double getValue();
+
+ void setValue(double value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/FloatResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/FloatResource.java
new file mode 100644
index 000000000..4c159052c
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/FloatResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface FloatResource extends Resource {
+ float getValue();
+
+ void setValue(float value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/IntResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/IntResource.java
new file mode 100644
index 000000000..574b84192
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/IntResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface IntResource extends Resource {
+ int getValue();
+
+ void setValue(int value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java
index 8a5a0e918..92c0ce73a 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGenerator.java
@@ -41,12 +41,10 @@ import org.teavm.model.MethodReference;
* The valid resource types are the following:
*
*
- * - Valid interfaces, marked with the {@link Resource} annotation. Read the description of this annotation
+ *
- Valid interfaces, extending the {@link Resource} annotation. Read the description of this interface
* for detailed description about valid resources interfaces.
* - {@link ResourceArray} of valid resources.
* - {@link ResourceMap} of valid resources.
- * - {@link String}, {@link Integer}, {@link Byte}, {@link Short}, {@link Float}, {@link Double},
- * {@link Boolean}.
* - The
null
value.
*
*
@@ -61,5 +59,5 @@ public interface MetadataGenerator {
* @param context context that contains useful compile-time information.
* @param method method which will be used to access the generated resources at run time.
*/
- Object generateMetadata(MetadataGeneratorContext context, MethodReference method);
+ Resource generateMetadata(MetadataGeneratorContext context, MethodReference method);
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGeneratorContext.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGeneratorContext.java
index 7003d9344..88f1bca57 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGeneratorContext.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/MetadataGeneratorContext.java
@@ -45,15 +45,15 @@ public interface MetadataGeneratorContext {
* Creates a new resource of the given type. The description of valid resources
* is available in documentation for {@link Resource}.
*/
- T createResource(Class resourceType);
+ T createResource(Class resourceType);
/**
* Creates a new resource array.
*/
- ResourceArray createResourceArray();
+ ResourceArray createResourceArray();
/**
* Creates a new resource map.
*/
- ResourceMap createResourceMap();
+ ResourceMap createResourceMap();
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
index 3524b52d9..b58ee600f 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/Resource.java
@@ -15,8 +15,6 @@
*/
package org.teavm.platform.metadata;
-import java.lang.annotation.*;
-
/**
* Marks a valid resource interface. Resource interface is an interface, that has get* and set* methods,
* according the default convention for JavaBeans. Each property must have both getter and setter.
@@ -28,9 +26,5 @@ import java.lang.annotation.*;
*
* @author Alexey Andreev
*/
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Inherited
-@Documented
-public @interface Resource {
+public interface Resource {
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceArray.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceArray.java
index 98a85ca2a..059c4ea0d 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceArray.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceArray.java
@@ -19,7 +19,7 @@ package org.teavm.platform.metadata;
*
* @author Alexey Andreev
*/
-public interface ResourceArray {
+public interface ResourceArray extends Resource {
int size();
T get(int i);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceMap.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceMap.java
index e798f94cc..3ce3f8bfe 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceMap.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ResourceMap.java
@@ -19,7 +19,7 @@ package org.teavm.platform.metadata;
*
* @author Alexey Andreev
*/
-public interface ResourceMap {
+public interface ResourceMap extends Resource {
boolean has(String key);
T get(String key);
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ShortResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ShortResource.java
new file mode 100644
index 000000000..c0a31ba68
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ShortResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface ShortResource extends Resource {
+ short getValue();
+
+ void setValue(short value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/StringResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/StringResource.java
new file mode 100644
index 000000000..a48754b30
--- /dev/null
+++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/StringResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.platform.metadata;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface StringResource extends Resource {
+ String getValue();
+
+ void setValue(String value);
+}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceArray.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceArray.java
index 43d1ae312..c2e9a9267 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceArray.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceArray.java
@@ -19,13 +19,14 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.teavm.codegen.SourceWriter;
+import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
/**
*
* @author Alexey Andreev
*/
-class BuildTimeResourceArray implements ResourceArray, ResourceWriter {
+class BuildTimeResourceArray implements ResourceArray, ResourceWriter {
private List data = new ArrayList<>();
@Override
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceMap.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceMap.java
index 213b2c479..2e1dba77c 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceMap.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceMap.java
@@ -19,13 +19,14 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.teavm.codegen.SourceWriter;
+import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceMap;
/**
*
* @author Alexey Andreev
*/
-class BuildTimeResourceMap implements ResourceMap, ResourceWriter {
+class BuildTimeResourceMap implements ResourceMap, ResourceWriter {
private Map data = new HashMap<>();
@Override
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
index f288a4cfd..9e962512a 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
@@ -29,8 +29,7 @@ import org.teavm.platform.metadata.ResourceMap;
class BuildTimeResourceProxyBuilder {
private Map, BuildTimeResourceProxyFactory> factories = new HashMap<>();
private static Set> allowedPropertyTypes = new HashSet<>(Arrays.>asList(
- boolean.class, Boolean.class, byte.class, Byte.class, short.class, Short.class,
- int.class, Integer.class, float.class, Float.class, double.class, Double.class,
+ boolean.class, byte.class, short.class, int.class, float.class, double.class,
String.class, ResourceArray.class, ResourceMap.class));
private static Map, Object> defaultValues = new HashMap<>();
@@ -89,9 +88,9 @@ class BuildTimeResourceProxyBuilder {
}
private void scanIface(Class> iface) {
- if (!iface.isAnnotationPresent(Resource.class)) {
+ if (!Resource.class.isAssignableFrom(iface)) {
throw new IllegalArgumentException("Error creating a new resource of type " + iface.getName() +
- ". This type is not marked with the " + Resource.class.getName() + " annotation");
+ ". This type does not implement the " + Resource.class.getName() + " interface");
}
// Scan methods
@@ -136,7 +135,7 @@ class BuildTimeResourceProxyBuilder {
String propertyName = property.getKey();
Class> propertyType = property.getValue();
if (!allowedPropertyTypes.contains(propertyType)) {
- if (!propertyType.isInterface() || !propertyType.isAnnotationPresent(Resource.class)) {
+ if (!propertyType.isInterface() || !Resource.class.isAssignableFrom(propertyType)) {
throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
" has an illegal type " + propertyType.getName());
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/DefaultMetadataGeneratorContext.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/DefaultMetadataGeneratorContext.java
index cd38cc840..c68f69911 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/DefaultMetadataGeneratorContext.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/DefaultMetadataGeneratorContext.java
@@ -19,6 +19,7 @@ import java.lang.reflect.Proxy;
import java.util.Properties;
import org.teavm.model.ListableClassReaderSource;
import org.teavm.platform.metadata.MetadataGeneratorContext;
+import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap;
@@ -55,19 +56,19 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext {
}
@Override
- public T createResource(Class resourceType) {
+ public T createResource(Class resourceType) {
return resourceType.cast(Proxy.newProxyInstance(classLoader,
new Class>[] { resourceType, ResourceWriter.class },
proxyBuilder.buildProxy(resourceType)));
}
@Override
- public ResourceArray createResourceArray() {
+ public ResourceArray createResourceArray() {
return new BuildTimeResourceArray<>();
}
@Override
- public ResourceMap createResourceMap() {
+ public ResourceMap createResourceMap() {
return new BuildTimeResourceMap<>();
}
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
index 62497207d..d9801bece 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderNativeGenerator.java
@@ -24,6 +24,7 @@ import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.*;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataProvider;
+import org.teavm.platform.metadata.Resource;
/**
*
@@ -73,7 +74,7 @@ public class MetadataProviderNativeGenerator implements Generator {
context.getClassLoader(), context.getProperties());
// Generate resource loader
- Object resource = generator.generateMetadata(metadataContext, methodRef);
+ Resource resource = generator.generateMetadata(metadataContext, methodRef);
writer.append("if (!window.hasOwnProperty(\"").appendMethodBody(methodRef).append("$$resource\")) {")
.indent().softNewLine();
writer.appendMethodBody(methodRef).append("$$resource = ");
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
index 7c399174b..5002ec399 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessor.java
@@ -15,6 +15,8 @@
*/
package org.teavm.platform.plugin;
+import org.teavm.platform.metadata.Resource;
+
/**
*
* @author Alexey Andreev
@@ -24,9 +26,9 @@ final class ResourceAccessor {
public static native void put(Object obj, String propertyName, Object elem);
- public static native Object get(Object obj, int index);
+ public static native Resource get(Object obj, int index);
- public static native void add(Object obj, Object elem);
+ public static native void add(Object obj, Resource elem);
public static native boolean has(Object obj, String key);
@@ -34,53 +36,29 @@ final class ResourceAccessor {
public static native int castToInt(Object obj);
- public static native Integer castToIntWrapper(Object obj);
-
public static native short castToShort(Object obj);
- public static native Short castToShortWrapper(Object obj);
-
public static native byte castToByte(Object obj);
- public static native Byte castToByteWrapper(Object obj);
-
public static native boolean castToBoolean(Object obj);
- public static native Boolean castToBooleanWrapper(Object obj);
-
public static native float castToFloat(Object obj);
- public static native Float castToFloatWrapper(Object obj);
-
public static native double castToDouble(Object obj);
- public static native Double castToDoubleWrapper(Object obj);
-
public static native String castToString(Object obj);
public static native Object castFromInt(int value);
- public static native Object castFromIntWrapper(Integer value);
-
public static native Object castFromShort(short value);
- public static native Object castFromShortWrapper(Short value);
-
public static native Object castFromByte(byte value);
- public static native Object castFromByteWrapper(Byte value);
-
public static native Object castFromBoolean(boolean value);
- public static native Object castFromBooleanWrapper(Boolean value);
-
public static native Object castFromFloat(float value);
- public static native Object castFromFloatWrapper(Float value);
-
public static native Object castFromDouble(double value);
- public static native Object castFromDoubleWrapper(Double value);
-
public static native Object castFromString(String value);
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java
index 98345dbd1..72c572674 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorDependencyListener.java
@@ -19,7 +19,6 @@ import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyListener;
import org.teavm.dependency.FieldDependency;
import org.teavm.dependency.MethodDependency;
-import org.teavm.model.MethodReference;
/**
*
@@ -37,58 +36,12 @@ class ResourceAccessorDependencyListener implements DependencyListener {
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
- case "castToIntWrapper":
- castToWrapper(agent, method, Integer.class, int.class);
- break;
- case "castToShortWrapper":
- castToWrapper(agent, method, Short.class, short.class);
- break;
- case "castToByteWrapper":
- castToWrapper(agent, method, Byte.class, byte.class);
- break;
- case "castToBooleanWrapper":
- castToWrapper(agent, method, Boolean.class, boolean.class);
- break;
- case "castToFloatWrapper":
- castToWrapper(agent, method, Float.class, float.class);
- break;
- case "castToDoubleWrapper":
- castToWrapper(agent, method, Double.class, double.class);
- break;
- case "castFromIntegerWrapper":
- castFromWrapper(agent, method, Integer.class, int.class);
- break;
- case "castFromShortWrapper":
- castFromWrapper(agent, method, Short.class, short.class);
- break;
- case "castFromByteWrapper":
- castFromWrapper(agent, method, Byte.class, byte.class);
- break;
- case "castFromBooleanWrapper":
- castFromWrapper(agent, method, Boolean.class, boolean.class);
- break;
- case "castFromFloatWrapper":
- castFromWrapper(agent, method, Float.class, float.class);
- break;
- case "castFromDoubleWrapper":
- castFromWrapper(agent, method, Double.class, double.class);
- break;
case "castToString":
method.getResult().propagate("java.lang.String");
break;
}
}
- private void castToWrapper(DependencyAgent agent, MethodDependency method, Class> wrapper, Class> primitive) {
- method.getResult().propagate(wrapper.getName());
- agent.linkMethod(new MethodReference(wrapper, "valueOf", primitive, wrapper), method.getStack()).use();
- }
-
- private void castFromWrapper(DependencyAgent agent, MethodDependency method, Class> wrapper, Class> primitive) {
- String primitiveName = primitive.getName();
- agent.linkMethod(new MethodReference(wrapper, primitiveName + "Value", primitive), method.getStack()).use();
- }
-
@Override
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
index 746e3e9b7..73e142c5c 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
@@ -86,42 +86,6 @@ class ResourceAccessorGenerator implements Injector {
case "castFromDouble":
context.writeExpr(context.getArgument(0));
break;
- case "castToIntWrapper":
- castToWrapper(context, Integer.class, int.class);
- break;
- case "castToShortWrapper":
- castToWrapper(context, Short.class, short.class);
- break;
- case "castToByteWrapper":
- castToWrapper(context, Byte.class, byte.class);
- break;
- case "castToBooleanWrapper":
- castToWrapper(context, Boolean.class, boolean.class);
- break;
- case "castToFloatWrapper":
- castToWrapper(context, Float.class, float.class);
- break;
- case "castToDoubleWrapper":
- castToWrapper(context, Double.class, double.class);
- break;
- case "castFromIntWrapper":
- castFromWrapper(context, Integer.class, int.class);
- break;
- case "castFromShortWrapper":
- castFromWrapper(context, Short.class, short.class);
- break;
- case "castFromByteWrapper":
- castFromWrapper(context, Byte.class, byte.class);
- break;
- case "castFromBooleanWrapper":
- castFromWrapper(context, Boolean.class, boolean.class);
- break;
- case "castFromFloatWrapper":
- castFromWrapper(context, Float.class, float.class);
- break;
- case "castFromDoubleWrapper":
- castFromWrapper(context, Double.class, double.class);
- break;
case "castToString":
context.getWriter().append("$rt_str(");
context.writeExpr(context.getArgument(0));
@@ -135,28 +99,6 @@ class ResourceAccessorGenerator implements Injector {
}
}
- private void castToWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
- context.getWriter().append('(');
- context.writeExpr(context.getArgument(0));
- context.getWriter().ws().append("==").ws().append("null").ws().append('?').ws().append("null")
- .ws().append(':').ws();
- context.getWriter().appendMethodBody(new MethodReference(wrapper, "valueOf", primitive, wrapper)).append('(');
- context.writeExpr(context.getArgument(0));
- context.getWriter().append("))");
- }
-
- private void castFromWrapper(InjectorContext context, Class> wrapper, Class> primitive) throws IOException {
- context.getWriter().append('(');
- context.writeExpr(context.getArgument(0));
- context.getWriter().ws().append("==").ws().append("null").ws().append('?').ws().append("null")
- .ws().append(':').ws();
- String primitiveName = primitive.getName();
- context.getWriter().appendMethodBody(new MethodReference(wrapper, primitiveName + "Value", primitive))
- .append('(');
- context.writeExpr(context.getArgument(0));
- context.getWriter().append("))");
- }
-
private void writePropertyAccessor(InjectorContext context, Expr property) throws IOException {
if (property instanceof ConstantExpr) {
String str = (String)((ConstantExpr)property).getValue();
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
index 4b542a767..014433545 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
@@ -14,7 +14,6 @@ import org.teavm.platform.metadata.ResourceMap;
class ResourceProgramTransformer {
private ClassReaderSource innerSource;
private Program program;
- private Set arrayItemsVars = new HashSet<>();
public ResourceProgramTransformer(ClassReaderSource innerSource, Program program) {
this.innerSource = innerSource;
@@ -25,11 +24,6 @@ class ResourceProgramTransformer {
for (int i = 0; i < program.basicBlockCount(); ++i) {
transformBasicBlock(program.basicBlockAt(i));
}
- if (!arrayItemsVars.isEmpty()) {
- for (int i = 0; i < program.basicBlockCount(); ++i) {
- postProcessBasicBlock(program.basicBlockAt(i));
- }
- }
}
private void transformBasicBlock(BasicBlock block) {
@@ -48,56 +42,6 @@ class ResourceProgramTransformer {
}
}
- private void postProcessBasicBlock(BasicBlock block) {
- List instructions = block.getInstructions();
- for (int i = 0; i < instructions.size(); ++i) {
- Instruction insn = instructions.get(i);
- if (!(insn instanceof CastInstruction)) {
- continue;
- }
- CastInstruction cast = (CastInstruction)insn;
- if (!arrayItemsVars.contains(cast.getReceiver())) {
- continue;
- }
- if (!(cast.getTargetType() instanceof ValueType.Object)) {
- continue;
- }
- String targetTypeName = ((ValueType.Object)cast.getTargetType()).getClassName();
- Variable var = cast.getValue();
- Variable recv = cast.getReceiver();
- switch (targetTypeName) {
- case "java.lang.Integer":
- instructions.set(i, castToWrapper(var, recv, int.class, Integer.class));
- break;
- case "java.lang.Boolean":
- instructions.set(i, castToWrapper(var, recv, boolean.class, Boolean.class));
- break;
- case "java.lang.Byte":
- instructions.set(i, castToWrapper(var, recv, byte.class, Byte.class));
- break;
- case "java.lang.Short":
- instructions.set(i, castToWrapper(var, recv, short.class, Short.class));
- break;
- case "java.lang.Float":
- instructions.set(i, castToWrapper(var, recv, float.class, Float.class));
- break;
- case "java.lang.Double":
- instructions.set(i, castToWrapper(var, recv, double.class, Double.class));
- break;
- case "java.lang.String": {
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToString",
- Object.class, String.class));
- castInvoke.getArguments().add(var);
- castInvoke.setReceiver(recv);
- instructions.set(i, castInvoke);
- break;
- }
- }
- }
- }
-
private List transformInvoke(InvokeInstruction insn) {
if (insn.getType() != InvocationType.VIRTUAL) {
return null;
@@ -105,9 +49,6 @@ class ResourceProgramTransformer {
MethodReference method = insn.getMethod();
if (method.getClassName().equals(ResourceArray.class.getName()) ||
method.getClassName().equals(ResourceMap.class.getName())) {
- if (method.getName().equals("get")) {
- arrayItemsVars.add(insn.getReceiver());
- }
InvokeInstruction accessInsn = new InvokeInstruction();
accessInsn.setType(InvocationType.SPECIAL);
ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
@@ -172,24 +113,6 @@ class ResourceProgramTransformer {
}
} else if (type instanceof ValueType.Object) {
switch (((ValueType.Object)type).getClassName()) {
- case "java.lang.Boolean":
- getAndCastPropertyToWrapper(insn, property, instructions, boolean.class, Boolean.class);
- return instructions;
- case "java.lang.Byte":
- getAndCastPropertyToWrapper(insn, property, instructions, byte.class, Byte.class);
- return instructions;
- case "java.lang.Short":
- getAndCastPropertyToWrapper(insn, property, instructions, short.class, Short.class);
- return instructions;
- case "java.lang.Integer":
- getAndCastPropertyToWrapper(insn, property, instructions, int.class, Integer.class);
- return instructions;
- case "java.lang.Float":
- getAndCastPropertyToWrapper(insn, property, instructions, float.class, Float.class);
- return instructions;
- case "java.lang.Double":
- getAndCastPropertyToWrapper(insn, property, instructions, double.class, Double.class);
- return instructions;
case "java.lang.String": {
Variable resultVar = insn.getProgram().createVariable();
getProperty(insn, property, instructions, resultVar);
@@ -250,35 +173,6 @@ class ResourceProgramTransformer {
instructions.add(castInvoke);
}
- private Instruction castToWrapper(Variable var, Variable receiver, Class> primitive, Class> wrapper) {
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- String primitiveCapitalized = primitive.getName();
- primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
- primitiveCapitalized.substring(1);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
- Object.class, wrapper));
- castInvoke.getArguments().add(var);
- castInvoke.setReceiver(receiver);
- return castInvoke;
- }
-
- private void getAndCastPropertyToWrapper(InvokeInstruction insn, String property, List instructions,
- Class> primitive, Class> wrapper) {
- Variable resultVar = program.createVariable();
- getProperty(insn, property, instructions, resultVar);
- InvokeInstruction castInvoke = new InvokeInstruction();
- castInvoke.setType(InvocationType.SPECIAL);
- String primitiveCapitalized = primitive.getName();
- primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
- primitiveCapitalized.substring(1);
- castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Wrapper",
- Object.class, wrapper));
- castInvoke.getArguments().add(resultVar);
- castInvoke.setReceiver(insn.getReceiver());
- instructions.add(castInvoke);
- }
-
private List transformSetterInvocation(InvokeInstruction insn, String property) {
return null;
}
From b9d6e29ca2ec6cee42bfc831ad04e243589815b6 Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Mon, 9 Jun 2014 18:52:16 +0400
Subject: [PATCH 12/16] Tests pass
---
.../plugin/ResourceProgramTransformer.java | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
index 014433545..798031e2a 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
@@ -62,7 +62,7 @@ class ResourceProgramTransformer {
return Arrays.asList(accessInsn);
}
ClassReader iface = innerSource.get(method.getClassName());
- if (iface.getAnnotations().get(Resource.class.getName()) == null) {
+ if (!isSubclass(iface, Resource.class.getName())) {
return null;
}
if (method.getName().startsWith("get")) {
@@ -81,6 +81,23 @@ class ResourceProgramTransformer {
return null;
}
+ private boolean isSubclass(ClassReader cls, String superClass) {
+ if (cls.getName().equals(superClass)) {
+ return true;
+ }
+ ClassReader parent = cls.getParent() != null ? innerSource.get(cls.getParent()) : null;
+ if (parent != null && isSubclass(parent, superClass)) {
+ return true;
+ }
+ for (String ifaceName : cls.getInterfaces()) {
+ ClassReader iface = innerSource.get(ifaceName);
+ if (iface != null) {
+ return isSubclass(iface, superClass);
+ }
+ }
+ return false;
+ }
+
private List transformGetterInvocation(InvokeInstruction insn, String property) {
if (insn.getReceiver() == null) {
return Collections.emptyList();
From da2a26fb4ff8fc52f8d0aa222531ce78e96a217f Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Mon, 9 Jun 2014 19:44:36 +0400
Subject: [PATCH 13/16] Adds more metadata usecases
---
.../metadata/MetadataGeneratorTest.java | 39 +++++++++
.../metadata/TestResourceGenerator.java | 2 +
.../plugin/BuildTimeResourceProxyBuilder.java | 22 +++++-
.../plugin/ResourceAccessorGenerator.java | 12 ++-
.../plugin/ResourceProgramTransformer.java | 79 +++++++++++++++++++
5 files changed, 147 insertions(+), 7 deletions(-)
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
index ad4bf808a..ec59b1299 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/MetadataGeneratorTest.java
@@ -61,5 +61,44 @@ public class MetadataGeneratorTest {
assertEquals("baz", res.getArrayB().get(0).getBar());
assertNull(res.getArrayC());
}
+
+ @MetadataProvider(TestResourceGenerator.class)
+ private native TestResource getEmptyResource();
+
+ @Test
+ public void resourceDefaultsSet() {
+ TestResource res = getEmptyResource();
+ assertEquals(0, res.getA());
+ assertFalse(res.getB());
+ assertEquals(0, res.getD());
+ assertEquals(0, res.getE());
+ assertEquals(0, res.getF(), 1E-10);
+ assertEquals(0, res.getG(), 1E-10);
+ assertNull(res.getFoo());
+ assertNull(res.getArrayA());
+ assertNull(res.getArrayB());
+ assertNull(res.getArrayC());
+ assertNull(res.getMapA());
+ assertNull(res.getMapB());
+ assertNull(res.getMapC());
+ }
+
+ @Test
+ public void resourceModifiedInRunTime() {
+ TestResource res = getEmptyResource();
+ res.setA(23);
+ res.setB(true);
+ res.setD((byte)24);
+ res.setE((short)25);
+ res.setF(3.14f);
+ res.setG(2.72);
+
+ assertEquals(23, res.getA());
+ assertTrue(res.getB());
+ assertEquals(24, res.getD());
+ assertEquals(25, res.getE());
+ assertEquals(3.14, res.getF(), 0.001);
+ assertEquals(2.72, res.getG(), 0.001);
+ }
}
diff --git a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
index 6edf353ce..43f672805 100644
--- a/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
+++ b/teavm-classlib/src/test/java/org/teavm/platform/metadata/TestResourceGenerator.java
@@ -31,6 +31,8 @@ public class TestResourceGenerator implements MetadataGenerator {
return createInt(context, 23);
case "getResource":
return getResource(context);
+ case "getEmptyResource":
+ return context.createResource(TestResource.class);
default:
throw new RuntimeException("Unsupported method: " + method);
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
index 9e962512a..a936fee0f 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeResourceProxyBuilder.java
@@ -62,6 +62,7 @@ class BuildTimeResourceProxyBuilder {
Map methods = new HashMap<>();
private Map propertyIndexes = new HashMap<>();
private Object[] initialData;
+ private Map> propertyTypes = new HashMap<>();
public ProxyFactoryCreation(Class> iface) {
this.rootIface = iface;
@@ -73,12 +74,24 @@ class BuildTimeResourceProxyBuilder {
" that is not an interface");
}
scanIface(rootIface);
+
+ // Fill default values
+ initialData = new Object[propertyIndexes.size()];
+ for (Map.Entry> property : propertyTypes.entrySet()) {
+ String propertyName = property.getKey();
+ Class> propertyType = property.getValue();
+ initialData[propertyIndexes.get(propertyName)] = defaultValues.get(propertyType);
+ }
+
+ // Generate write method
Method writeMethod;
try {
writeMethod = ResourceWriter.class.getMethod("write", SourceWriter.class);
} catch (NoSuchMethodException e) {
throw new AssertionError("Method must exist", e);
}
+
+ // Create factory
String[] properties = new String[propertyIndexes.size()];
for (Map.Entry entry : propertyIndexes.entrySet()) {
properties[entry.getValue()] = entry.getKey();
@@ -129,18 +142,19 @@ class BuildTimeResourceProxyBuilder {
}
}
- // Verify types of properties and fill default values
- initialData = new Object[propertyIndexes.size()];
+ // Verify types of properties
for (Map.Entry> property : getters.entrySet()) {
String propertyName = property.getKey();
Class> propertyType = property.getValue();
if (!allowedPropertyTypes.contains(propertyType)) {
if (!propertyType.isInterface() || !Resource.class.isAssignableFrom(propertyType)) {
- throw new IllegalArgumentException("Property " + iface.getName() + "." + propertyName +
+ throw new IllegalArgumentException("Property " + rootIface.getName() + "." + propertyName +
" has an illegal type " + propertyType.getName());
}
}
- initialData[propertyIndexes.get(propertyName)] = defaultValues.get(propertyType);
+ if (!propertyTypes.containsKey(propertyName)) {
+ propertyTypes.put(propertyName, propertyType);
+ }
}
// Scan superinterfaces
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
index 73e142c5c..1eaa46a52 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorGenerator.java
@@ -52,7 +52,7 @@ class ResourceAccessorGenerator implements Injector {
context.writeExpr(context.getArgument(0));
writePropertyAccessor(context, context.getArgument(1));
}
- context.getWriter().append(']').ws().append('=').ws();
+ context.getWriter().ws().append('=').ws();
context.writeExpr(context.getArgument(2));
context.getWriter().append(')');
break;
@@ -87,14 +87,20 @@ class ResourceAccessorGenerator implements Injector {
context.writeExpr(context.getArgument(0));
break;
case "castToString":
+ context.getWriter().append('(');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().ws().append("!==").ws().append("null").ws().append("?").ws();
context.getWriter().append("$rt_str(");
context.writeExpr(context.getArgument(0));
- context.getWriter().append(")");
+ context.getWriter().append(")").ws().append(':').ws().append("null)");
break;
case "castFromString":
+ context.getWriter().append('(');
+ context.writeExpr(context.getArgument(0));
+ context.getWriter().ws().append("!==").ws().append("null").ws().append("?").ws();
context.getWriter().append("$rt_ustr(");
context.writeExpr(context.getArgument(0));
- context.getWriter().append(")");
+ context.getWriter().append(")").ws().append(':').ws().append("null)");
break;
}
}
diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
index 798031e2a..56e51343b 100644
--- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
+++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceProgramTransformer.java
@@ -191,9 +191,88 @@ class ResourceProgramTransformer {
}
private List transformSetterInvocation(InvokeInstruction insn, String property) {
+ ValueType type = insn.getMethod().getDescriptor().parameterType(0);
+ List instructions = new ArrayList<>();
+ if (type instanceof ValueType.Primitive) {
+ switch (((ValueType.Primitive)type).getKind()) {
+ case BOOLEAN:
+ castAndSetProperty(insn, property, instructions, boolean.class);
+ return instructions;
+ case BYTE:
+ castAndSetProperty(insn, property, instructions, byte.class);
+ return instructions;
+ case SHORT:
+ castAndSetProperty(insn, property, instructions, short.class);
+ return instructions;
+ case INTEGER:
+ castAndSetProperty(insn, property, instructions, int.class);
+ return instructions;
+ case FLOAT:
+ castAndSetProperty(insn, property, instructions, float.class);
+ return instructions;
+ case DOUBLE:
+ castAndSetProperty(insn, property, instructions, double.class);
+ return instructions;
+ case CHARACTER:
+ case LONG:
+ break;
+ }
+ } else if (type instanceof ValueType.Object) {
+ switch (((ValueType.Object)type).getClassName()) {
+ case "java.lang.String": {
+ Variable castVar = insn.getProgram().createVariable();
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFromString",
+ String.class, Object.class));
+ castInvoke.getArguments().add(insn.getArguments().get(0));
+ castInvoke.setReceiver(castVar);
+ instructions.add(castInvoke);
+ setProperty(insn, property, instructions, castVar);
+ return instructions;
+ }
+ default: {
+ setProperty(insn, property, instructions, insn.getArguments().get(0));
+ return instructions;
+ }
+ }
+ }
return null;
}
+ private void setProperty(InvokeInstruction insn, String property, List instructions,
+ Variable valueVar) {
+ Variable nameVar = program.createVariable();
+ StringConstantInstruction nameInsn = new StringConstantInstruction();
+ nameInsn.setConstant(property);
+ nameInsn.setReceiver(nameVar);
+ instructions.add(nameInsn);
+ InvokeInstruction accessorInvoke = new InvokeInstruction();
+ accessorInvoke.setType(InvocationType.SPECIAL);
+ accessorInvoke.setMethod(new MethodReference(ResourceAccessor.class, "put",
+ Object.class, String.class, Object.class, void.class));
+ accessorInvoke.getArguments().add(insn.getInstance());
+ accessorInvoke.getArguments().add(nameVar);
+ accessorInvoke.getArguments().add(valueVar);
+ instructions.add(accessorInvoke);
+ }
+
+ private void castAndSetProperty(InvokeInstruction insn, String property, List instructions,
+ Class> primitive) {
+ Variable castVar = program.createVariable();
+ InvokeInstruction castInvoke = new InvokeInstruction();
+ castInvoke.setType(InvocationType.SPECIAL);
+ String primitiveCapitalized = primitive.getName();
+ primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
+ primitiveCapitalized.substring(1);
+ castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castFrom" + primitiveCapitalized,
+ primitive, Object.class));
+ castInvoke.getArguments().add(insn.getArguments().get(0));
+ castInvoke.setReceiver(castVar);
+ instructions.add(castInvoke);
+ setProperty(insn, property, instructions, castVar);
+ }
+
private String getPropertyName(String name) {
if (name.length() == 1) {
return name.toLowerCase();
From c3e30cc295f03d325f6a7756397e8ef171d3c4cf Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Mon, 9 Jun 2014 21:26:58 +0400
Subject: [PATCH 14/16] Dependency plugin receives DependencyAgent instead of
DependencyChecker
---
.../java/lang/CharacterNativeGenerator.java | 4 ++--
.../java/lang/ClassNativeGenerator.java | 6 ++---
.../java/lang/ObjectNativeGenerator.java | 18 +++++----------
.../java/lang/StringNativeGenerator.java | 4 ++--
.../java/lang/SystemNativeGenerator.java | 14 ++++++------
.../lang/reflect/ArrayNativeGenerator.java | 22 ++++++++-----------
.../java/util/LocaleNativeGenerator.java | 4 ++--
.../java/util/TimerNativeGenerator.java | 7 +++---
.../teavm/dependency/DependencyPlugin.java | 2 +-
.../java/org/teavm/jso/JSNativeGenerator.java | 20 ++++++++---------
10 files changed, 46 insertions(+), 55 deletions(-)
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java
index 0a06f086c..6a4470e07 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java
@@ -19,7 +19,7 @@ import java.io.IOException;
import org.teavm.classlib.impl.unicode.UnicodeHelper;
import org.teavm.classlib.impl.unicode.UnicodeSupport;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
+import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
@@ -52,7 +52,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin {
}
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "obtainDigitMapping":
case "obtainClasses":
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java
index 88aa1666e..30b71de3b 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ClassNativeGenerator.java
@@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
+import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
@@ -186,7 +186,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
}
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency graph) {
switch (graph.getReference().getName()) {
case "voidClass":
case "booleanClass":
@@ -205,7 +205,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
graph.getResult().propagate("java.lang.Class");
break;
case "newInstance":
- checker.linkMethod(new MethodReference(InstantiationException.class.getName(), "",
+ agent.linkMethod(new MethodReference(InstantiationException.class.getName(), "",
ValueType.VOID), graph.getStack()).use();
break;
}
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java
index 20a5942c6..64c3c2d1a 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java
@@ -17,16 +17,12 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
-import org.teavm.dependency.DependencyPlugin;
-import org.teavm.dependency.MethodDependency;
+import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
-import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
-import org.teavm.model.ValueType;
/**
*
@@ -62,13 +58,13 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
}
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "clone":
method.getVariable(0).connect(method.getResult());
break;
case "getClass":
- achieveGetClass(checker, method);
+ achieveGetClass(agent, method);
break;
case "wrap":
method.getVariable(1).connect(method.getResult());
@@ -87,11 +83,9 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu
writer.append(".constructor)");
}
- private void achieveGetClass(DependencyChecker checker, MethodDependency method) {
- String classClass = "java.lang.Class";
- MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew",
- ValueType.object(classClass)));
- checker.addEntryPoint(initMethod);
+ private void achieveGetClass(DependencyAgent agent, MethodDependency method) {
+ MethodReference initMethod = new MethodReference(Class.class, "createNew", Class.class);
+ agent.linkMethod(initMethod, method.getStack()).use();
method.getResult().propagate("java.lang.Class");
}
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java
index 34ccf207e..2dec76c28 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java
@@ -16,7 +16,7 @@
package org.teavm.classlib.java.lang;
import java.io.IOException;
-import org.teavm.dependency.DependencyChecker;
+import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Injector;
@@ -29,7 +29,7 @@ import org.teavm.model.MethodReference;
*/
public class StringNativeGenerator implements Injector, DependencyPlugin {
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "wrap":
method.getVariable(1).connect(method.getResult());
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java
index 81b66a994..78c4de695 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java
@@ -54,16 +54,16 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
}
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "doArrayCopy":
achieveArrayCopy(method);
break;
case "setOut":
- achieveSetOut(checker, method);
+ achieveSetOut(agent, method);
break;
case "setErr":
- achieveSetErr(checker, method);
+ achieveSetErr(agent, method);
break;
}
}
@@ -97,13 +97,13 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
src.getArrayItem().connect(dest.getArrayItem());
}
- private void achieveSetErr(DependencyChecker checker, MethodDependency method) {
- FieldDependency fieldDep = checker.linkField(new FieldReference("java.lang.System", "err"), method.getStack());
+ private void achieveSetErr(DependencyAgent agent, MethodDependency method) {
+ FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "err"), method.getStack());
method.getVariable(1).connect(fieldDep.getValue());
}
- private void achieveSetOut(DependencyChecker checker, MethodDependency method) {
- FieldDependency fieldDep = checker.linkField(new FieldReference("java.lang.System", "out"), method.getStack());
+ private void achieveSetOut(DependencyAgent agent, MethodDependency method) {
+ FieldDependency fieldDep = agent.linkField(new FieldReference("java.lang.System", "out"), method.getStack());
method.getVariable(1).connect(fieldDep.getValue());
}
}
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java
index a3b9b6a12..0f65e69ed 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java
@@ -17,10 +17,7 @@ package org.teavm.classlib.java.lang.reflect;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
-import org.teavm.dependency.DependencyConsumer;
-import org.teavm.dependency.DependencyPlugin;
-import org.teavm.dependency.MethodDependency;
+import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.ClassReader;
@@ -41,16 +38,16 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
ValueType.INTEGER, ValueType.LONG, ValueType.FLOAT, ValueType.DOUBLE, ValueType.BOOLEAN };
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "getLength":
- achieveGetLength(checker, method);
+ achieveGetLength(agent, method);
break;
case "newInstanceImpl":
method.getResult().propagate("[java.lang.Object");
break;
case "getImpl":
- achieveGet(checker, method);
+ achieveGet(agent, method);
break;
}
}
@@ -81,13 +78,12 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
writer.append("return " + array + ".data.length;").softNewLine();
}
- private void achieveGetLength(final DependencyChecker checker, final MethodDependency method) {
+ private void achieveGetLength(final DependencyAgent agent, final MethodDependency method) {
method.getVariable(1).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) {
if (!type.startsWith("[")) {
- MethodReference cons = new MethodReference("java.lang.IllegalArgumentException",
- new MethodDescriptor("", ValueType.VOID));
- checker.addEntryPoint(cons);
+ MethodReference cons = new MethodReference(IllegalArgumentException.class, "", void.class);
+ agent.linkMethod(cons, method.getStack()).use();
}
}
});
@@ -129,7 +125,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
writer.outdent().append("}").softNewLine();
}
- private void achieveGet(final DependencyChecker checker, final MethodDependency method) {
+ private void achieveGet(final DependencyAgent agent, final MethodDependency method) {
method.getVariable(1).getArrayItem().connect(method.getResult());
method.getVariable(1).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) {
@@ -140,7 +136,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
String wrapper = "java.lang." + primitiveWrappers[i];
MethodReference methodRef = new MethodReference(wrapper, "valueOf",
primitiveTypes[i], ValueType.object(wrapper));
- checker.linkMethod(methodRef, method.getStack()).use();
+ agent.linkMethod(methodRef, method.getStack()).use();
method.getResult().propagate("java.lang." + primitiveWrappers[i]);
}
}
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java
index 1a8fec60b..b81a1d1c1 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/LocaleNativeGenerator.java
@@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
+import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
@@ -63,7 +63,7 @@ public class LocaleNativeGenerator implements Generator, DependencyPlugin {
}
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getMethod().getName()) {
case "getDefaultLocale":
case "getDisplayCountry":
diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimerNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimerNativeGenerator.java
index 387f44216..4d9177f5c 100644
--- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimerNativeGenerator.java
+++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimerNativeGenerator.java
@@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
+import org.teavm.dependency.DependencyAgent;
import org.teavm.dependency.DependencyPlugin;
import org.teavm.dependency.MethodDependency;
import org.teavm.javascript.ni.Generator;
@@ -34,10 +34,11 @@ public class TimerNativeGenerator implements Generator, DependencyPlugin {
"performOnce", ValueType.VOID);
@Override
- public void methodAchieved(DependencyChecker checker, MethodDependency method) {
+ public void methodAchieved(DependencyAgent agent, MethodDependency method) {
switch (method.getReference().getName()) {
case "scheduleOnce": {
- MethodDependency performMethod = checker.linkMethod(performOnceRef, method.getStack());
+ MethodDependency performMethod = agent.linkMethod(performOnceRef, method.getStack());
+ performMethod.use();
method.getVariable(1).connect(performMethod.getVariable(1));
break;
}
diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java
index a69fa55b2..29d650351 100644
--- a/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java
+++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java
@@ -20,5 +20,5 @@ package org.teavm.dependency;
* @author Alexey Andreev
*/
public interface DependencyPlugin {
- void methodAchieved(DependencyChecker checker, MethodDependency method);
+ void methodAchieved(DependencyAgent checker, MethodDependency method);
}
diff --git a/teavm-jso/src/main/java/org/teavm/jso/JSNativeGenerator.java b/teavm-jso/src/main/java/org/teavm/jso/JSNativeGenerator.java
index cb7e4b2a4..74157561c 100644
--- a/teavm-jso/src/main/java/org/teavm/jso/JSNativeGenerator.java
+++ b/teavm-jso/src/main/java/org/teavm/jso/JSNativeGenerator.java
@@ -17,10 +17,7 @@ package org.teavm.jso;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
-import org.teavm.dependency.DependencyChecker;
-import org.teavm.dependency.DependencyConsumer;
-import org.teavm.dependency.DependencyPlugin;
-import org.teavm.dependency.MethodDependency;
+import org.teavm.dependency.*;
import org.teavm.javascript.ast.ConstantExpr;
import org.teavm.javascript.ast.Expr;
import org.teavm.javascript.ast.InvocationExpr;
@@ -28,7 +25,10 @@ import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
-import org.teavm.model.*;
+import org.teavm.model.ClassReader;
+import org.teavm.model.FieldReference;
+import org.teavm.model.MethodReader;
+import org.teavm.model.MethodReference;
/**
*
@@ -115,24 +115,24 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
}
@Override
- public void methodAchieved(final DependencyChecker checker, final MethodDependency method) {
+ public void methodAchieved(final DependencyAgent agent, final MethodDependency method) {
for (int i = 0; i < method.getReference().parameterCount(); ++i) {
method.getVariable(i).addConsumer(new DependencyConsumer() {
@Override public void consume(String type) {
- achieveFunctorMethods(checker, type, method);
+ achieveFunctorMethods(agent, type, method);
}
});
}
}
- private void achieveFunctorMethods(DependencyChecker checker, String type, MethodDependency caller) {
+ private void achieveFunctorMethods(DependencyAgent agent, String type, MethodDependency caller) {
if (caller.isMissing()) {
return;
}
- ClassReader cls = checker.getClassSource().get(type);
+ ClassReader cls = agent.getClassSource().get(type);
if (cls != null) {
for (MethodReader method : cls.getMethods()) {
- checker.linkMethod(method.getReference(), caller.getStack()).use();
+ agent.linkMethod(method.getReference(), caller.getStack()).use();
}
}
}
From 8e521c457fc501ca10fa54224ff8bbfaf10a5623 Mon Sep 17 00:00:00 2001
From: konsoletyper
Date: Tue, 10 Jun 2014 11:10:11 +0400
Subject: [PATCH 15/16] Adds service registration and retrieval infrastructure
---
.../org/teavm/common/ServiceRepository.java | 24 ++++++++++++++++
.../org/teavm/dependency/DependencyAgent.java | 3 +-
.../teavm/dependency/DependencyChecker.java | 14 ++++++++--
.../java/org/teavm/javascript/Renderer.java | 28 +++++++++++++++++--
.../teavm/javascript/RenderingContext.java | 3 +-
.../teavm/javascript/ni/GeneratorContext.java | 3 +-
.../teavm/javascript/ni/InjectorContext.java | 6 +++-
.../src/main/java/org/teavm/vm/TeaVM.java | 22 +++++++++++++--
.../main/java/org/teavm/vm/spi/TeaVMHost.java | 2 ++
9 files changed, 93 insertions(+), 12 deletions(-)
create mode 100644 teavm-core/src/main/java/org/teavm/common/ServiceRepository.java
diff --git a/teavm-core/src/main/java/org/teavm/common/ServiceRepository.java b/teavm-core/src/main/java/org/teavm/common/ServiceRepository.java
new file mode 100644
index 000000000..03f706295
--- /dev/null
+++ b/teavm-core/src/main/java/org/teavm/common/ServiceRepository.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014 Alexey Andreev.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.teavm.common;
+
+/**
+ *
+ * @author Alexey Andreev
+ */
+public interface ServiceRepository {
+ T getService(Class type);
+}
diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java
index 2062ef039..c9a7ae198 100644
--- a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java
+++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java
@@ -15,6 +15,7 @@
*/
package org.teavm.dependency;
+import org.teavm.common.ServiceRepository;
import org.teavm.model.ClassHolder;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
@@ -23,7 +24,7 @@ import org.teavm.model.MethodReference;
*
* @author Alexey Andreev
*/
-public interface DependencyAgent extends DependencyInfo {
+public interface DependencyAgent extends DependencyInfo, ServiceRepository {
DependencyNode createNode();
String generateClassName();
diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java
index 4258d3f08..7f3c52976 100644
--- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java
+++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java
@@ -45,18 +45,21 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
private ConcurrentMap achievableClasses = new ConcurrentHashMap<>();
private ConcurrentMap initializedClasses = new ConcurrentHashMap<>();
private List listeners = new ArrayList<>();
+ private ServiceRepository services;
ConcurrentMap missingMethods = new ConcurrentHashMap<>();
ConcurrentMap missingClasses = new ConcurrentHashMap<>();
ConcurrentMap missingFields = new ConcurrentHashMap<>();
- public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader) {
- this(classSource, classLoader, new SimpleFiniteExecutor());
+ public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
+ this(classSource, classLoader, services, new SimpleFiniteExecutor());
}
- public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
+ public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services,
+ FiniteExecutor executor) {
this.classSource = new DependencyClassSource(classSource);
this.classLoader = classLoader;
this.executor = executor;
+ this.services = services;
methodReaderCache = new ConcurrentCachedMapper<>(new Mapper() {
@Override public MethodReader map(MethodReference preimage) {
return findMethodReader(preimage);
@@ -447,4 +450,9 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
sb.append('\n');
}
}
+
+ @Override
+ public T getService(Class type) {
+ return services.getService(type);
+ }
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
index 1006a503b..ce4d2691e 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java
@@ -22,6 +22,7 @@ import java.util.*;
import org.teavm.codegen.NamingException;
import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter;
+import org.teavm.common.ServiceRepository;
import org.teavm.javascript.ast.*;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.InjectedBy;
@@ -44,6 +45,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
private boolean minifying;
private Map injectorMap = new HashMap<>();
private Properties properties = new Properties();
+ private ServiceRepository services;
private static class InjectorHolder {
public final Injector injector;
@@ -57,11 +59,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
injectorMap.put(method, new InjectorHolder(injector));
}
- public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader) {
+ public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader,
+ ServiceRepository services) {
this.naming = writer.getNaming();
this.writer = writer;
this.classSource = classSource;
this.classLoader = classLoader;
+ this.services = services;
}
@Override
@@ -506,7 +510,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
@Override
public Properties getProperties() {
- return null;
+ return new Properties(properties);
+ }
+
+ @Override
+ public T getService(Class type) {
+ return services.getService(type);
}
}
@@ -1429,5 +1438,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
public int argumentCount() {
return arguments.size();
}
+
+ @Override
+ public T getService(Class type) {
+ return services.getService(type);
+ }
+
+ @Override
+ public Properties getProperties() {
+ return new Properties(properties);
+ }
+ }
+
+ @Override
+ public T getService(Class type) {
+ return services.getService(type);
}
}
diff --git a/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java b/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java
index 48e2b6cae..70c374f53 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/RenderingContext.java
@@ -18,13 +18,14 @@ package org.teavm.javascript;
import java.util.Properties;
import org.teavm.codegen.NamingStrategy;
import org.teavm.codegen.SourceWriter;
+import org.teavm.common.ServiceRepository;
import org.teavm.model.ListableClassReaderSource;
/**
*
* @author Alexey Andreev
*/
-public interface RenderingContext {
+public interface RenderingContext extends ServiceRepository {
NamingStrategy getNaming();
SourceWriter getWriter();
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java
index d54363239..985727a90 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java
@@ -16,13 +16,14 @@
package org.teavm.javascript.ni;
import java.util.Properties;
+import org.teavm.common.ServiceRepository;
import org.teavm.model.ListableClassReaderSource;
/**
*
* @author Alexey Andreev
*/
-public interface GeneratorContext {
+public interface GeneratorContext extends ServiceRepository {
String getParameterName(int index);
ListableClassReaderSource getClassSource();
diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/InjectorContext.java b/teavm-core/src/main/java/org/teavm/javascript/ni/InjectorContext.java
index 95cf19776..71db4a2e9 100644
--- a/teavm-core/src/main/java/org/teavm/javascript/ni/InjectorContext.java
+++ b/teavm-core/src/main/java/org/teavm/javascript/ni/InjectorContext.java
@@ -16,7 +16,9 @@
package org.teavm.javascript.ni;
import java.io.IOException;
+import java.util.Properties;
import org.teavm.codegen.SourceWriter;
+import org.teavm.common.ServiceRepository;
import org.teavm.javascript.ast.Expr;
import org.teavm.model.ValueType;
@@ -24,7 +26,7 @@ import org.teavm.model.ValueType;
*
* @author Alexey Andreev
*/
-public interface InjectorContext {
+public interface InjectorContext extends ServiceRepository {
Expr getArgument(int index);
int argumentCount();
@@ -33,6 +35,8 @@ public interface InjectorContext {
SourceWriter getWriter();
+ Properties getProperties();
+
void writeEscaped(String str) throws IOException;
void writeType(ValueType type) throws IOException;
diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java
index 8eba7ff75..3a9c78e2a 100644
--- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java
+++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java
@@ -19,6 +19,7 @@ import java.io.*;
import java.util.*;
import org.teavm.codegen.*;
import org.teavm.common.FiniteExecutor;
+import org.teavm.common.ServiceRepository;
import org.teavm.dependency.*;
import org.teavm.javascript.Decompiler;
import org.teavm.javascript.Renderer;
@@ -65,7 +66,7 @@ import org.teavm.vm.spi.TeaVMPlugin;
*
* @author Alexey Andreev
*/
-public class TeaVM implements TeaVMHost {
+public class TeaVM implements TeaVMHost, ServiceRepository {
private ClassReaderSource classSource;
private DependencyChecker dependencyChecker;
private FiniteExecutor executor;
@@ -78,12 +79,13 @@ public class TeaVM implements TeaVMHost {
private Map methodGenerators = new HashMap<>();
private Map methodInjectors = new HashMap<>();
private List rendererListeners = new ArrayList<>();
+ private Map, Object> services = new HashMap<>();
private Properties properties = new Properties();
TeaVM(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
this.classSource = classSource;
this.classLoader = classLoader;
- dependencyChecker = new DependencyChecker(this.classSource, classLoader, executor);
+ dependencyChecker = new DependencyChecker(this.classSource, classLoader, this, executor);
this.executor = executor;
}
@@ -335,7 +337,7 @@ public class TeaVM implements TeaVMHost {
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer);
- Renderer renderer = new Renderer(sourceWriter, classSet, classLoader);
+ Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this);
for (Map.Entry entry : methodInjectors.entrySet()) {
renderer.addInjector(entry.getKey(), entry.getValue());
}
@@ -529,4 +531,18 @@ public class TeaVM implements TeaVMHost {
plugin.install(this);
}
}
+
+ @Override
+ public T getService(Class type) {
+ Object service = services.get(type);
+ if (service == null) {
+ throw new IllegalArgumentException("Service not registered: " + type.getName());
+ }
+ return type.cast(service);
+ }
+
+ @Override
+ public void registerService(Class type, T instance) {
+ services.put(type, instance);
+ }
}
diff --git a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
index 2acbda0af..59a38ab52 100644
--- a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
+++ b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java
@@ -41,6 +41,8 @@ public interface TeaVMHost {
void add(RendererListener listener);
+ void registerService(Class