Fixes bugs in JSO and building resources

This commit is contained in:
Alexey Andreev 2014-03-26 23:15:55 +04:00
parent ae60a7b4a0
commit bf68cf4b7d
9 changed files with 129 additions and 44 deletions

View File

@ -120,6 +120,11 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return classSource; return classSource;
} }
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
@Override @Override
public String generateClassName() { public String generateClassName() {
return "$$tmp$$.TempClass" + classNameSuffix++; return "$$tmp$$.TempClass" + classNameSuffix++;

View File

@ -338,6 +338,21 @@ class DependencyGraphBuilder {
@Override @Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "[" + itemType)); useRunners.add(new TypePropagationRunner(nodes[receiver.getIndex()], "[" + itemType));
final String className = extractClassName(itemType);
if (className != null) {
useRunners.add(new Runnable() {
@Override public void run() {
dependencyChecker.initClass(className, callerStack);
}
});
}
}
private String extractClassName(ValueType itemType) {
while (itemType instanceof ValueType.Array) {
itemType = ((ValueType.Array)itemType).getItemType();
}
return itemType instanceof ValueType.Object ? ((ValueType.Object)itemType).getClassName() : null;
} }
@Override @Override

View File

@ -27,6 +27,8 @@ import org.teavm.model.MethodReference;
public interface DependencyInfo { public interface DependencyInfo {
ClassReaderSource getClassSource(); ClassReaderSource getClassSource();
ClassLoader getClassLoader();
boolean isMethodAchievable(MethodReference methodRef); boolean isMethodAchievable(MethodReference methodRef);
Collection<MethodReference> getAchievableMethods(); Collection<MethodReference> getAchievableMethods();

View File

@ -33,6 +33,13 @@ public class DirectoryBuildTarget implements BuildTarget {
@Override @Override
public OutputStream createResource(String fileName) throws IOException { public OutputStream createResource(String fileName) throws IOException {
int index = fileName.lastIndexOf('/');
if (index >= 0) {
File dir = new File(directory, fileName.substring(0, index));
if (!dir.exists()) {
dir.mkdirs();
}
}
return new FileOutputStream(new File(directory, fileName)); return new FileOutputStream(new File(directory, fileName));
} }
} }

View File

@ -166,6 +166,48 @@ public final class JS {
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c, public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
JSObject d, JSObject e, JSObject f, JSObject g, JSObject h); JSObject d, JSObject e, JSObject f, JSObject g, JSObject h);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c, JSObject d);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c, JSObject d, JSObject e);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c, JSObject d, JSObject e, JSObject f);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c, JSObject d, JSObject e, JSObject f, JSObject g);
@InjectedBy(JSNativeGenerator.class)
@PluggableDependency(JSNativeGenerator.class)
public static native JSObject instantiate(JSObject instance, JSObject constructor, JSObject a, JSObject b,
JSObject c, JSObject d, JSObject e, JSObject f, JSObject g, JSObject h);
public static <T extends JSObject> Iterable<T> iterate(final JSArray<T> array) { public static <T extends JSObject> Iterable<T> iterate(final JSArray<T> array) {
return new Iterable<T>() { return new Iterable<T>() {
@Override public Iterator<T> iterator() { @Override public Iterator<T> iterator() {

View File

@ -1,40 +1,16 @@
/*
* 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.jso; package org.teavm.jso;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface JSConstructor<T extends JSObject> extends JSFunction { @Retention(RetentionPolicy.RUNTIME)
T construct(); @Target(ElementType.METHOD)
public @interface JSConstructor {
T construct(JSObject a); String value() default "";
T construct(JSObject a, JSObject b);
T construct(JSObject a, JSObject b, JSObject c);
T construct(JSObject a, JSObject b, JSObject c, JSObject d);
T construct(JSObject a, JSObject b, JSObject c, JSObject d, JSObject e);
T construct(JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f);
T construct(JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f, JSObject g);
T construct(JSObject a, JSObject b, JSObject c, JSObject d, JSObject e, JSObject f, JSObject g, JSObject h);
} }

View File

@ -20,9 +20,12 @@ package org.teavm.jso;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public interface JSGlobal extends JSObject { public interface JSGlobal extends JSObject {
@JSProperty @JSConstructor
JSConstructor<JSArray<JSObject>> getArray(); JSObject newObject();
@JSProperty @JSConstructor
JSConstructor<JSObject> getObject(); <T extends JSObject> JSArray<T> newArray();
@JSConstructor
<T extends JSObject> JSArray<T> newArray(int sz);
} }

View File

@ -87,6 +87,19 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin
} }
writer.append(')'); writer.append(')');
break; break;
case "instantiate":
writer.append("(new ");
context.writeExpr(context.getArgument(0));
renderProperty(context.getArgument(1), context);
writer.append('(');
for (int i = 2; i < context.argumentCount(); ++i) {
if (i > 2) {
writer.append(',').ws();
}
context.writeExpr(context.getArgument(i));
}
writer.append("))");
break;
case "wrap": case "wrap":
context.writeExpr(context.getArgument(0)); context.writeExpr(context.getArgument(0));
break; break;

View File

@ -89,7 +89,7 @@ class JavascriptNativeProcessor {
} }
} else if (isProperSetter(method.getDescriptor())) { } else if (isProperSetter(method.getDescriptor())) {
Variable wrapped = wrap(invoke.getArguments().get(0), method.parameterType(0)); Variable wrapped = wrap(invoke.getArguments().get(0), method.parameterType(0));
addPropertySet(cutPrefix(method.getName(), 3), invoke.getArguments().get(0), wrapped); addPropertySet(cutPrefix(method.getName(), 3), invoke.getInstance(), wrapped);
} else { } else {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " + throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript property declaration"); "a proper native JavaScript property declaration");
@ -111,26 +111,48 @@ class JavascriptNativeProcessor {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " + throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript indexer declaration"); "a proper native JavaScript indexer declaration");
} }
} else {
String name = method.getName();
AnnotationReader constructorAnnot = method.getAnnotations().get(JSConstructor.class.getName());
boolean isConstructor = false;
if (constructorAnnot != null) {
if (!isSupportedType(method.getResultType())) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript constructor declaration");
}
AnnotationValue nameVal = constructorAnnot.getValue("value");
name = nameVal != null ? constructorAnnot.getValue("value").getString() : "";
if (name.isEmpty()) {
if (!method.getName().startsWith("new") || method.getName().length() == 3) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"declared as a native JavaScript constructor, but its name does " +
"not satisfy conventions");
}
name = method.getName().substring(3);
}
isConstructor = true;
} else { } else {
if (method.getResultType() != ValueType.VOID && !isSupportedType(method.getResultType())) { if (method.getResultType() != ValueType.VOID && !isSupportedType(method.getResultType())) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " + throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript method declaration"); "a proper native JavaScript method declaration");
} }
}
for (ValueType arg : method.getParameterTypes()) { for (ValueType arg : method.getParameterTypes()) {
if (!isSupportedType(arg)) { if (!isSupportedType(arg)) {
throw new RuntimeException("Method " + invoke.getMethod() + " is not " + throw new RuntimeException("Method " + invoke.getMethod() + " is not " +
"a proper native JavaScript method declaration"); "a proper native JavaScript method or constructor declaration");
} }
} }
Variable result = invoke.getReceiver() != null ? program.createVariable() : null; Variable result = invoke.getReceiver() != null ? program.createVariable() : null;
InvokeInstruction newInvoke = new InvokeInstruction(); InvokeInstruction newInvoke = new InvokeInstruction();
ValueType[] signature = new ValueType[method.parameterCount() + 3]; ValueType[] signature = new ValueType[method.parameterCount() + 3];
Arrays.fill(signature, ValueType.object(JSObject.class.getName())); Arrays.fill(signature, ValueType.object(JSObject.class.getName()));
newInvoke.setMethod(new MethodReference(JS.class.getName(), "invoke", signature)); newInvoke.setMethod(new MethodReference(JS.class.getName(),
isConstructor ? "instantiate" : "invoke", signature));
newInvoke.setType(InvocationType.SPECIAL); newInvoke.setType(InvocationType.SPECIAL);
newInvoke.setReceiver(result); newInvoke.setReceiver(result);
newInvoke.getArguments().add(invoke.getInstance()); newInvoke.getArguments().add(invoke.getInstance());
newInvoke.getArguments().add(addStringWrap(addString(method.getName()))); newInvoke.getArguments().add(addStringWrap(addString(name)));
for (int k = 0; k < invoke.getArguments().size(); ++k) { for (int k = 0; k < invoke.getArguments().size(); ++k) {
Variable arg = wrapArgument(invoke.getArguments().get(k), method.parameterType(k)); Variable arg = wrapArgument(invoke.getArguments().get(k), method.parameterType(k));
newInvoke.getArguments().add(arg); newInvoke.getArguments().add(arg);