diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumDependencySupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumDependencySupport.java index 5a505455d..21cf3283c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumDependencySupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumDependencySupport.java @@ -38,8 +38,9 @@ public class EnumDependencySupport implements DependencyListener { public void classAchieved(DependencyChecker dependencyChecker, String className) { ClassReader cls = dependencyChecker.getClassSource().get(className); if (cls == null || cls.getParent() == null || !cls.getParent().equals("java.lang.Enum")) { - allEnums.propagate(className); + return; } + allEnums.propagate(className); if (enumConstantsStack != null) { MethodReader method = cls.getMethod(new MethodDescriptor("values", ValueType.arrayOf(ValueType.object(cls.getName())))); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java index 1e8aecad6..09dd74958 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/NewInstanceDependencySupport.java @@ -34,6 +34,9 @@ public class NewInstanceDependencySupport implements DependencyListener { @Override public void classAchieved(DependencyChecker dependencyChecker, String className) { ClassReader cls = dependencyChecker.getClassSource().get(className); + if (cls == null) { + return; + } if (cls.hasModifier(ElementModifier.ABSTRACT) || cls.hasModifier(ElementModifier.INTERFACE)) { return; } 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 252e5b26a..20a5942c6 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 @@ -65,13 +65,13 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu public void methodAchieved(DependencyChecker checker, MethodDependency method) { switch (method.getReference().getName()) { case "clone": - achieveClone(method); + method.getVariable(0).connect(method.getResult()); break; case "getClass": achieveGetClass(checker, method); break; case "wrap": - achieveWrap(method); + method.getVariable(1).connect(method.getResult()); break; } } @@ -109,15 +109,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu writer.append("return copy;").softNewLine(); } - private void achieveClone(MethodDependency method) { - method.getVariable(0).connect(method.getResult()); - } - private void generateWrap(InjectorContext context) throws IOException { context.writeExpr(context.getArgument(0)); } - - private void achieveWrap(MethodDependency graph) { - graph.getVariable(1).connect(graph.getResult()); - } } 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 69bf0e7a7..64d510deb 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,6 +16,9 @@ package org.teavm.classlib.java.lang; import java.io.IOException; +import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyPlugin; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ni.Injector; import org.teavm.javascript.ni.InjectorContext; import org.teavm.model.MethodReference; @@ -24,17 +27,22 @@ import org.teavm.model.MethodReference; * * @author Alexey Andreev */ -public class StringNativeGenerator implements Injector { +public class StringNativeGenerator implements Injector, DependencyPlugin { @Override - public void generate(InjectorContext context, MethodReference methodRef) throws IOException { - switch (methodRef.getName()) { + public void methodAchieved(DependencyChecker checker, MethodDependency method) { + switch (method.getReference().getName()) { case "wrap": - generateWrap(context); + method.getVariable(0).connect(method.getResult()); break; } } - private void generateWrap(InjectorContext context) throws IOException { - context.writeExpr(context.getArgument(0)); + @Override + public void generate(InjectorContext context, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "wrap": + context.writeExpr(context.getArgument(0)); + break; + } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java index 80589f05f..664075ae6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TString.java @@ -19,6 +19,7 @@ import org.teavm.classlib.impl.charset.*; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TUnsupportedEncodingException; import org.teavm.classlib.java.util.TArrays; +import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.InjectedBy; import org.teavm.javascript.ni.Rename; @@ -549,6 +550,7 @@ public class TString extends TObject implements TSerializable, TComparable extends TObject { + private boolean initialized; + private T value; + + public TThreadLocal() { + super(); + } + + protected T initialValue() { + return null; + } + + public T get() { + if (!initialized) { + value = initialValue(); + initialized = true; + } + return value; + } + + public void set(T value) { + this.value = value; + } + + public void remove() { + initialized = false; + value = null; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java index 943794448..cba174630 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TArrayList.java @@ -42,6 +42,7 @@ public class TArrayList extends TAbstractList implements TCloneable, TSeri for (int i = 0; i < array.length; ++i) { array[i] = iter.next(); } + size = array.length; } public void trimToSize() { diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/util/CollectionsTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/util/CollectionsTest.java new file mode 100644 index 000000000..b873997ec --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/lang/util/CollectionsTest.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.classlib.java.lang.util; + +import static org.junit.Assert.assertEquals; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class CollectionsTest { + private List array; + + @Test + public void arraySorted() { + array = new ArrayList<>(); + array.addAll(Arrays.asList(2, 5, 7, 3, 5, 6)); + Collections.sort(array); + assertEquals(Integer.valueOf(2), array.get(0)); + assertEquals(Integer.valueOf(3), array.get(1)); + assertEquals(Integer.valueOf(5), array.get(2)); + assertEquals(Integer.valueOf(5), array.get(3)); + assertEquals(Integer.valueOf(6), array.get(4)); + assertEquals(Integer.valueOf(7), array.get(5)); + } +} 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 23ff0723e..a69fa55b2 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 graph); + void methodAchieved(DependencyChecker checker, MethodDependency method); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java b/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java index 7ef479b9e..c5b766b93 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java @@ -90,6 +90,9 @@ class BreakToContinueReplacer implements StatementVisitor { @Override public void visit(ContinueStatement statement) { + if (statement.getTarget() == replacedBreak) { + statement.setTarget(replacement); + } } @Override 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 176309e86..ad8a97633 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -1225,7 +1225,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { if (expr.getType() instanceof ValueType.Object) { String clsName = ((ValueType.Object)expr.getType()).getClassName(); ClassHolder cls = classSource.get(clsName); - if (!cls.getModifiers().contains(ElementModifier.INTERFACE)) { + if (cls != null && !cls.getModifiers().contains(ElementModifier.INTERFACE)) { writer.append("("); expr.getExpr().acceptVisitor(this); writer.append(" instanceof ").appendClass(clsName).append(")"); diff --git a/teavm-html4j/pom.xml b/teavm-html4j/pom.xml index 6bd1e7bd0..6cf1a6a79 100644 --- a/teavm-html4j/pom.xml +++ b/teavm-html4j/pom.xml @@ -45,6 +45,12 @@ 0.8-SNAPSHOT true + + org.netbeans.html + ko4j + 0.8-SNAPSHOT + true + junit junit diff --git a/teavm-html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java b/teavm-html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java new file mode 100644 index 000000000..38d342969 --- /dev/null +++ b/teavm-html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java @@ -0,0 +1,166 @@ +/** + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.teavm.html4j.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import net.java.html.BrwsrCtx; +import net.java.html.js.JavaScriptBody; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.context.spi.Contexts; +import org.apidesign.html.json.tck.KnockoutTCK; +import org.testng.Assert; + +/** + * + * @author Jaroslav Tulach + */ +public final class KnockoutFXTest extends KnockoutTCK { + private static Class browserClass; + private static Fn.Presenter browserContext; + + public KnockoutFXTest() { + } + + static synchronized ClassLoader getClassLoader() throws InterruptedException { + while (browserClass == null) { + KnockoutFXTest.class.wait(); + } + return browserClass.getClassLoader(); + } + + public static synchronized void initialized(Class browserCls) throws Exception { + browserClass = browserCls; + browserContext = Fn.activePresenter(); + KnockoutFXTest.class.notifyAll(); + } + + public static void initialized() throws Exception { + Assert.assertSame( + KnockoutFXTest.class.getClassLoader(), + ClassLoader.getSystemClassLoader(), + "No special classloaders" + ); + KnockoutFXTest.initialized(KnockoutFXTest.class); + browserContext = Fn.activePresenter(); + } + + @Override + public BrwsrCtx createContext() { + Contexts.Builder cb = Contexts.newBuilder(); + return cb.build(); + } + + @Override + public Object createJSON(Map values) { + Object json = createJSON(); + for (Map.Entry entry : values.entrySet()) { + setProperty(json, entry.getKey(), entry.getValue()); + } + return json; + } + + @JavaScriptBody(args = {}, body = "return new Object();") + private static native Object createJSON(); + @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;") + private static native void setProperty(Object json, String key, Object value); + + @Override + @JavaScriptBody(args = { "s", "args" }, body = "" + + "var f = new Function(s); " + + "return f.apply(null, args);" + ) + public native Object executeScript(String script, Object[] arguments); + + @JavaScriptBody(args = { }, body = + "var h;" + + "if (!!window && !!window.location && !!window.location.href)\n" + + " h = window.location.href;\n" + + "else " + + " h = null;" + + "return h;\n" + ) + private static native String findBaseURL(); + + @Override + public URI prepareURL(String content, String mimeType, String[] parameters) { + try { + final URL baseURL = new URL(findBaseURL()); + StringBuilder sb = new StringBuilder(); + sb.append("/dynamic?mimeType=").append(mimeType); + for (int i = 0; i < parameters.length; i++) { + sb.append("¶m" + i).append("=").append(parameters[i]); + } + String mangle = content.replace("\n", "%0a") + .replace("\"", "\\\"").replace(" ", "%20"); + sb.append("&content=").append(mangle); + + URL query = new URL(baseURL, sb.toString()); + URLConnection c = query.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); + URI connectTo = new URI(br.readLine()); + return connectTo; + } catch (IOException ex) { + throw new IllegalStateException(ex); + } catch (URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public boolean canFailWebSocketTest() { + try { + Class.forName("java.util.function.Function"); + return false; + } catch (ClassNotFoundException ex) { + // running on JDK7, FX WebView WebSocket impl does not work + return true; + } + } +} diff --git a/teavm-html4j/src/test/resources/META-INF/services/org.apidesign.html.json.tck.KnockoutTCK b/teavm-html4j/src/test/resources/META-INF/services/org.apidesign.html.json.tck.KnockoutTCK new file mode 100644 index 000000000..9bce235af --- /dev/null +++ b/teavm-html4j/src/test/resources/META-INF/services/org.apidesign.html.json.tck.KnockoutTCK @@ -0,0 +1 @@ +org.teavm.html4j.test.KnockoutFXTest \ No newline at end of file