diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java new file mode 100644 index 000000000..8dab8cd2e --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/DeclaringClassMetadataGenerator.java @@ -0,0 +1,32 @@ +/* + * 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.classlib.impl; + +import org.teavm.model.MethodReference; +import org.teavm.platform.metadata.MetadataGenerator; +import org.teavm.platform.metadata.MetadataGeneratorContext; +import org.teavm.platform.metadata.Resource; + +/** + * + * @author Alexey Andreev + */ +public class DeclaringClassMetadataGenerator implements MetadataGenerator { + @Override + public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) { + return null; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index 4d3d853bb..af9de2a36 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -31,7 +31,6 @@ public class JCLPlugin implements TeaVMPlugin { host.add(new EnumDependencySupport()); host.add(new EnumTransformer()); host.add(new ClassLookupDependencySupport()); - host.add(new NewInstanceDependencySupport()); host.add(new ObjectEnrichRenderer()); ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader()); host.add(serviceLoaderSupp); 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 cd94de90f..7080fd740 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 @@ -35,75 +35,18 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { - case "getComponentType0": - generateGetComponentType(context, writer); - break; - case "getSuperclass": - generateGetSuperclass(context, writer); - break; case "forNameImpl": generateForName(context, writer); break; - case "newInstance": - generateNewInstance(context, writer); - break; case "getDeclaringClass": generateGetDeclaringClass(context, writer); break; } } - private void generateGetComponentType(GeneratorContext context, SourceWriter writer) throws IOException { - String thisArg = context.getParameterName(0); - writer.append("var item = " + thisArg + ".$data.$meta.item;").softNewLine(); - writer.append("return item != null ? $rt_cls(item) : null;").softNewLine(); - } - - private void generateGetSuperclass(GeneratorContext context, SourceWriter writer) throws IOException { - String thisArg = context.getParameterName(0); - writer.append("var superclass = " + thisArg + ".$data.$meta.superclass;").softNewLine(); - writer.append("return superclass ? $rt_cls(superclass) : null;").softNewLine(); - } - @Override public void generate(InjectorContext context, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { - case "isInstance": - generateIsInstance(context); - break; - case "isAssignableFrom": - generateIsAssignableFrom(context); - break; - case "voidClass": - context.getWriter().append("$rt_cls($rt_voidcls())"); - break; - case "booleanClass": - context.getWriter().append("$rt_cls($rt_booleancls())"); - break; - case "charClass": - context.getWriter().append("$rt_cls($rt_charcls())"); - break; - case "byteClass": - context.getWriter().append("$rt_cls($rt_bytecls())"); - break; - case "shortClass": - context.getWriter().append("$rt_cls($rt_shortcls())"); - break; - case "intClass": - context.getWriter().append("$rt_cls($rt_intcls())"); - break; - case "longClass": - context.getWriter().append("$rt_cls($rt_longcls())"); - break; - case "floatClass": - context.getWriter().append("$rt_cls($rt_floatcls())"); - break; - case "doubleClass": - context.getWriter().append("$rt_cls($rt_doublecls())"); - break; - case "wrapClass": - context.writeExpr(context.getArgument(0)); - break; case "getEnumConstantsImpl": context.writeExpr(context.getArgument(0)); context.getWriter().append(".$data.values()"); @@ -111,24 +54,6 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug } } - private void generateIsAssignableFrom(InjectorContext context) throws IOException { - SourceWriter writer = context.getWriter(); - writer.append("$rt_isAssignable("); - context.writeExpr(context.getArgument(1)); - writer.append(".$data,").ws(); - context.writeExpr(context.getArgument(0)); - writer.append(".$data)"); - } - - private void generateIsInstance(InjectorContext context) throws IOException { - SourceWriter writer = context.getWriter(); - writer.append("$rt_isInstance("); - context.writeExpr(context.getArgument(1)); - writer.append(",").ws(); - context.writeExpr(context.getArgument(0)); - writer.append(".$data)"); - } - private void generateForName(GeneratorContext context, SourceWriter writer) throws IOException { String param = context.getParameterName(1); writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent(); @@ -140,32 +65,6 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug writer.outdent().append("}").softNewLine(); } - private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException { - String self = context.getParameterName(0); - writer.append("if (!").appendClass("java.lang.Class").append(".$$constructors$$) {").indent().softNewLine(); - writer.appendClass("java.lang.Class").append(".$$constructors$$ = true;").softNewLine(); - for (String clsName : context.getClassSource().getClassNames()) { - ClassReader cls = context.getClassSource().get(clsName); - MethodReader method = cls.getMethod(new MethodDescriptor("", ValueType.VOID)); - if (method != null) { - writer.appendClass(clsName).append(".$$constructor$$ = ").appendMethodBody(method.getReference()) - .append(";").softNewLine(); - } - } - writer.outdent().append("}").softNewLine(); - writer.append("var cls = " + self + ".$data;").softNewLine(); - writer.append("var ctor = cls.$$constructor$$;").softNewLine(); - writer.append("if (!ctor) {").indent().softNewLine(); - writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine(); - writer.appendMethodBody(new MethodReference(InstantiationException.class.getName(), new MethodDescriptor( - "", ValueType.VOID))).append("(ex);").softNewLine(); - writer.append("$rt_throw(ex);").softNewLine(); - writer.outdent().append("}").softNewLine(); - writer.append("var instance = new cls();").softNewLine(); - writer.append("ctor(instance);").softNewLine(); - writer.append("return instance;").softNewLine(); - } - private void generateGetDeclaringClass(GeneratorContext context, SourceWriter writer) throws IOException { String self = context.getParameterName(0); writer.append("if (!").appendClass("java.lang.Class").append(".$$owners$$) {").indent().softNewLine(); @@ -188,25 +87,10 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug @Override public void methodAchieved(DependencyAgent agent, MethodDependency graph, CallLocation location) { switch (graph.getReference().getName()) { - case "voidClass": - case "booleanClass": - case "byteClass": - case "shortClass": - case "charClass": - case "intClass": - case "longClass": - case "floatClass": - case "doubleClass": - case "wrapClass": - case "getSuperclass": - case "getComponentType0": case "forNameImpl": case "getDeclaringClass": graph.getResult().propagate(agent.getType("java.lang.Class")); break; - case "getName": - graph.getResult().propagate(agent.getType("java.lang.String")); - break; case "newInstance": agent.linkMethod(new MethodReference(InstantiationException.class, "", void.class), location).use(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 91ae6d732..668bde0a1 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -15,9 +15,11 @@ */ package org.teavm.classlib.java.lang; -import org.teavm.dependency.PluggableDependency; -import org.teavm.javascript.spi.GeneratedBy; +import org.teavm.classlib.impl.DeclaringClassMetadataGenerator; import org.teavm.javascript.spi.InjectedBy; +import org.teavm.platform.Platform; +import org.teavm.platform.PlatformClass; +import org.teavm.platform.metadata.MetadataProvider; /** * @@ -25,102 +27,122 @@ import org.teavm.javascript.spi.InjectedBy; */ public class TClass extends TObject { TString name; - TString binaryName; - boolean primitive; - boolean array; - boolean isEnum; private TClass componentType; private boolean componentTypeDirty = true; + private PlatformClass platformClass; - static TClass createNew() { - return new TClass<>(); + private TClass(PlatformClass platformClass) { + this.platformClass = platformClass; + platformClass.setJavaClass(Platform.getPlatformObject(this)); } - @InjectedBy(ClassNativeGenerator.class) - public native boolean isInstance(TObject obj); + static TClass getClass(PlatformClass cls) { + if (cls == null) { + return null; + } + TClass result = (TClass)(Object)Platform.asJavaClass(cls.getJavaClass()); + if (result == null) { + result = new TClass<>(cls); + } + return result; + } - @InjectedBy(ClassNativeGenerator.class) - public native boolean isAssignableFrom(TClass obj); + PlatformClass getPlatformClass() { + return platformClass; + } + + public boolean isInstance(TObject obj) { + return Platform.isInstance(Platform.getPlatformObject(obj), platformClass); + } + + public boolean isAssignableFrom(TClass obj) { + return Platform.isAssignable(obj.getPlatformClass(), platformClass); + } - @PluggableDependency(ClassNativeGenerator.class) public TString getName() { + if (name == null) { + name = TString.wrap(platformClass.getMetadata().getName()); + } return name; } public boolean isPrimitive() { - return primitive; + return platformClass.getMetadata().isPrimitive(); } public boolean isArray() { - return array; + return platformClass.getMetadata().isArray(); } public boolean isEnum() { - return isEnum; + return platformClass.getMetadata().isEnum(); } public TClass getComponentType() { if (componentTypeDirty) { - componentType = getComponentType0(); + PlatformClass arrayItem = platformClass.getMetadata().getArrayItem(); + componentType = arrayItem != null ? getClass(arrayItem) : null; componentTypeDirty = false; } return componentType; } - @GeneratedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - private native TClass getComponentType0(); + @SuppressWarnings("unchecked") + static TClass voidClass() { + return (TClass)getClass(Platform.getPrimitives().getVoidClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass voidClass(); + @SuppressWarnings("unchecked") + static TClass booleanClass() { + return (TClass)getClass(Platform.getPrimitives().getBooleanClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass booleanClass(); + @SuppressWarnings("unchecked") + static TClass charClass() { + return (TClass)getClass(Platform.getPrimitives().getCharClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass charClass(); + @SuppressWarnings("unchecked") + static TClass byteClass() { + return (TClass)getClass(Platform.getPrimitives().getByteClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass byteClass(); + @SuppressWarnings("unchecked") + static TClass shortClass() { + return (TClass)getClass(Platform.getPrimitives().getShortClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass shortClass(); + @SuppressWarnings("unchecked") + static TClass intClass() { + return (TClass)getClass(Platform.getPrimitives().getIntClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass intClass(); + @SuppressWarnings("unchecked") + static TClass longClass() { + return (TClass)getClass(Platform.getPrimitives().getLongClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass longClass(); + @SuppressWarnings("unchecked") + static TClass floatClass() { + return (TClass)getClass(Platform.getPrimitives().getFloatClass()); + } - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass floatClass(); - - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - static native TClass doubleClass(); - - @InjectedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - public static native TClass wrapClass(Class cls); + @SuppressWarnings("unchecked") + static TClass doubleClass() { + return (TClass)getClass(Platform.getPrimitives().getDoubleClass()); + } public boolean desiredAssertionStatus() { return true; } - @GeneratedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - public native TClass getSuperclass(); + @SuppressWarnings("unchecked") + public TClass getSuperclass() { + return (TClass)getClass(platformClass.getMetadata().getSuperclass()); + } public T[] getEnumConstants() { - return isEnum ? getEnumConstantsImpl() : null; + return isEnum() ? getEnumConstantsImpl() : null; } @InjectedBy(ClassNativeGenerator.class) @@ -128,10 +150,9 @@ public class TClass extends TObject { @SuppressWarnings("unchecked") public T cast(TObject obj) { - if (obj != null && !isAssignableFrom(TClass.wrapClass(obj.getClass()))) { - throw new TClassCastException(TString.wrap(new TStringBuilder() - .append(TClass.wrapClass(obj.getClass()).getName()) - .append(TString.wrap(" is not subtype of ")).append(name).toString())); + if (obj != null && !isAssignableFrom((TClass)(Object)obj.getClass())) { + throw new TClassCastException(TString.wrap(obj.getClass().getName() + + " is not subtype of " + name)); } return (T)obj; } @@ -140,30 +161,25 @@ public class TClass extends TObject { return TClassLoader.getSystemClassLoader(); } - @GeneratedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - private static native TClass forNameImpl(TString name); - public static TClass forName(TString name) throws TClassNotFoundException { - TClass result = forNameImpl(name); - if (result == null) { + PlatformClass cls = Platform.lookupClass(name.toString()); + if (cls == null) { throw new TClassNotFoundException(); } - return result; + return getClass(cls); } @SuppressWarnings("unused") public static TClass forName(TString name, boolean initialize, TClassLoader loader) - throws TClassNotFoundException { + throws TClassNotFoundException { return forName(name); } - @GeneratedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) - public native T newInstance() throws TInstantiationException, TIllegalAccessException; + public T newInstance() throws TInstantiationException, TIllegalAccessException { + return Platform.newInstance(platformClass); + } - @GeneratedBy(ClassNativeGenerator.class) - @PluggableDependency(ClassNativeGenerator.class) + @MetadataProvider(DeclaringClassMetadataGenerator.class) public native TClass getDeclaringClass(); @SuppressWarnings("unchecked") diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java index 9ff6bbb18..cc02cc5d7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TEnum.java @@ -61,7 +61,7 @@ public abstract class TEnum> extends TObject implements TComp @SuppressWarnings("unchecked") public final TClass getDeclaringClass() { - return (TClass)TClass.wrapClass(getClass()); + return (TClass)(Object)getClass(); } @Override diff --git a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java index 5e2749cb4..a1ced11f0 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java +++ b/teavm-core/src/main/java/org/teavm/codegen/SourceWriter.java @@ -103,6 +103,10 @@ public class SourceWriter implements Appendable, LocationProvider { return append(naming.getNameFor(cls)); } + public SourceWriter appendClass(Class cls) throws NamingException, IOException { + return append(naming.getNameFor(cls.getName())); + } + public SourceWriter appendField(FieldReference field) throws NamingException, IOException { return append(naming.getNameFor(field)); } @@ -113,7 +117,12 @@ public class SourceWriter implements Appendable, LocationProvider { public SourceWriter appendMethod(String className, String name, ValueType... params) throws NamingException, IOException { - return append(naming.getNameFor(new MethodReference(className, new MethodDescriptor(name, params)))); + return append(naming.getNameFor(new MethodReference(className, name, params))); + } + + public SourceWriter appendMethod(Class cls, String name, Class... params) + throws NamingException, IOException { + return append(naming.getNameFor(new MethodReference(cls, name, params))); } public SourceWriter appendMethodBody(MethodReference method) throws NamingException, IOException { @@ -125,6 +134,11 @@ public class SourceWriter implements Appendable, LocationProvider { return append(naming.getFullNameFor(new MethodReference(className, new MethodDescriptor(name, params)))); } + public SourceWriter appendMethodBody(Class cls, String name, Class... params) + throws NamingException, IOException { + return append(naming.getFullNameFor(new MethodReference(cls, name, params))); + } + private void appendIndent() throws IOException { if (minified) { return; diff --git a/teavm-jso/src/main/java/org/teavm/jso/JS.java b/teavm-jso/src/main/java/org/teavm/jso/JS.java index 19eaa7d1c..bd99b5f6f 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/JS.java +++ b/teavm-jso/src/main/java/org/teavm/jso/JS.java @@ -102,7 +102,7 @@ public final class JS { public static native JSObject wrap(short num); @InjectedBy(JSNativeGenerator.class) - public static native JSObject pass(Object obj); + public static native JSObject marshall(Object obj); public static JSArray wrap(T[] array) { JSArray result = createArray(array.length); diff --git a/teavm-platform/pom.xml b/teavm-platform/pom.xml index 9388726fa..a9ea6d967 100644 --- a/teavm-platform/pom.xml +++ b/teavm-platform/pom.xml @@ -35,6 +35,16 @@ teavm-core ${project.version} + + org.teavm + teavm-jso + ${project.version} + + + org.teavm + teavm-dom + ${project.version} + junit junit diff --git a/teavm-platform/src/main/java/org/teavm/platform/Platform.java b/teavm-platform/src/main/java/org/teavm/platform/Platform.java new file mode 100644 index 000000000..e115ff33b --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/Platform.java @@ -0,0 +1,78 @@ +/* + * 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; + +import org.teavm.dependency.PluggableDependency; +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.plugin.PlatformGenerator; + +/** + * + * @author Alexey Andreev + */ +public final class Platform { + private Platform() { + } + + public static PlatformObject getPlatformObject(Object obj) { + return (PlatformObject)JS.marshall(obj); + } + + public static boolean isInstance(PlatformObject obj, PlatformClass cls) { + return obj != null && !JS.isUndefined(obj.getPlatformClass().getMetadata()) && + isAssignable(obj.getPlatformClass(), cls); + } + + public static boolean isAssignable(PlatformClass from, PlatformClass to) { + if (from == to) { + return true; + } + PlatformSequence supertypes = from.getMetadata().getSupertypes(); + for (int i = 0; i < supertypes.getLength(); ++i) { + if (isAssignable(supertypes.get(i), to)) { + return true; + } + } + return false; + } + + @InjectedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) + public static native Class asJavaClass(PlatformObject obj); + + public static PlatformPrimitives getPrimitives() { + return (PlatformPrimitives)JS.getGlobal(); + } + + @GeneratedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) + public static native T newInstance(PlatformClass cls); + + @GeneratedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) + public static native PlatformClass lookupClass(String name); + + @GeneratedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) + public static native void initClass(PlatformClass cls); + + @GeneratedBy(PlatformGenerator.class) + @PluggableDependency(PlatformGenerator.class) + public static native PlatformClass classFromResource(ClassResource resource); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java new file mode 100644 index 000000000..b127fe84f --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformClass.java @@ -0,0 +1,35 @@ +/* + * 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; + +import org.teavm.jso.JSObject; +import org.teavm.jso.JSProperty; +import org.teavm.platform.metadata.Resource; + +/** + * + * @author Alexey Andreev + */ +public interface PlatformClass extends JSObject, Resource { + @JSProperty("$meta") + PlatformClassMetadata getMetadata(); + + @JSProperty("classObject") + void setJavaClass(PlatformObject obj); + + @JSProperty("classObject") + PlatformObject getJavaClass(); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java new file mode 100644 index 000000000..80a540f60 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java @@ -0,0 +1,46 @@ +/* + * 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; + +import org.teavm.jso.JSObject; +import org.teavm.jso.JSProperty; + +/** + * + * @author Alexey Andreev + */ +public interface PlatformClassMetadata extends JSObject { + @JSProperty("item") + PlatformClass getArrayItem(); + + @JSProperty + PlatformSequence getSupertypes(); + + @JSProperty + PlatformClass getSuperclass(); + + @JSProperty + String getName(); + + @JSProperty + boolean isPrimitive(); + + @JSProperty + boolean isArray(); + + @JSProperty + boolean isEnum(); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformObject.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformObject.java new file mode 100644 index 000000000..1e547f331 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformObject.java @@ -0,0 +1,28 @@ +/* + * 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; + +import org.teavm.jso.JSObject; +import org.teavm.jso.JSProperty; + +/** + * + * @author Alexey Andreev + */ +public interface PlatformObject extends JSObject { + @JSProperty("constructor") + PlatformClass getPlatformClass(); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java new file mode 100644 index 000000000..f1a9b9cf9 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformPrimitives.java @@ -0,0 +1,52 @@ +/* + * 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; + +import org.teavm.jso.JSObject; +import org.teavm.jso.JSProperty; + +/** + * + * @author Alexey Andreev + */ +public interface PlatformPrimitives extends JSObject { + @JSProperty("$rt_voidcls") + PlatformClass getVoidClass(); + + @JSProperty("$rt_booleancls") + PlatformClass getBooleanClass(); + + @JSProperty("$rt_bytecls") + PlatformClass getByteClass(); + + @JSProperty("$rt_shortcls") + PlatformClass getShortClass(); + + @JSProperty("$rt_charcls") + PlatformClass getCharClass(); + + @JSProperty("$rt_intcls") + PlatformClass getIntClass(); + + @JSProperty("$rt_longcls") + PlatformClass getLongClass(); + + @JSProperty("$rt_floatcls") + PlatformClass getFloatClass(); + + @JSProperty("$rt_doublecls") + PlatformClass getDoubleClass(); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java b/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java new file mode 100644 index 000000000..c5ce51330 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/PlatformSequence.java @@ -0,0 +1,32 @@ +/* + * 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; + +import org.teavm.jso.JSIndexer; +import org.teavm.jso.JSObject; +import org.teavm.jso.JSProperty; + +/** + * + * @author Alexey Andreev + */ +public interface PlatformSequence extends JSObject { + @JSProperty + int getLength(); + + @JSIndexer + T get(int index); +} diff --git a/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassResource.java b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassResource.java new file mode 100644 index 000000000..143bf608c --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/metadata/ClassResource.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 ClassResource extends Resource { +} 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 067b4fe26..e505fed5e 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 @@ -18,6 +18,7 @@ package org.teavm.platform.metadata; import java.util.Properties; import org.teavm.common.ServiceRepository; import org.teavm.model.ListableClassReaderSource; +import org.teavm.platform.Platform; import org.teavm.vm.TeaVM; /** @@ -48,6 +49,12 @@ public interface MetadataGeneratorContext extends ServiceRepository { */ T createResource(Class resourceType); + /** + * Creates a new resource that represents class literal. Client code then may use + * {@link Platform#classFromResource(ClassResource)} to get actual class. + */ + ClassResource createClassResource(String className); + /** * Creates a new resource array. */ diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeClassResource.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeClassResource.java new file mode 100644 index 000000000..2e9ac00dd --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/BuildTimeClassResource.java @@ -0,0 +1,41 @@ +/* + * 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.platform.metadata.ClassResource; + +/** + * + * @author Alexey Andreev + */ +class BuildTimeClassResource implements ClassResource, ResourceWriter { + private String className; + + public BuildTimeClassResource(String className) { + this.className = className; + } + + public String getClassName() { + return className; + } + + @Override + public void write(SourceWriter writer) throws IOException { + writer.appendClass(className); + } +} 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 947202715..049fe912b 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,10 +19,7 @@ import java.lang.reflect.Proxy; import java.util.Properties; import org.teavm.common.ServiceRepository; 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; +import org.teavm.platform.metadata.*; /** * @@ -70,6 +67,11 @@ class DefaultMetadataGeneratorContext implements MetadataGeneratorContext { return new BuildTimeResourceArray<>(); } + @Override + public ClassResource createClassResource(String className) { + return new BuildTimeClassResource(className); + } + @Override public ResourceMap createResourceMap() { return new BuildTimeResourceMap<>(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java similarity index 83% rename from teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java rename to teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java index e94490899..14897e80b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/NewInstanceDependencySupport.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.classlib.impl; +package org.teavm.platform.plugin; import org.teavm.dependency.*; import org.teavm.model.*; +import org.teavm.platform.Platform; /** * @@ -39,7 +40,7 @@ public class NewInstanceDependencySupport implements DependencyListener { if (cls.hasModifier(ElementModifier.ABSTRACT) || cls.hasModifier(ElementModifier.INTERFACE)) { return; } - MethodReader method = cls.getMethod(new MethodDescriptor("", ValueType.VOID)); + MethodReader method = cls.getMethod(new MethodDescriptor("", void.class)); if (method != null) { allClassesNode.propagate(agent.getType(className)); } @@ -48,7 +49,7 @@ public class NewInstanceDependencySupport implements DependencyListener { @Override public void methodAchieved(final DependencyAgent agent, MethodDependency method, final CallLocation location) { MethodReader reader = method.getMethod(); - if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) { + if (reader.getOwnerName().equals(Platform.class.getName()) && reader.getName().equals("newInstance")) { allClassesNode.connect(method.getResult()); method.getResult().addConsumer(new DependencyConsumer() { @Override public void consume(DependencyAgentType type) { @@ -59,8 +60,10 @@ public class NewInstanceDependencySupport implements DependencyListener { } private void attachConstructor(DependencyAgent checker, String type, CallLocation location) { - MethodReference ref = new MethodReference(type, new MethodDescriptor("", ValueType.VOID)); - checker.linkMethod(ref, location).use(); + MethodReference ref = new MethodReference(type, "", ValueType.VOID); + MethodDependency methodDep = checker.linkMethod(ref, location); + methodDep.getVariable(0).propagate(checker.getType(type)); + methodDep.use(); } @Override 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 new file mode 100644 index 000000000..1e83f74e1 --- /dev/null +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java @@ -0,0 +1,87 @@ +/* + * 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.dependency.DependencyAgent; +import org.teavm.dependency.DependencyPlugin; +import org.teavm.dependency.MethodDependency; +import org.teavm.javascript.spi.Generator; +import org.teavm.javascript.spi.GeneratorContext; +import org.teavm.javascript.spi.Injector; +import org.teavm.javascript.spi.InjectorContext; +import org.teavm.model.*; +import org.teavm.platform.Platform; + +/** + * + * @author Alexey Andreev + */ +public class PlatformGenerator implements Generator, Injector, DependencyPlugin { + @Override + public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) { + switch (method.getReference().getName()) { + case "asJavaClass": + method.getResult().propagate(agent.getType("java.lang.Class")); + return; + } + } + + @Override + public void generate(InjectorContext context, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "asJavaClass": + context.writeExpr(context.getArgument(0)); + return; + } + } + + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "newInstance": + generateNewInstance(context, writer); + } + } + + private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException { + String self = context.getParameterName(0); + writer.append("if").ws().append("(!").appendClass(Platform.class).append(".$$constructors$$)").ws() + .append("{").indent().softNewLine(); + writer.appendClass(Platform.class).append(".$$constructors$$").ws().append("=").append("true;").softNewLine(); + for (String clsName : context.getClassSource().getClassNames()) { + ClassReader cls = context.getClassSource().get(clsName); + MethodReader method = cls.getMethod(new MethodDescriptor("", void.class)); + if (method != null) { + writer.appendClass(clsName).append(".$$constructor$$").ws().append("=").ws() + .appendMethodBody(method.getReference()).append(";").softNewLine(); + } + } + writer.outdent().append("}").softNewLine(); + writer.append("var cls = " + self + ".$data;").softNewLine(); + writer.append("var ctor = cls.$$constructor$$;").softNewLine(); + writer.append("if (!ctor) {").indent().softNewLine(); + writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine(); + writer.appendMethodBody(new MethodReference(InstantiationException.class, "", void.class)) + .append("(ex);").softNewLine(); + writer.append("$rt_throw(ex);").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("var instance = new cls();").softNewLine(); + writer.append("ctor(instance);").softNewLine(); + writer.append("return instance;").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 5c3a34bd4..e722ccfd8 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 @@ -30,5 +30,6 @@ public class PlatformPlugin implements TeaVMPlugin { host.add(new ResourceAccessorTransformer(host)); host.add(new ResourceAccessorDependencyListener()); host.add(new AsyncMethodProcessor()); + host.add(new NewInstanceDependencySupport()); } }