From a9ff14b599ee0e5217024aeb92e6ebc0580cc048 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 26 Feb 2015 23:28:01 +0300 Subject: [PATCH] Repair Class.getEnumConstants() --- .../java/org/teavm/javascript/Renderer.java | 2 +- .../resources/org/teavm/javascript/runtime.js | 46 ---------------- .../java/org/teavm/platform/Platform.java | 5 ++ .../metadata/MetadataGeneratorContext.java | 7 +++ .../metadata/StaticFieldResource.java | 23 ++++++++ .../plugin/BuildTimeStaticFieldResource.java | 42 +++++++++++++++ .../DefaultMetadataGeneratorContext.java | 6 +++ .../plugin/EnumDependencySupport.java | 29 +++++----- .../plugin/PlatformDependencyListener.java | 54 +++++++++++++++++++ .../platform/plugin/PlatformGenerator.java | 35 ++++++++++-- .../teavm/platform/plugin/PlatformPlugin.java | 1 + .../ResourceAccessorDependencyListener.java | 3 ++ 12 files changed, 187 insertions(+), 66 deletions(-) create mode 100644 teavm-platform/src/main/java/org/teavm/platform/metadata/StaticFieldResource.java create mode 100644 teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeStaticFieldResource.java create mode 100644 teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformDependencyListener.java 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 18d8848a9..633b12fa6 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -403,7 +403,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append("],").ws(); int flags = 0; if (cls.getModifiers().contains(NodeModifier.ENUM)) { - flags &= 1; + flags |= 1; } writer.append(flags).append(',').ws(); MethodHolder clinit = classSource.get(cls.getName()).getMethod( diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 40ee7774d..edd420b48 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -328,23 +328,6 @@ function $rt_assertNotNaN(value) { } return value; } -function $rt_methodStubs(data) { - for (var i = 0; i < data.length; i += 2) { - var clinit = data[i + 0]; - var names = data[i + 1]; - if (!(names instanceof Array)) { - names = [names]; - } - for (var j = 0; j < names.length; j = (j + 1) | 0) { - window[names[j]] = (function(name, clinit) { - return function() { - clinit(); - return window[name].apply(window, arguments); - } - })(names[j], clinit); - } - } -} var $rt_stdoutBuffer = ""; function $rt_putStdout(ch) { if (ch == 0xA) { @@ -420,35 +403,6 @@ function $rt_metadata(data) { } } } -function $rt_virtualMethods(cls) { - for (var i = 1; i < arguments.length; i += 2) { - var name = arguments[i]; - var func = arguments[i + 1]; - if (typeof name === 'string') { - cls.prototype[name] = func; - } else { - for (var j = 0; j < name.length; ++j) { - cls.prototype[name[j]] = func; - } - } - } -} -function $rt_virtualMethods(data) { - for (var i = 0; i < data.length; i += 2) { - var cls = data[i + 0]; - var methods = data[i + 1]; - for (var j = 0; j < methods.length; j += 2) { - var name = methods[j + 0]; - var func = methods[j + 1]; - if (typeof name === 'string') { - name = [name]; - } - for (var k = 0; k < name.length; ++k) { - cls.prototype[name[k]] = func; - } - } - } -} function $rt_asyncResult(value) { return function() { return value; diff --git a/teavm-platform/src/main/java/org/teavm/platform/Platform.java b/teavm-platform/src/main/java/org/teavm/platform/Platform.java index 2a11be646..2f602e933 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/Platform.java +++ b/teavm-platform/src/main/java/org/teavm/platform/Platform.java @@ -20,6 +20,7 @@ import org.teavm.javascript.spi.GeneratedBy; import org.teavm.javascript.spi.InjectedBy; import org.teavm.jso.JS; import org.teavm.platform.metadata.ClassResource; +import org.teavm.platform.metadata.StaticFieldResource; import org.teavm.platform.plugin.PlatformGenerator; /** @@ -90,6 +91,10 @@ public final class Platform { @InjectedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) + public static native Object objectFromResource(StaticFieldResource resource); + + @GeneratedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) public static native Enum[] getEnumConstants(PlatformClass cls); @GeneratedBy(PlatformGenerator.class) 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 e505fed5e..e9644c9d2 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 @@ -17,6 +17,7 @@ package org.teavm.platform.metadata; import java.util.Properties; import org.teavm.common.ServiceRepository; +import org.teavm.model.FieldReference; import org.teavm.model.ListableClassReaderSource; import org.teavm.platform.Platform; import org.teavm.vm.TeaVM; @@ -55,6 +56,12 @@ public interface MetadataGeneratorContext extends ServiceRepository { */ ClassResource createClassResource(String className); + /** + * Creates a new resource that represents static field. Client code then may use + * {@link Platform#objectFromResource(StaticFieldResource)} to get actual field value. + */ + StaticFieldResource createFieldResource(FieldReference field); + /** * Creates a new resource array. */ diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/StaticFieldResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/StaticFieldResource.java new file mode 100644 index 000000000..5bfdcead5 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/StaticFieldResource.java @@ -0,0 +1,23 @@ +/* + * Copyright 2015 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 StaticFieldResource extends Resource { +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeStaticFieldResource.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeStaticFieldResource.java new file mode 100644 index 000000000..fa848b04c --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeStaticFieldResource.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015 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.codegen.SourceWriter; +import org.teavm.model.FieldReference; +import org.teavm.platform.metadata.StaticFieldResource; + +/** + * + * @author Alexey Andreev + */ +class BuildTimeStaticFieldResource implements StaticFieldResource, ResourceWriter { + private FieldReference field; + + public BuildTimeStaticFieldResource(FieldReference field) { + this.field = field; + } + + public FieldReference getField() { + return field; + } + + @Override + public void write(SourceWriter writer) throws IOException { + writer.appendField(field); + } +} 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 049fe912b..35a1b08eb 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 @@ -18,6 +18,7 @@ package org.teavm.platform.plugin; import java.lang.reflect.Proxy; import java.util.Properties; import org.teavm.common.ServiceRepository; +import org.teavm.model.FieldReference; import org.teavm.model.ListableClassReaderSource; import org.teavm.platform.metadata.*; @@ -72,6 +73,11 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext { return new BuildTimeClassResource(className); } + @Override + public StaticFieldResource createFieldResource(FieldReference field) { + return new BuildTimeStaticFieldResource(field); + } + @Override public ResourceMap createResourceMap() { return new BuildTimeResourceMap<>(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/EnumDependencySupport.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/EnumDependencySupport.java index fe0deb778..96620653b 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/EnumDependencySupport.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/EnumDependencySupport.java @@ -16,11 +16,7 @@ package org.teavm.platform.plugin; import org.teavm.dependency.*; -import org.teavm.model.CallLocation; -import org.teavm.model.ClassReader; -import org.teavm.model.MethodDescriptor; -import org.teavm.model.MethodReader; -import org.teavm.model.ValueType; +import org.teavm.model.*; import org.teavm.platform.Platform; /** @@ -29,7 +25,6 @@ import org.teavm.platform.Platform; */ public class EnumDependencySupport implements DependencyListener { private DependencyNode allEnums; - private boolean unlocked; @Override public void started(DependencyAgent agent) { @@ -43,21 +38,25 @@ public class EnumDependencySupport implements DependencyListener { return; } allEnums.propagate(agent.getType(className)); - if (unlocked) { - MethodReader method = cls.getMethod(new MethodDescriptor("values", - ValueType.arrayOf(ValueType.object(cls.getName())))); - if (method != null) { - agent.linkMethod(method.getReference(), location).use(); - } - } + } @Override - public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) { + public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) { if (method.getReference().getClassName().equals(Platform.class.getName()) && method.getReference().getName().equals("getEnumConstants")) { - unlocked = true; allEnums.connect(method.getResult().getArrayItem()); + final MethodReference ref = method.getReference(); + allEnums.addConsumer(new DependencyConsumer() { + @Override public void consume(DependencyAgentType type) { + ClassReader cls = agent.getClassSource().get(type.getName()); + MethodReader method = cls.getMethod(new MethodDescriptor("values", + ValueType.arrayOf(ValueType.object(cls.getName())))); + if (method != null) { + agent.linkMethod(method.getReference(), new CallLocation(ref)).use(); + } + } + }); method.getResult().propagate(agent.getType("[java.lang.Enum")); for (String cls : agent.getAchievableClasses()) { classAchieved(agent, cls, location); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformDependencyListener.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformDependencyListener.java new file mode 100644 index 000000000..9ff5ad491 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformDependencyListener.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 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.*; +import org.teavm.model.CallLocation; +import org.teavm.platform.Platform; + +/** + * + * @author Alexey Andreev + */ +public class PlatformDependencyListener implements DependencyListener { + private DependencyNode allClasses; + + @Override + public void started(DependencyAgent agent) { + allClasses = agent.createNode(); + } + + @Override + public void classAchieved(DependencyAgent agent, String className, CallLocation location) { + allClasses.propagate(agent.getType(className)); + } + + @Override + public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) { + if (!method.getReference().getClassName().equals(Platform.class.getName())) { + return; + } + switch (method.getReference().getName()) { + case "objectFromResource": + allClasses.connect(method.getResult()); + break; + } + } + + @Override + public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) { + } +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java index 1360b334a..b5574cdd4 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java @@ -26,6 +26,7 @@ import org.teavm.javascript.spi.Injector; import org.teavm.javascript.spi.InjectorContext; import org.teavm.model.*; import org.teavm.platform.Platform; +import org.teavm.platform.PlatformClass; import org.teavm.platform.PlatformRunnable; /** @@ -58,12 +59,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin switch (methodRef.getName()) { case "asJavaClass": case "classFromResource": + case "objectFromResource": context.writeExpr(context.getArgument(0)); return; - case "getEnumConstants": - context.writeExpr(context.getArgument(0)); - context.getWriter().append(".values()"); - break; } } @@ -85,6 +83,9 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin case "schedule": generateSchedule(context, writer, true); break; + case "getEnumConstants": + generateEnumConstants(context, writer); + break; } } @@ -203,4 +204,30 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin writer.outdent().append("},").ws().append(timeout ? context.getParameterName(2) : "0") .append(");").softNewLine(); } + + private void generateEnumConstants(GeneratorContext context, SourceWriter writer) throws IOException { + writer.append("var c").ws().append("=").ws().append("'$$enumConstants$$';").softNewLine(); + for (String clsName : context.getClassSource().getClassNames()) { + ClassReader cls = context.getClassSource().get(clsName); + MethodReader method = cls.getMethod(new MethodDescriptor("values", + ValueType.arrayOf(ValueType.object(clsName)))); + if (method != null) { + writer.appendClass(clsName).append("[c]").ws().append("=").ws(); + writer.appendMethodBody(method.getReference()); + writer.append(";").softNewLine(); + } + } + + String selfName = writer.getNaming().getFullNameFor(new MethodReference(Platform.class, "getEnumConstants", + PlatformClass.class, Enum[].class)); + writer.append(selfName).ws().append("=").ws().append("function(cls)").ws().append("{").softNewLine().indent(); + writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine(); + writer.append("return null;").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return cls[c]();").softNewLine(); + writer.outdent().append("}").softNewLine(); + + writer.append("return ").append(selfName).append("(").append(context.getParameterName(1)) + .append(");").softNewLine(); + } } 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 17a53af71..4eb92c96b 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 @@ -33,5 +33,6 @@ public class PlatformPlugin implements TeaVMPlugin { host.add(new NewInstanceDependencySupport()); host.add(new ClassLookupDependencySupport()); host.add(new EnumDependencySupport()); + host.add(new PlatformDependencyListener()); } } 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 0e3462599..20e7da06a 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 @@ -36,6 +36,9 @@ class ResourceAccessorDependencyListener implements DependencyListener { @Override public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) { + if (!method.getReference().getClassName().equals(ResourceAccessor.class.getName())) { + return; + } switch (method.getReference().getName()) { case "castToString": method.getResult().propagate(agent.getType("java.lang.String"));