Adds simple support of Class.forName and class.newInstance

This commit is contained in:
konsoletyper 2014-02-23 21:14:10 +04:00
parent 6e4e66c759
commit 9cdc099b1a
17 changed files with 410 additions and 12 deletions

View File

@ -27,5 +27,6 @@ public class JCLPlugin implements JavascriptBuilderPlugin {
public void install(JavascriptBuilderHost host) {
host.add(new EnumDependencySupport());
host.add(new EnumTransformer());
host.add(new NewInstanceDependencySupport());
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.classlib.impl;
import org.teavm.dependency.*;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class NewInstanceDependencySupport implements DependencyListener {
private DependencyNode allClassesNode;
@Override
public void started(DependencyChecker dependencyChecker) {
allClassesNode = dependencyChecker.createNode();
}
@Override
public void classAchieved(DependencyChecker dependencyChecker, String className) {
ClassReader cls = dependencyChecker.getClassSource().get(className);
if (cls.hasModifier(ElementModifier.ABSTRACT) || cls.hasModifier(ElementModifier.INTERFACE)) {
return;
}
if (cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID)) != null) {
allClassesNode.propagate(className);
}
}
@Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
MethodReader reader = method.getMethod();
if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) {
allClassesNode.connect(method.getResult());
}
}
@Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
}
}

View File

@ -24,7 +24,7 @@ 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.MethodReference;
import org.teavm.model.*;
/**
*
@ -41,6 +41,12 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "getSuperclass":
generateGetSuperclass(context, writer);
break;
case "forNameImpl":
generateForName(context, writer);
break;
case "newInstance":
generateNewInstance(context, writer);
break;
}
}
@ -102,6 +108,43 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
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();
for (String name : context.getClassSource().getClassNames()) {
writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ")
.append("return $rt_cls(").appendClass(name).append(");").softNewLine();
}
writer.append("default: return null;").softNewLine();
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("<init>", 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 === null) {").indent().softNewLine();
writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();");
writer.appendMethodBody(new MethodReference(InstantiationException.class.getName(), new MethodDescriptor(
"<init>", 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)");
writer.append("return instance");
}
@Override
public void methodAchieved(DependencyChecker checker, MethodDependency graph) {
switch (graph.getReference().getName()) {
@ -110,6 +153,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "wrap":
case "getSuperclass":
case "getComponentType0":
case "forNameImpl":
graph.getResult().propagate("java.lang.Class");
break;
}

View File

@ -109,4 +109,29 @@ public class TClass<T extends TObject> extends TObject {
}
return (T)obj;
}
public TClassLoader getClassLoader() {
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) {
throw new TClassNotFoundException();
}
return result;
}
@SuppressWarnings("unused")
public static TClass<?> forName(TString name, boolean initialize, TClassLoader loader)
throws TClassNotFoundException {
return forName(name);
}
@GeneratedBy(ClassNativeGenerator.class)
public native T newInstance() throws TInstantiationException, TIllegalAccessException;
}

View File

@ -0,0 +1,41 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public abstract class TClassLoader extends TObject {
private TClassLoader parent;
private static TSystemClassLoader systemClassLoader = new TSystemClassLoader();
protected TClassLoader() {
this(null);
}
protected TClassLoader(TClassLoader parent) {
this.parent = parent;
}
public TClassLoader getParent() {
return parent;
}
public static TClassLoader getSystemClassLoader() {
return systemClassLoader;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TClassNotFoundException extends TReflectiveOperationException {
private static final long serialVersionUID = -1162632869775788325L;
public TClassNotFoundException() {
super();
}
public TClassNotFoundException(TString message, TThrowable cause) {
super(message, cause);
}
public TClassNotFoundException(TString message) {
super(message);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TIllegalAccessException extends ReflectiveOperationException {
private static final long serialVersionUID = 8240407889170934565L;
public TIllegalAccessException() {
super();
}
public TIllegalAccessException(String message) {
super(message);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TInstantiationException extends ReflectiveOperationException {
private static final long serialVersionUID = 8771605296206833516L;
public TInstantiationException() {
super();
}
public TInstantiationException(String message) {
super(message);
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TReflectiveOperationException extends TException {
private static final long serialVersionUID = -455785869284249992L;
public TReflectiveOperationException() {
super();
}
public TReflectiveOperationException(TString message, TThrowable cause) {
super(message, cause);
}
public TReflectiveOperationException(TString message) {
super(message);
}
public TReflectiveOperationException(TThrowable cause) {
super(cause);
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
class TSystemClassLoader extends TClassLoader {
TSystemClassLoader() {
}
}

View File

@ -29,8 +29,8 @@ public class LoggerNativeGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
writer.append("if (console) {").indent().softNewLine();
writer.append("console.").append(methodRef.getName()).append("(").append(context.getParameterName(1))
.append(");").softNewLine();
writer.append("console.").append(methodRef.getName()).append("($rt_ustr(").append(context.getParameterName(1))
.append("));").softNewLine();
writer.outdent().append("}").softNewLine();
}
}

View File

@ -89,4 +89,12 @@ public class ClassTest {
Object obj = 23;
Float.class.cast(obj);
}
@Test
public void instanceCreatedThroughReflection() throws Exception {
Runnable instance = (Runnable)Class.forName(TestObject.class.getName()).newInstance();
instance.run();
assertEquals(TestObject.class, instance.getClass());
assertEquals(1, ((TestObject)instance).getCounter());
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TestObject extends Object implements Runnable {
private int counter;
public TestObject() {
}
@Override
public void run() {
++counter;
}
public int getCounter() {
return counter;
}
}

View File

@ -37,7 +37,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
private static final String variableNames = "abcdefghijkmnopqrstuvwxyz";
private NamingStrategy naming;
private SourceWriter writer;
private ClassHolderSource classSource;
private ListableClassHolderSource classSource;
private ClassLoader classLoader;
private boolean minifying;
private Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
@ -50,7 +50,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
}
}
public Renderer(SourceWriter writer, ClassHolderSource classSource, ClassLoader classLoader) {
public Renderer(SourceWriter writer, ListableClassHolderSource classSource, ClassLoader classLoader) {
this.naming = writer.getNaming();
this.writer = writer;
this.classSource = classSource;
@ -442,7 +442,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
}
@Override
public ClassReaderSource getClassSource() {
public ListableClassReaderSource getClassSource() {
return classSource;
}
}

View File

@ -15,7 +15,7 @@
*/
package org.teavm.javascript.ni;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ListableClassReaderSource;
/**
*
@ -24,5 +24,5 @@ import org.teavm.model.ClassReaderSource;
public interface GeneratorContext {
String getParameterName(int index);
ClassReaderSource getClassSource();
ListableClassReaderSource getClassSource();
}

View File

@ -15,12 +15,9 @@
*/
package org.teavm.model;
import java.util.Set;
/**
*
* @author Alexey Andreev
*/
public interface ListableClassHolderSource extends ClassHolderSource {
Set<String> getClassNames();
public interface ListableClassHolderSource extends ClassHolderSource, ListableClassReaderSource {
}

View File

@ -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.model;
import java.util.Set;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public interface ListableClassReaderSource extends ClassReaderSource {
Set<String> getClassNames();
}