From cff91e03ffa1b396cfcdfee1ff99e269cef98b54 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 1 Feb 2015 20:40:56 +0400 Subject: [PATCH 01/12] Add resolving of JSR opcode --- .../src/main/java/org/teavm/parsing/Parser.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/parsing/Parser.java b/teavm-core/src/main/java/org/teavm/parsing/Parser.java index 5baa8abaf..d48165e5b 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/Parser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/Parser.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.commons.JSRInlinerAdapter; import org.objectweb.asm.tree.*; import org.teavm.model.*; import org.teavm.optimization.UnreachableBasicBlockEliminator; @@ -32,6 +33,12 @@ public final class Parser { } public static MethodHolder parseMethod(MethodNode node, String className, String fileName) { + MethodNode nodeWithoutJsr = new MethodNode(Opcodes.ASM5, node.access, node.name, node.desc, node.signature, + node.exceptions.toArray(new String[0])); + JSRInlinerAdapter adapter = new JSRInlinerAdapter(nodeWithoutJsr, node.access, node.name, node.desc, + node.signature, node.exceptions.toArray(new String[0])); + node.accept(adapter); + node = nodeWithoutJsr; ValueType[] signature = MethodDescriptor.parseSignature(node.desc); MethodHolder method = new MethodHolder(node.name, signature); parseModifiers(node.access, method); @@ -59,8 +66,8 @@ public final class Parser { cls.setParent(null); } if (node.interfaces != null) { - for (Object obj : node.interfaces) { - cls.getInterfaces().add(((String)obj).replace('/', '.')); + for (String iface : node.interfaces) { + cls.getInterfaces().add(iface.replace('/', '.')); } } for (Object obj : node.fields) { @@ -68,8 +75,7 @@ public final class Parser { cls.addField(parseField(fieldNode)); } String fullFileName = node.name.substring(0, node.name.lastIndexOf('/') + 1) + node.sourceFile; - for (Object obj : node.methods) { - MethodNode methodNode = (MethodNode)obj; + for (MethodNode methodNode : node.methods) { cls.addMethod(parseMethod(methodNode, node.name, fullFileName)); } if (node.outerClass != null) { From 73a1e95aaeb6cc5f90d3a8cc66cd41d2a294ae49 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Mon, 2 Feb 2015 08:24:57 -0800 Subject: [PATCH 02/12] Added some missing classes to be able to compile codenameone. --- .../teavm/classlib/java/io/TDataOutput.java | 113 ++++++ .../classlib/java/io/TDataOutputStream.java | 371 ++++++++++++++++++ .../classlib/java/io/TOutputStreamWriter.java | 92 +++++ .../org/teavm/classlib/java/io/TWriter.java | 108 +++++ 4 files changed, 684 insertions(+) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutput.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutputStream.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/io/TOutputStreamWriter.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/io/TWriter.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutput.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutput.java new file mode 100644 index 000000000..70c5f097e --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutput.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ + +package org.teavm.classlib.java.io; +import org.teavm.classlib.java.lang.*; +/** + * The DataOutput interface provides for converting data from any of the Java primitive types to a series of bytes and writing these bytes to a binary stream. There is also a facility for converting a String into Java modified UTF-8 format and writing the resulting series of bytes. + * For all the methods in this interface that write bytes, it is generally true that if a byte cannot be written for any reason, an IOException is thrown. + * Since: JDK1.0, CLDC 1.0 See Also:DataInput, DataOutputStream + */ +public interface TDataOutput{ + /** + * Writes to the output stream all the bytes in array b. If b is null, a NullPointerException is thrown. If b.length is zero, then no bytes are written. Otherwise, the byte b[0] is written first, then b[1], and so on; the last byte written is b[b.length-1]. + */ + public abstract void write(byte[] b) throws TIOException; + + /** + * Writes len bytes from array b, in order, to the output stream. If b is null, a NullPointerException is thrown. If off is negative, or len is negative, or off+len is greater than the length of the array b, then an IndexOutOfBoundsException is thrown. If len is zero, then no bytes are written. Otherwise, the byte b[off] is written first, then b[off+1], and so on; the last byte written is b[off+len-1]. + */ + public abstract void write(byte[] b, int off, int len) throws TIOException; + + /** + * Writes to the output stream the eight low-order bits of the argument b. The 24 high-order bits of b are ignored. + */ + public abstract void write(int b) throws TIOException; + + /** + * Writes a boolean value to this output stream. If the argument v is true, the value (byte)1 is written; if v is false, the value (byte)0 is written. The byte written by this method may be read by the readBoolean method of interface DataInput, which will then return a boolean equal to v. + */ + public abstract void writeBoolean(boolean v) throws TIOException; + + /** + * Writes to the output stream the eight low- order bits of the argument v. The 24 high-order bits of v are ignored. (This means that writeByte does exactly the same thing as write for an integer argument.) The byte written by this method may be read by the readByte method of interface DataInput, which will then return a byte equal to (byte)v. + */ + public abstract void writeByte(int v) throws TIOException; + + /** + * Writes a char value, which is comprised of two bytes, to the output stream. The byte values to be written, in the order shown, are: + * (byte)(0xff (v 8)) (byte)(0xff v) + * The bytes written by this method may be read by the readChar method of interface DataInput, which will then return a char equal to (char)v. + */ + public abstract void writeChar(int v) throws TIOException; + + /** + * Writes every character in the string s, to the output stream, in order, two bytes per character. If s is null, a NullPointerException is thrown. If s.length is zero, then no characters are written. Otherwise, the character s[0] is written first, then s[1], and so on; the last character written is s[s.length-1]. For each character, two bytes are actually written, high-order byte first, in exactly the manner of the writeChar method. + */ + public abstract void writeChars(TString s) throws java.io.IOException; + + /** + * Writes a double value, which is comprised of eight bytes, to the output stream. It does this as if it first converts this double value to a long in exactly the manner of the Double.doubleToLongBits method and then writes the long value in exactly the manner of the writeLong method. The bytes written by this method may be read by the readDouble method of interface DataInput, which will then return a double equal to v. + */ + public abstract void writeDouble(double v) throws TIOException; + + /** + * Writes a float value, which is comprised of four bytes, to the output stream. It does this as if it first converts this float value to an int in exactly the manner of the Float.floatToIntBits method and then writes the int value in exactly the manner of the writeInt method. The bytes written by this method may be read by the readFloat method of interface DataInput, which will then return a float equal to v. + */ + public abstract void writeFloat(float v) throws TIOException; + + /** + * Writes an int value, which is comprised of four bytes, to the output stream. The byte values to be written, in the order shown, are: + * (byte)(0xff (v 24)) (byte)(0xff (v 16)) (byte)(0xff (v 8)) (byte)(0xff v) + * The bytes written by this method may be read by the readInt method of interface DataInput, which will then return an int equal to v. + */ + public abstract void writeInt(int v) throws TIOException; + + /** + * Writes an long value, which is comprised of four bytes, to the output stream. The byte values to be written, in the order shown, are: + * (byte)(0xff (v 56)) (byte)(0xff (v 48)) (byte)(0xff (v 40)) (byte)(0xff (v 32)) (byte)(0xff (v 24)) (byte)(0xff (v 16)) (byte)(0xff (v 8)) (byte)(0xff v) + * The bytes written by this method may be read by the readLong method of interface DataInput, which will then return a long equal to v. + */ + public abstract void writeLong(long v) throws TIOException; + + /** + * Writes two bytes to the output stream to represent the value of the argument. The byte values to be written, in the order shown, are: + * (byte)(0xff (v 8)) (byte)(0xff v) + * The bytes written by this method may be read by the readShort method of interface DataInput, which will then return a short equal to (short)v. + */ + public abstract void writeShort(int v) throws TIOException; + + /** + * Writes two bytes of length information to the output stream, followed by the Java modified UTF representation of every character in the string s. If s is null, a NullPointerException is thrown. Each character in the string s is converted to a group of one, two, or three bytes, depending on the value of the character. + * If a character c is in the range u0001 through u007f, it is represented by one byte: + * (byte)c + * If a character c is u0000 or is in the range u0080 through u07ff, then it is represented by two bytes, to be written in the order shown: + * (byte)(0xc0 | (0x1f (c 6))) (byte)(0x80 | (0x3f c)) + * If a character c is in the range u0800 through uffff, then it is represented by three bytes, to be written in the order shown: + * (byte)(0xe0 | (0x0f (c 12))) (byte)(0x80 | (0x3f (c 6))) (byte)(0x80 | (0x3f c)) + * First, the total number of bytes needed to represent all the characters of s is calculated. If this number is larger than 65535, then a UTFDataFormatError is thrown. Otherwise, this length is written to the output stream in exactly the manner of the writeShort method; after this, the one-, two-, or three-byte representation of each character in the string s is written. + * The bytes written by this method may be read by the readUTF method of interface DataInput, which will then return a String equal to s. + */ + public abstract void writeUTF(TString s) throws TIOException; + +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutputStream.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutputStream.java new file mode 100644 index 000000000..7064857ac --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TDataOutputStream.java @@ -0,0 +1,371 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.io; +import org.teavm.classlib.java.lang.*; +/** + * A data output stream lets an application write primitive Java data types to an output stream in a portable way. An application can then use a data input stream to read the data back in. + * Since: JDK1.0, CLDC 1.0 See Also:DataInputStream + */ +public class TDataOutputStream extends TFilterOutputStream implements TDataOutput{ + /** + * The number of bytes written out so far. + */ + protected int written; + byte buff[]; + + /** + * Constructs a new {@code DataOutputStream} on the {@code OutputStream} + * {@code out}. Note that data written by this stream is not in a human + * readable form but can be reconstructed by using a {@link DataInputStream} + * on the resulting output. + * + * @param out + * the target stream for writing. + */ + public TDataOutputStream(TOutputStream out) { + super(out); + buff = new byte[8]; + } + + /** + * Flushes this stream to ensure all pending data is sent out to the target + * stream. This implementation then also flushes the target stream. + * + * @throws IOException + * if an error occurs attempting to flush this stream. + */ + @Override + public void flush() throws TIOException { + super.flush(); + } + + /** + * Returns the total number of bytes written to the target stream so far. + * + * @return the number of bytes written to the target stream. + */ + public final int size() { + if (written < 0) { + written = TInteger.MAX_VALUE; + } + return written; + } + + /** + * Writes {@code count} bytes from the byte array {@code buffer} starting at + * {@code offset} to the target stream. + * + * @param buffer + * the buffer to write to the target stream. + * @param offset + * the index of the first byte in {@code buffer} to write. + * @param count + * the number of bytes from the {@code buffer} to write. + * @throws IOException + * if an error occurs while writing to the target stream. + * @throws NullPointerException + * if {@code buffer} is {@code null}. + * @see DataInputStream#readFully(byte[]) + * @see DataInputStream#readFully(byte[], int, int) + */ + @Override + public void write(byte buffer[], int offset, int count) throws TIOException { + if (buffer == null) { + throw new TNullPointerException(); + } + out.write(buffer, offset, count); + written += count; + } + + /** + * Writes a byte to the target stream. Only the least significant byte of + * the integer {@code oneByte} is written. + * + * @param oneByte + * the byte to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readByte() + */ + @Override + public void write(int oneByte) throws TIOException { + out.write(oneByte); + written++; + } + + /** + * Writes a boolean to the target stream. + * + * @param val + * the boolean value to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readBoolean() + */ + public final void writeBoolean(boolean val) throws TIOException { + out.write(val ? 1 : 0); + written++; + } + + /** + * Writes an 8-bit byte to the target stream. Only the least significant + * byte of the integer {@code val} is written. + * + * @param val + * the byte value to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readByte() + * @see DataInputStream#readUnsignedByte() + */ + public final void writeByte(int val) throws TIOException { + out.write(val); + written++; + } + + /** + * Writes the low order bytes from a string to the target stream. + * + * @param str + * the string containing the bytes to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readFully(byte[]) + * @see DataInputStream#readFully(byte[],int,int) + */ + public final void writeBytes(TString str) throws TIOException { + if (str.length() == 0) { + return; + } + byte bytes[] = new byte[str.length()]; + for (int index = 0; index < str.length(); index++) { + bytes[index] = (byte) str.charAt(index); + } + out.write(bytes); + written += bytes.length; + } + + /** + * Writes a 16-bit character to the target stream. Only the two lower bytes + * of the integer {@code val} are written, with the higher one written + * first. This corresponds to the Unicode value of {@code val}. + * + * @param val + * the character to write to the target stream + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readChar() + */ + public final void writeChar(int val) throws TIOException { + buff[0] = (byte) (val >> 8); + buff[1] = (byte) val; + out.write(buff, 0, 2); + written += 2; + } + + /** + * Writes the 16-bit characters contained in {@code str} to the target + * stream. + * + * @param str + * the string that contains the characters to write to this + * stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readChar() + */ + public final void writeChars(TString str) throws TIOException { + byte newBytes[] = new byte[str.length() * 2]; + for (int index = 0; index < str.length(); index++) { + int newIndex = index == 0 ? index : index * 2; + newBytes[newIndex] = (byte) (str.charAt(index) >> 8); + newBytes[newIndex + 1] = (byte) str.charAt(index); + } + out.write(newBytes); + written += newBytes.length; + } + + /** + * Writes a 64-bit double to the target stream. The resulting output is the + * eight bytes resulting from calling Double.doubleToLongBits(). + * + * @param val + * the double to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readDouble() + */ + public final void writeDouble(double val) throws TIOException { + writeLong(TDouble.doubleToLongBits(val)); + } + + /** + * Writes a 32-bit float to the target stream. The resulting output is the + * four bytes resulting from calling Float.floatToIntBits(). + * + * @param val + * the float to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readFloat() + */ + public final void writeFloat(float val) throws TIOException { + writeInt(TFloat.floatToIntBits(val)); + } + + /** + * Writes a 32-bit int to the target stream. The resulting output is the + * four bytes, highest order first, of {@code val}. + * + * @param val + * the int to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readInt() + */ + public final void writeInt(int val) throws TIOException { + buff[0] = (byte) (val >> 24); + buff[1] = (byte) (val >> 16); + buff[2] = (byte) (val >> 8); + buff[3] = (byte) val; + out.write(buff, 0, 4); + written += 4; + } + + /** + * Writes a 64-bit long to the target stream. The resulting output is the + * eight bytes, highest order first, of {@code val}. + * + * @param val + * the long to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readLong() + */ + public final void writeLong(long val) throws TIOException { + buff[0] = (byte) (val >> 56); + buff[1] = (byte) (val >> 48); + buff[2] = (byte) (val >> 40); + buff[3] = (byte) (val >> 32); + buff[4] = (byte) (val >> 24); + buff[5] = (byte) (val >> 16); + buff[6] = (byte) (val >> 8); + buff[7] = (byte) val; + out.write(buff, 0, 8); + written += 8; + } + + int writeLongToBuffer(long val, + byte[] buffer, int offset) throws TIOException { + buffer[offset++] = (byte) (val >> 56); + buffer[offset++] = (byte) (val >> 48); + buffer[offset++] = (byte) (val >> 40); + buffer[offset++] = (byte) (val >> 32); + buffer[offset++] = (byte) (val >> 24); + buffer[offset++] = (byte) (val >> 16); + buffer[offset++] = (byte) (val >> 8); + buffer[offset++] = (byte) val; + return offset; + } + + /** + * Writes the specified 16-bit short to the target stream. Only the lower + * two bytes of the integer {@code val} are written, with the higher one + * written first. + * + * @param val + * the short to write to the target stream. + * @throws IOException + * if an error occurs while writing to the target stream. + * @see DataInputStream#readShort() + * @see DataInputStream#readUnsignedShort() + */ + public final void writeShort(int val) throws TIOException { + buff[0] = (byte) (val >> 8); + buff[1] = (byte) val; + out.write(buff, 0, 2); + written += 2; + } + + int writeShortToBuffer(int val, + byte[] buffer, int offset) throws TIOException { + buffer[offset++] = (byte) (val >> 8); + buffer[offset++] = (byte) val; + return offset; + } + + /** + * Writes the specified encoded in {@link DataInput modified UTF-8} to this + * stream. + * + * @param str + * the string to write to the target stream encoded in + * {@link DataInput modified UTF-8}. + * @throws IOException + * if an error occurs while writing to the target stream. + * @throws UTFDataFormatException + * if the encoded string is longer than 65535 bytes. + * @see DataInputStream#readUTF() + */ + public final void writeUTF(TString str) throws TIOException { + long utfCount = countUTFBytes(str); + if (utfCount > 65535) { + throw new TIOException(TString.wrap("UTF Error")); + } + byte[] buffer = new byte[(int)utfCount + 2]; + int offset = 0; + offset = writeShortToBuffer((int) utfCount, buffer, offset); + offset = writeUTFBytesToBuffer(str, (int) utfCount, buffer, offset); + write(buffer, 0, offset); + } + + long countUTFBytes(TString str) { + int utfCount = 0, length = str.length(); + for (int i = 0; i < length; i++) { + int charValue = str.charAt(i); + if (charValue > 0 && charValue <= 127) { + utfCount++; + } else if (charValue <= 2047) { + utfCount += 2; + } else { + utfCount += 3; + } + } + return utfCount; + } + + int writeUTFBytesToBuffer(TString str, long count, + byte[] buffer, int offset) throws TIOException { + int length = str.length(); + for (int i = 0; i < length; i++) { + int charValue = str.charAt(i); + if (charValue > 0 && charValue <= 127) { + buffer[offset++] = (byte) charValue; + } else if (charValue <= 2047) { + buffer[offset++] = (byte) (0xc0 | (0x1f & (charValue >> 6))); + buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); + } else { + buffer[offset++] = (byte) (0xe0 | (0x0f & (charValue >> 12))); + buffer[offset++] = (byte) (0x80 | (0x3f & (charValue >> 6))); + buffer[offset++] = (byte) (0x80 | (0x3f & charValue)); + } + } + return offset; + } + +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TOutputStreamWriter.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TOutputStreamWriter.java new file mode 100644 index 000000000..6a7de47e3 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TOutputStreamWriter.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ + +package org.teavm.classlib.java.io; +import org.teavm.classlib.java.lang.*; +/** + * An OutputStreamWriter is a bridge from character streams to byte streams: Characters written to it are translated into bytes. The encoding that it uses may be specified by name, or the platform's default encoding may be accepted. + * Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered. + * Since: CLDC 1.0 See Also:Writer, UnsupportedEncodingException + */ +public class TOutputStreamWriter extends TWriter{ + private TOutputStream os; + private TString enc; + + /** + * Create an OutputStreamWriter that uses the default character encoding. + * os - An OutputStream + */ + public TOutputStreamWriter(TOutputStream os){ + this.os = os; + enc = TString.wrap("UTF-8"); + } + + /** + * Create an OutputStreamWriter that uses the named character encoding. + * os - An OutputStreamenc - The name of a supported + * - If the named encoding is not supported + */ + public TOutputStreamWriter(TOutputStream os, TString enc) throws TUnsupportedEncodingException{ + this.os = os; + this.enc = enc; + } + + /** + * Close the stream. + */ + public void close() throws TIOException{ + os.close(); + } + + /** + * Flush the stream. + */ + public void flush() throws TIOException{ + os.flush(); + } + + /** + * Write a portion of an array of characters. + */ + public void write(char[] cbuf, int off, int len) throws TIOException{ + write(new TString(cbuf, off, len)); + } + + /** + * Write a single character. + */ + public void write(int c) throws TIOException{ + write(new TString(new char[] {(char)c})); + } + + /** + * Write a portion of a string. + */ + public void write(TString str, int off, int len) throws TIOException{ + if(off > 0 || len != str.length()) { + str = str.substring(off, len); + } + os.write(str.getBytes(enc)); + } + +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TWriter.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TWriter.java new file mode 100644 index 000000000..b20a35726 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/io/TWriter.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ + +package org.teavm.classlib.java.io; + +import org.teavm.classlib.java.lang.*; +/** + * Abstract class for writing to character streams. The only methods that a subclass must implement are write(char[], int, int), flush(), and close(). Most subclasses, however, will override some of the methods defined here in order to provide higher efficiency, additional functionality, or both. + * Since: JDK1.1, CLDC 1.0 See Also:OutputStreamWriter, Reader + */ +public abstract class TWriter extends TObject{ + /** + * The object used to synchronize operations on this stream. For efficiency, a character-stream object may use an object other than itself to protect critical sections. A subclass should therefore use the object in this field rather than this or a synchronized method. + */ + protected TObject lock; + + /** + * Create a new character-stream writer whose critical sections will synchronize on the writer itself. + */ + protected TWriter(){ + lock = this; + } + + /** + * Create a new character-stream writer whose critical sections will synchronize on the given object. + * lock - Object to synchronize on. + */ + protected TWriter(TObject lock){ + this.lock = lock; + } + + /** + * Close the stream, flushing it first. Once a stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously-closed stream, however, has no effect. + */ + public abstract void close() throws TIOException; + + /** + * Flush the stream. If the stream has saved any characters from the various write() methods in a buffer, write them immediately to their intended destination. Then, if that destination is another character or byte stream, flush it. Thus one flush() invocation will flush all the buffers in a chain of Writers and OutputStreams. + */ + public abstract void flush() throws TIOException; + + /** + * Write an array of characters. + */ + public void write(char[] cbuf) throws TIOException{ + write(cbuf, 0, cbuf.length); + } + + /** + * Write a portion of an array of characters. + */ + public abstract void write(char[] cbuf, int off, int len) throws TIOException; + + /** + * Write a single character. The character to be written is contained in the 16 low-order bits of the given integer value; the 16 high-order bits are ignored. + * Subclasses that intend to support efficient single-character output should override this method. + */ + public void write(int c) throws TIOException{ + synchronized (lock) { + char oneCharArray[] = new char[1]; + oneCharArray[0] = (char) c; + write(oneCharArray); + } + } + + /** + * Write a string. + */ + public void write(TString str) throws TIOException{ + write(str, 0, str.length()); + } + + /** + * Write a portion of a string. + */ + public void write(TString str, int off, int len) throws TIOException{ + if (len < 0) { + throw new StringIndexOutOfBoundsException(); + } + char buf[] = new char[len]; + str.getChars(off, off + len, buf, 0); + + synchronized (lock) { + write(buf, 0, buf.length); + } + } + +} From 72cb3973d6f1781c84940d75a56c10b316629867 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Mon, 2 Feb 2015 12:45:32 -0800 Subject: [PATCH 03/12] Added some implementations for Object.wait(), Object.notify(), Object.notifyAll(), and Thread.start() to try to emulate the behaviour of multithreaded environments. --- .../java/lang/ObjectNativeGenerator.java | 75 +++++++++++++++++++ .../org/teavm/classlib/java/lang/TObject.java | 35 ++++++--- .../org/teavm/classlib/java/lang/TThread.java | 6 ++ .../java/lang/ThreadNativeGenerator.java | 29 ++++++- .../org/teavm/samples/async/AsyncProgram.java | 40 ++++++++++ 5 files changed, 173 insertions(+), 12 deletions(-) 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 3176e3319..77212fa66 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 @@ -43,6 +43,15 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu case "clone": generateClone(context, writer); break; + case "wait": + generateWait(context, writer); + break; + case "notify": + generateNotify(context, writer); + break; + case "notifyAll": + generateNotifyAll(context, writer); + break; } } @@ -70,6 +79,10 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu case "wrap": method.getVariable(1).connect(method.getResult()); break; + //case "wait": + // method.getVariable(0).connect(method.getResult()); + // break; + } } @@ -107,4 +120,66 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu private void generateWrap(InjectorContext context) throws IOException { context.writeExpr(context.getArgument(0)); } + + private void generateWait(GeneratorContext context, SourceWriter writer) throws IOException { + String pname = context.getParameterName(1); + String obj = context.getParameterName(0); + writer.append("(function(){").indent().softNewLine(); + writer.append("var completed = false;").softNewLine(); + writer.append("var retCallback = ").append(context.getCompleteContinuation()).append(";").softNewLine(); + writer.append("console.log(retCallback);").softNewLine(); + writer.append("var callback = function(){").indent().softNewLine(); + writer.append("if (completed){return;} completed=true;").softNewLine(); + writer.append("retCallback();").softNewLine(); + writer.outdent().append("};").softNewLine(); + writer.append("if (").append(pname).append(">0){").indent().softNewLine(); + writer.append("setTimeout(callback, ").append(pname).append(");").softNewLine(); + writer.outdent().append("}").softNewLine(); + addNotifyListener(context, writer, "callback"); + writer.outdent().append("})();").softNewLine(); + + + + } + + private void generateNotify(GeneratorContext context, SourceWriter writer) throws IOException { + sendNotify(context, writer); + } + + private void generateNotifyAll(GeneratorContext context, SourceWriter writer) throws IOException { + sendNotifyAll(context, writer); + } + + private String getNotifyListeners(GeneratorContext context){ + return context.getParameterName(0)+".__notifyListeners"; + } + + private void addNotifyListener(GeneratorContext context, SourceWriter writer, String callback) throws IOException { + String lArr = getNotifyListeners(context); + writer.append(lArr).append("=").append(lArr).append("||[];").softNewLine(); + writer.append(lArr).append(".push(").append(callback).append(");").softNewLine(); + } + + private void sendNotify(GeneratorContext context, SourceWriter writer) throws IOException { + String lArr = getNotifyListeners(context); + writer.append("setTimeout(function(){").indent().softNewLine(); + writer.append("if (!").append(lArr).append(" || ").append(lArr).append(".length===0){return;}").softNewLine(); + writer.append("var m = ").append(lArr).append(".shift();").softNewLine(); + writer.append("console.log('Notify callback : '+m);").softNewLine(); + writer.append("m.apply(null);").softNewLine(); + writer.outdent().append("}, 0);").softNewLine(); + } + + private void sendNotifyAll(GeneratorContext context, SourceWriter writer) throws IOException { + String obj = context.getParameterName(0); + String lArr = getNotifyListeners(context); + writer.append("setTimeout(function(){").indent().softNewLine(); + writer.append("if (!").append(lArr).append("){return;}").softNewLine(); + writer.append("while (").append(lArr).append(".length>0){").indent().softNewLine(); + writer.append(lArr).append(".shift().call(null);").softNewLine(); + writer.outdent().append("}"); + writer.outdent().append("}, 0);").softNewLine(); + + } + } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index 6759d3cc7..5de13b11f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -15,11 +15,13 @@ */ package org.teavm.classlib.java.lang; + import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.GeneratedBy; import org.teavm.javascript.ni.InjectedBy; import org.teavm.javascript.ni.Rename; import org.teavm.javascript.ni.Superclass; +import org.teavm.runtime.Async; /** * @@ -62,26 +64,37 @@ public class TObject { @Override protected native Object clone() throws TCloneNotSupportedException; + @GeneratedBy(ObjectNativeGenerator.class) @Rename("notify") - public final void notify0() { - } + public native final void notify0(); + + @GeneratedBy(ObjectNativeGenerator.class) @Rename("notifyAll") - public final void notifyAll0() { - } - - @SuppressWarnings("unused") + public native final void notifyAll0(); + + @Rename("wait") - public final void wait0(long timeout) throws TInterruptedException { + public final void wait0(long timeout) throws TInterruptedException{ + try { + wait(timeout, 0); + } catch ( InterruptedException ex){ + throw new TInterruptedException(); + } } - - @SuppressWarnings("unused") + + @Async + @GeneratedBy(ObjectNativeGenerator.class) @Rename("wait") - public final void wait0(long timeout, int nanos) throws TInterruptedException { - } + public native final void wait0(long timeout, int nanos) throws TInterruptedException; @Rename("wait") public final void wait0() throws TInterruptedException { + try { + wait(0l); + } catch (InterruptedException ex) { + throw new TInterruptedException(); + } } @Override diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 12ff437f9..926c03d5a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -15,6 +15,7 @@ */ package org.teavm.classlib.java.lang; +import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.GeneratedBy; import org.teavm.runtime.Async; @@ -44,6 +45,11 @@ public class TThread extends TObject implements TRunnable { this.target = target; } + @PluggableDependency(ThreadNativeGenerator.class) + @GeneratedBy(ThreadNativeGenerator.class) + public native void start(); + + @Override public void run() { if (target != null) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index 2560d7931..ff1ab7d8b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -17,24 +17,45 @@ package org.teavm.classlib.java.lang; 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.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.CallLocation; import org.teavm.model.MethodReference; /** * * @author Alexey Andreev */ -public class ThreadNativeGenerator implements Generator { +public class ThreadNativeGenerator implements Generator, DependencyPlugin { + + private static final MethodReference runRef = new MethodReference(Thread.class, + "run", void.class); + @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { if (methodRef.getName().equals("sleep")) { generateSleep(context, writer); } else if (methodRef.getName().equals("yield")) { generateYield(context, writer); + } else if ( methodRef.getName().equals("start")){ + generateStart(context, writer); } } + + + public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) { + switch (method.getReference().getName()) { + case "start": { + MethodDependency performMethod = agent.linkMethod(runRef, null); + performMethod.use(); + break; + } + } + } private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { writer.append("setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("();").softNewLine(); @@ -46,4 +67,10 @@ public class ThreadNativeGenerator implements Generator { writer.append(context.getCompleteContinuation()).append("();").softNewLine(); writer.outdent().append("},").ws().append("0);").softNewLine(); } + + private void generateStart(GeneratorContext context, SourceWriter writer) throws IOException { + String obj = context.getParameterName(0); + + writer.append("setTimeout(function() {").append(obj).append(".").appendMethod(runRef).append("();},0);").softNewLine(); + } } diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index fca37cc4a..27eda6f2f 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -15,6 +15,7 @@ */ package org.teavm.samples.async; + /** * * @author Alexey Andreev @@ -27,8 +28,44 @@ public final class AsyncProgram { withoutAsync(); System.out.println(); withAsync(); + + System.out.println(); + + + + final Object lock = new Object(); + + Thread t = new Thread(new Runnable(){ + + @Override + public void run() { + try { + doRun(lock); + } catch (InterruptedException ex){ + System.out.println(ex.getMessage()); + } + } + + }); + t.start(); + + System.out.println("Now trying wait..."); + + lock.wait(20000); + System.out.println("Finished waiting"); + } + private static void doRun(Object lock) throws InterruptedException { + System.out.println("Executing timer task"); + Thread.sleep(2000); + System.out.println("Calling lock.notify()"); + lock.notify(); + System.out.println("Finished calling lock.notify()"); + Thread.sleep(5000); + System.out.println("Finished another 5 second sleep"); + } + private static void withoutAsync() { System.out.println("Start sync"); for (int i = 0; i < 20; ++i) { @@ -54,6 +91,9 @@ public final class AsyncProgram { Thread.sleep(1000); } } + System.out.println("2nd Thread.sleep in same method"); + Thread.sleep(1000); + System.out.println("Complete async"); } } From b37c92b02d8562cce97fb42c4961c0b035dd6e14 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Tue, 3 Feb 2015 09:07:46 -0800 Subject: [PATCH 04/12] Merged Alexey's patch for Thread.start --- .../org/teavm/classlib/java/lang/TThread.java | 7 ++++-- .../java/lang/ThreadNativeGenerator.java | 22 ++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 926c03d5a..8b7715d38 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -48,8 +48,11 @@ public class TThread extends TObject implements TRunnable { @PluggableDependency(ThreadNativeGenerator.class) @GeneratedBy(ThreadNativeGenerator.class) public native void start(); - - + + private static void launch(TThread thread) { + thread.run(); + } + @Override public void run() { if (target != null) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index ff1ab7d8b..0537343d6 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -30,10 +30,10 @@ import org.teavm.model.MethodReference; * @author Alexey Andreev */ public class ThreadNativeGenerator implements Generator, DependencyPlugin { - - private static final MethodReference runRef = new MethodReference(Thread.class, - "run", void.class); - + + private static final MethodReference launchRef = new MethodReference(Thread.class, + "launch", Thread.class, void.class); + @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { if (methodRef.getName().equals("sleep")) { @@ -45,17 +45,18 @@ public class ThreadNativeGenerator implements Generator, DependencyPlugin { } } - - + @Override public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) { switch (method.getReference().getName()) { case "start": { - MethodDependency performMethod = agent.linkMethod(runRef, null); + MethodDependency performMethod = agent.linkMethod(launchRef, null); + method.getVariable(0).connect(performMethod.getVariable(1)); performMethod.use(); break; } } } + private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { writer.append("setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("();").softNewLine(); @@ -67,10 +68,11 @@ public class ThreadNativeGenerator implements Generator, DependencyPlugin { writer.append(context.getCompleteContinuation()).append("();").softNewLine(); writer.outdent().append("},").ws().append("0);").softNewLine(); } - + private void generateStart(GeneratorContext context, SourceWriter writer) throws IOException { String obj = context.getParameterName(0); - - writer.append("setTimeout(function() {").append(obj).append(".").appendMethod(runRef).append("();},0);").softNewLine(); + + writer.append("setTimeout(function() { $rt_rootInvocationAdapter(").appendMethodBody(launchRef).append(")(") + .append(obj).append(");},0);").softNewLine(); } } From e6e52d1be5f4a4855c60500b57f5c7566bb37e5b Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Wed, 4 Feb 2015 13:55:02 -0800 Subject: [PATCH 05/12] Added preliminary support for keeping track of which thread is currently running. This implementation simply overrides setTimeout() to keep track of the thread that is running. It restores it to the main thread after a thread finishes running. May need to override other async methods e.g. XMLHTTPRequest, but not sure yet. This change may be sufficient if all of our async methods meant to emulate threads use the setTimeout construction. --- .../org/teavm/classlib/java/lang/TThread.java | 35 +++++++++++++++---- .../java/lang/ThreadNativeGenerator.java | 1 - .../src/main/java/org/teavm/vm/TeaVM.java | 27 ++++++++++++++ .../org/teavm/samples/async/AsyncProgram.java | 8 +++-- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 8b7715d38..77d8c6c1e 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -24,7 +24,11 @@ import org.teavm.runtime.Async; * @author Alexey Andreev */ public class TThread extends TObject implements TRunnable { - private static TThread currentThread = new TThread(TString.wrap("main")); + private static TThread mainThread = new TThread(TString.wrap("main")); + private static TThread currentThread = mainThread; + private static long nextId = 1; + private static int activeCount = 1; + private long id; private TString name; private TRunnable target; @@ -33,16 +37,17 @@ public class TThread extends TObject implements TRunnable { } public TThread(TString name) { - this(name, null); + this(null, name); } public TThread(TRunnable target) { - this(null, target); + this(target, null ); } - public TThread(TString name, TRunnable target) { + public TThread(TRunnable target, TString name ) { this.name = name; this.target = target; + id=nextId++; } @PluggableDependency(ThreadNativeGenerator.class) @@ -50,7 +55,23 @@ public class TThread extends TObject implements TRunnable { public native void start(); private static void launch(TThread thread) { - thread.run(); + try { + activeCount++; + setCurrentThread(thread); + thread.run(); + } finally { + activeCount--; + setCurrentThread(mainThread); + } + + + } + + private static void setCurrentThread(TThread thread){ + currentThread = thread; + } + private static TThread getMainThread(){ + return mainThread; } @Override @@ -84,11 +105,11 @@ public class TThread extends TObject implements TRunnable { } public static int activeCount() { - return 1; + return activeCount; } public long getId() { - return 1; + return id; } public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index 0537343d6..7a12c7c2d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -71,7 +71,6 @@ public class ThreadNativeGenerator implements Generator, DependencyPlugin { private void generateStart(GeneratorContext context, SourceWriter writer) throws IOException { String obj = context.getParameterName(0); - writer.append("setTimeout(function() { $rt_rootInvocationAdapter(").appendMethodBody(launchRef).append(")(") .append(obj).append(");},0);").softNewLine(); } diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 7a03aa30b..719fff4d3 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -344,6 +344,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository { internDep.use(); dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use(); + dependencyChecker.linkMethod(new MethodReference(Thread.class, "currentThread", Thread.class), null).use(); + dependencyChecker.linkMethod(new MethodReference(Thread.class, "getMainThread", Thread.class), null).use(); + dependencyChecker.linkMethod( + new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class), null).use(); MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference( NoClassDefFoundError.class, "", String.class, void.class), null); exceptionCons.use(); @@ -422,6 +426,29 @@ public class TeaVM implements TeaVMHost, ServiceRepository { listener.begin(renderer, target); } sourceWriter.append("\"use strict\";").newLine(); + + + // Keep track of current running thread by overriding setTimeout + sourceWriter.append("self.old_setTimeout=self.setTimeout;").softNewLine(); + sourceWriter.append("self.setTimeout=function(f,interval){").indent().softNewLine(); + MethodReference currentThreadRef = new MethodReference( + Thread.class, "currentThread", Thread.class); + MethodReference setCurrentThreadRef = new MethodReference( + Thread.class, "setCurrentThread", Thread.class, void.class); + MethodReference getMainThreadRef = new MethodReference(Thread.class, "getMainThread", Thread.class); + + sourceWriter.append("var currThread = ").appendMethodBody(currentThreadRef).append("();").softNewLine(); + sourceWriter.append("var callback = function(){").indent().softNewLine(); + sourceWriter.appendMethodBody(setCurrentThreadRef).append("(currThread);").softNewLine(); + sourceWriter.append("try{f();} finally {").softNewLine(); + sourceWriter.appendMethodBody(setCurrentThreadRef).append("("). + appendMethodBody(getMainThreadRef).append("());}").softNewLine(); + sourceWriter.outdent().append("};").softNewLine(); + sourceWriter.append("self.old_setTimeout(callback, interval);").softNewLine(); + sourceWriter.outdent().append("};").softNewLine(); + + // END Thread stuff + renderer.renderRuntime(); for (ClassNode clsNode : clsNodes) { ClassReader cls = classSet.get(clsNode.getName()); diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index 27eda6f2f..3b16394a1 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -46,9 +46,9 @@ public final class AsyncProgram { } } - }); + }, "Test Thread"); t.start(); - + System.out.println("Should be main -> Current thread is "+Thread.currentThread().getName()); System.out.println("Now trying wait..."); lock.wait(20000); @@ -57,12 +57,16 @@ public final class AsyncProgram { } private static void doRun(Object lock) throws InterruptedException { + System.out.println("Current thread is "+Thread.currentThread().getName()); System.out.println("Executing timer task"); Thread.sleep(2000); + System.out.println("Current thread is "+Thread.currentThread().getName()); System.out.println("Calling lock.notify()"); lock.notify(); + System.out.println("Current thread is "+Thread.currentThread().getName()); System.out.println("Finished calling lock.notify()"); Thread.sleep(5000); + System.out.println("Current thread is "+Thread.currentThread().getName()); System.out.println("Finished another 5 second sleep"); } From cca4336a157bdb8d69b5efe10453c19f967cabf1 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Fri, 6 Feb 2015 14:11:07 -0800 Subject: [PATCH 06/12] Merged with latest async branch. Also added MonitorExitInstruction and MonitorEnterInstruction classes, and updated all associated visitors. These don't do anything yet though. --- .../java/lang/ObjectNativeGenerator.java | 13 ++--- .../java/lang/ThreadNativeGenerator.java | 6 +-- .../org/teavm/cache/DiskProgramCache.java | 10 ++++ .../main/java/org/teavm/cache/ProgramIO.java | 10 ++++ .../teavm/javascript/StatementGenerator.java | 10 ++++ .../teavm/model/InstructionReadVisitor.java | 10 ++++ .../instructions/InstructionVisitor.java | 4 ++ .../instructions/MonitorEnterInstruction.java | 50 +++++++++++++++++++ .../instructions/MonitorExitInstruction.java | 48 ++++++++++++++++++ .../teavm/model/util/BasicBlockMapper.java | 14 ++++++ .../teavm/model/util/DefinitionExtractor.java | 10 ++++ .../util/InstructionTransitionExtractor.java | 10 ++++ .../model/util/InstructionVariableMapper.java | 14 ++++++ .../model/util/MissingItemsProcessor.java | 10 ++++ .../org/teavm/model/util/UsageExtractor.java | 10 ++++ .../optimization/GlobalValueNumbering.java | 10 ++++ .../optimization/LoopInvariantMotion.java | 20 ++++++++ .../UnusedVariableElimination.java | 10 ++++ .../optimization/VariableEscapeAnalyzer.java | 10 ++++ .../VariableUsageGraphBuilder.java | 10 ++++ .../org/teavm/parsing/ClassRefsRenamer.java | 10 ++++ .../org/teavm/parsing/SSATransformer.java | 10 ++++ .../src/main/java/org/teavm/vm/TeaVM.java | 5 +- .../resources/org/teavm/javascript/runtime.js | 2 +- 24 files changed, 301 insertions(+), 15 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/model/instructions/MonitorEnterInstruction.java create mode 100644 teavm-core/src/main/java/org/teavm/model/instructions/MonitorExitInstruction.java 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 77212fa66..e90cb051d 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 @@ -127,13 +127,12 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu writer.append("(function(){").indent().softNewLine(); writer.append("var completed = false;").softNewLine(); writer.append("var retCallback = ").append(context.getCompleteContinuation()).append(";").softNewLine(); - writer.append("console.log(retCallback);").softNewLine(); writer.append("var callback = function(){").indent().softNewLine(); writer.append("if (completed){return;} completed=true;").softNewLine(); - writer.append("retCallback();").softNewLine(); + writer.append("retCallback($rt_asyncResult(null));").softNewLine(); writer.outdent().append("};").softNewLine(); writer.append("if (").append(pname).append(">0){").indent().softNewLine(); - writer.append("setTimeout(callback, ").append(pname).append(");").softNewLine(); + writer.append("$rt_setTimeout(callback, ").append(pname).append(");").softNewLine(); writer.outdent().append("}").softNewLine(); addNotifyListener(context, writer, "callback"); writer.outdent().append("})();").softNewLine(); @@ -162,18 +161,16 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu private void sendNotify(GeneratorContext context, SourceWriter writer) throws IOException { String lArr = getNotifyListeners(context); - writer.append("setTimeout(function(){").indent().softNewLine(); + writer.append("$rt_setTimeout(function(){").indent().softNewLine(); writer.append("if (!").append(lArr).append(" || ").append(lArr).append(".length===0){return;}").softNewLine(); - writer.append("var m = ").append(lArr).append(".shift();").softNewLine(); - writer.append("console.log('Notify callback : '+m);").softNewLine(); - writer.append("m.apply(null);").softNewLine(); + writer.append(lArr).append(".shift().apply(null);").softNewLine(); writer.outdent().append("}, 0);").softNewLine(); } private void sendNotifyAll(GeneratorContext context, SourceWriter writer) throws IOException { String obj = context.getParameterName(0); String lArr = getNotifyListeners(context); - writer.append("setTimeout(function(){").indent().softNewLine(); + writer.append("$rt_setTimeout(function(){").indent().softNewLine(); writer.append("if (!").append(lArr).append("){return;}").softNewLine(); writer.append("while (").append(lArr).append(".length>0){").indent().softNewLine(); writer.append(lArr).append(".shift().call(null);").softNewLine(); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java index 2b59714ba..5af53318f 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -58,20 +58,20 @@ public class ThreadNativeGenerator implements Generator, DependencyPlugin { } private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { - writer.append("setTimeout(function() {").indent().softNewLine(); + writer.append("$rt_setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("($rt_asyncResult(null));").softNewLine(); writer.outdent().append("},").ws().append(context.getParameterName(1)).append(");").softNewLine(); } private void generateYield(GeneratorContext context, SourceWriter writer) throws IOException { - writer.append("setTimeout(function() {").indent().softNewLine(); + writer.append("$rt_setTimeout(function() {").indent().softNewLine(); writer.append(context.getCompleteContinuation()).append("($rt_asyncResult(null));").softNewLine(); writer.outdent().append("},").ws().append("0);").softNewLine(); } private void generateStart(GeneratorContext context, SourceWriter writer) throws IOException { String obj = context.getParameterName(0); - writer.append("setTimeout(function() { $rt_rootInvocationAdapter(").appendMethodBody(launchRef).append(")(") + writer.append("$rt_setTimeout(function() { $rt_rootInvocationAdapter(").appendMethodBody(launchRef).append(")(") .append(obj).append(");},0);").softNewLine(); } } diff --git a/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java b/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java index 716fa20dc..91f55b9b2 100644 --- a/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java +++ b/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java @@ -153,5 +153,15 @@ public class DiskProgramCache implements ProgramCache { @Override public void visit(IsInstanceInstruction insn) { } @Override public void visit(InitClassInstruction insn) { } @Override public void visit(NullCheckInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } } diff --git a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java index 2e878c392..19978b16d 100644 --- a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java @@ -594,6 +594,16 @@ public class ProgramIO { throw new IOExceptionWrapper(e); } } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } private static class IOExceptionWrapper extends RuntimeException { diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java index 9c3388ff6..3595f4611 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -666,4 +666,14 @@ class StatementGenerator implements InstructionVisitor { public void visit(NullCheckInstruction insn) { assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), insn.getReceiver()); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java index 67cb3bbad..446953241 100644 --- a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -201,4 +201,14 @@ class InstructionReadVisitor implements InstructionVisitor { public void visit(NullCheckInstruction insn) { reader.nullCheck(insn.getReceiver(), insn.getValue()); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java index 865335d5d..7a38d2306 100644 --- a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java +++ b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java @@ -87,4 +87,8 @@ public interface InstructionVisitor { void visit(InitClassInstruction insn); void visit(NullCheckInstruction insn); + + void visit(MonitorEnterInstruction insn); + + void visit(MonitorExitInstruction insn); } diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/MonitorEnterInstruction.java b/teavm-core/src/main/java/org/teavm/model/instructions/MonitorEnterInstruction.java new file mode 100644 index 000000000..8938b5819 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/instructions/MonitorEnterInstruction.java @@ -0,0 +1,50 @@ +/* + * Copyright 2013 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.instructions; + +import org.teavm.model.Instruction; +import org.teavm.model.Variable; + +/** + * + * @author shannah + */ +public class MonitorEnterInstruction extends Instruction { + + private Variable objectRef; + + + + @Override + public void acceptVisitor(InstructionVisitor visitor) { + visitor.visit(this); + } + + /** + * @return the objectRef + */ + public Variable getObjectRef() { + return objectRef; + } + + /** + * @param objectRef the objectRef to set + */ + public void setObjectRef(Variable objectRef) { + this.objectRef = objectRef; + } + +} diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/MonitorExitInstruction.java b/teavm-core/src/main/java/org/teavm/model/instructions/MonitorExitInstruction.java new file mode 100644 index 000000000..d705489ae --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/instructions/MonitorExitInstruction.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013 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.instructions; + +import org.teavm.model.Instruction; +import org.teavm.model.Variable; + +/** + * + * @author shannah + */ +public class MonitorExitInstruction extends Instruction { + + private Variable objectRef; + + @Override + public void acceptVisitor(InstructionVisitor visitor) { + visitor.visit(this); + } + + /** + * @return the objectRef + */ + public Variable getObjectRef() { + return objectRef; + } + + /** + * @param objectRef the objectRef to set + */ + public void setObjectRef(Variable objectRef) { + this.objectRef = objectRef; + } + +} diff --git a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java index 520b90689..8162a454f 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java @@ -184,4 +184,18 @@ public abstract class BasicBlockMapper implements InstructionVisitor { @Override public void visit(NullCheckInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } + + + + } diff --git a/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java index 5d0d42f43..7cca20ed0 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java @@ -202,4 +202,14 @@ public class DefinitionExtractor implements InstructionVisitor { public void visit(NullCheckInstruction insn) { definedVariables = new Variable[] { insn.getReceiver() }; } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java index 366134a22..6f6ef9856 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java @@ -204,4 +204,14 @@ public class InstructionTransitionExtractor implements InstructionVisitor { public void visit(NullCheckInstruction insn) { targets = null; } + + @Override + public void visit(MonitorEnterInstruction insn) { + targets = null; + } + + @Override + public void visit(MonitorExitInstruction insn) { + targets = null; + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java index fc9af0584..97d0e658c 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java @@ -228,4 +228,18 @@ public abstract class InstructionVariableMapper implements InstructionVisitor { insn.setReceiver(map(insn.getReceiver())); insn.setValue(map(insn.getValue())); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } + + + + } diff --git a/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java index f0885b3ae..b154e3a46 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java @@ -310,5 +310,15 @@ public class MissingItemsProcessor { @Override public void visit(EmptyInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } }; } diff --git a/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java index 803ab0fd5..c65d9da33 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java @@ -206,4 +206,14 @@ public class UsageExtractor implements InstructionVisitor { public void visit(NullCheckInstruction insn) { usedVariables = new Variable[] { insn.getValue() }; } + + @Override + public void visit(MonitorEnterInstruction insn) { + usedVariables = new Variable[] {insn.getObjectRef() }; + } + + @Override + public void visit(MonitorExitInstruction insn) { + usedVariables = new Variable[] {insn.getObjectRef()}; + } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java index efdfb2ab7..a6d4ac1ca 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java +++ b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java @@ -418,5 +418,15 @@ public class GlobalValueNumbering implements MethodOptimization { insn.setValue(program.variableAt(val)); bind(insn.getReceiver().getIndex(), "nullCheck @" + val); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } }; } diff --git a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java index 74cf5a707..99e9a1cbe 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java +++ b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java @@ -379,6 +379,16 @@ public class LoopInvariantMotion implements MethodOptimization { public void visit(NullCheckInstruction insn) { canMove = true; } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } private class CopyConstantVisitor implements InstructionVisitor { @@ -561,5 +571,15 @@ public class LoopInvariantMotion implements MethodOptimization { @Override public void visit(NullCheckInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java index 64f1f4cc5..b4d13841e 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java +++ b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java @@ -248,5 +248,15 @@ public class UnusedVariableElimination implements MethodOptimization { public void visit(NullCheckInstruction insn) { requestUsage(insn.getReceiver()); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java b/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java index ca185b27b..41deb3cb5 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java +++ b/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java @@ -204,5 +204,15 @@ public final class VariableEscapeAnalyzer { @Override public void visit(NullCheckInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java b/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java index b16104866..0b5e1c691 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java @@ -210,5 +210,15 @@ public final class VariableUsageGraphBuilder { public void visit(NullCheckInstruction insn) { use(insn.getReceiver(), insn.getValue()); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index 939f2601c..921b9d700 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -284,4 +284,14 @@ public class ClassRefsRenamer implements InstructionVisitor { @Override public void visit(NullCheckInstruction insn) { } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java index 1060d5beb..b16afe881 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java @@ -447,5 +447,15 @@ public class SSATransformer { insn.setValue(use(insn.getValue())); insn.setReceiver(define(insn.getReceiver())); } + + @Override + public void visit(MonitorEnterInstruction insn) { + + } + + @Override + public void visit(MonitorExitInstruction insn) { + + } }; } diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index fb2dfa3f0..cf333c617 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -430,8 +430,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { // Keep track of current running thread by overriding setTimeout - sourceWriter.append("self.old_setTimeout=self.setTimeout;").softNewLine(); - sourceWriter.append("self.setTimeout=function(f,interval){").indent().softNewLine(); + sourceWriter.append("function $rt_setTimeout(f,interval){").indent().softNewLine(); MethodReference currentThreadRef = new MethodReference( Thread.class, "currentThread", Thread.class); MethodReference setCurrentThreadRef = new MethodReference( @@ -445,7 +444,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { sourceWriter.appendMethodBody(setCurrentThreadRef).append("("). appendMethodBody(getMainThreadRef).append("());}").softNewLine(); sourceWriter.outdent().append("};").softNewLine(); - sourceWriter.append("self.old_setTimeout(callback, interval);").softNewLine(); + sourceWriter.append("setTimeout(callback, interval);").softNewLine(); sourceWriter.outdent().append("};").softNewLine(); // END Thread stuff 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 d6793042b..ec2a05e12 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -416,7 +416,7 @@ function $rt_asyncAdapter(f) { return $return($rt_asyncResult(result)); } } -function $rt_rootInvocationAdapter(f) { +function $rt_rootInvocationAdapter(f, extraArgs) { return function() { var args = Array.prototype.slice.apply(arguments); if (extraArgs) { From 2fbc50e76fda38adc88a1577886718a6e17a0acc Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Fri, 6 Feb 2015 16:47:59 -0800 Subject: [PATCH 07/12] Most of the elements are in place for monitors to work... something is wrong tough because I get errors when I try to compile files with synchronized sections. --- .../org/teavm/classlib/java/lang/TObject.java | 33 ++++++++++ .../org/teavm/classlib/java/lang/TThread.java | 6 +- .../src/main/java/org/teavm/cache/AstIO.java | 10 ++++ .../cache/DiskRegularMethodNodeCache.java | 10 ++++ .../javascript/BreakToContinueReplacer.java | 10 ++++ .../javascript/CertainBlockCountVisitor.java | 10 ++++ .../teavm/javascript/OptimizingVisitor.java | 10 ++++ .../javascript/RedundantLabelEliminator.java | 10 ++++ .../javascript/ReferenceCountingVisitor.java | 10 ++++ .../java/org/teavm/javascript/Renderer.java | 34 +++++++++++ .../teavm/javascript/StatementGenerator.java | 16 ++++- .../org/teavm/javascript/TryCatchFinder.java | 10 ++++ .../javascript/UnusedVariableEliminator.java | 10 ++++ .../javascript/ast/MonitorEnterStatement.java | 60 +++++++++++++++++++ .../javascript/ast/MonitorExitStatement.java | 60 +++++++++++++++++++ .../teavm/javascript/ast/RenamingVisitor.java | 10 ++++ .../javascript/ast/StatementVisitor.java | 4 ++ .../main/java/org/teavm/model/BasicBlock.java | 15 ++++- .../model/util/InstructionVariableMapper.java | 4 +- .../optimization/GlobalValueNumbering.java | 6 +- .../java/org/teavm/parsing/ProgramParser.java | 15 ++++- .../org/teavm/parsing/SSATransformer.java | 4 +- .../teavm-samples-async/nb-configuration.xml | 19 ++++++ .../teavm-samples-async/nbactions.xml | 17 ++++++ .../org/teavm/samples/async/AsyncProgram.java | 22 +++++++ 25 files changed, 402 insertions(+), 13 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java create mode 100644 teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java create mode 100644 teavm-samples/teavm-samples-async/nb-configuration.xml create mode 100644 teavm-samples/teavm-samples-async/nbactions.xml diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index 5de13b11f..a343528ed 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -29,6 +29,39 @@ import org.teavm.runtime.Async; */ @Superclass("") public class TObject { + + private TThread owner; + private TObject monitorLock; + private int monitorCount=0; + + static void monitorEnter(TObject o){ + if ( o.monitorLock == null ){ + o.monitorLock = new TObject(); + } + while (o.owner != null && o.owner != TThread.currentThread() ){ + try { + o.monitorLock.wait(); + } catch (InterruptedException ex) { + + } + } + o.owner = TThread.currentThread(); + o.monitorCount++; + + } + + static void monitorExit(TObject o){ + o.owner = null; + o.monitorCount--; + if ( o.monitorLock != null ){ + o.monitorLock.notifyAll(); + } + } + + static boolean holdsLock(TObject o){ + return o.owner == TThread.currentThread(); + } + @Rename("fakeInit") public TObject() { } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 77d8c6c1e..b03b29853 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -112,8 +112,8 @@ public class TThread extends TObject implements TRunnable { return id; } - public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) { - return true; + public static boolean holdsLock(TObject obj) { + return TObject.holdsLock(obj); } public static void sleep(long millis) throws TInterruptedException { @@ -123,4 +123,6 @@ public class TThread extends TObject implements TRunnable { @Async @GeneratedBy(ThreadNativeGenerator.class) private static native void sleep(double millis) throws TInterruptedException; + + } diff --git a/teavm-core/src/main/java/org/teavm/cache/AstIO.java b/teavm-core/src/main/java/org/teavm/cache/AstIO.java index 3fda51324..6edeb906b 100644 --- a/teavm-core/src/main/java/org/teavm/cache/AstIO.java +++ b/teavm-core/src/main/java/org/teavm/cache/AstIO.java @@ -508,6 +508,16 @@ public class AstIO { throw new IOExceptionWrapper(e); } } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } private NodeLocation readLocation(DataInput input) throws IOException { diff --git a/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java b/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java index 33253cd80..c597c6490 100644 --- a/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java +++ b/teavm-core/src/main/java/org/teavm/cache/DiskRegularMethodNodeCache.java @@ -261,6 +261,16 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } static class Item { 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 de500d61f..01e8d7a73 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/BreakToContinueReplacer.java @@ -116,4 +116,14 @@ class BreakToContinueReplacer implements StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java index bd475a54a..66152cb01 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/CertainBlockCountVisitor.java @@ -111,4 +111,14 @@ class CertainBlockCountVisitor implements StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java index 3d432424b..0d3474098 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -618,4 +618,14 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { public void visit(RestoreAsyncStatement statement) { resultStmt = statement; } + + @Override + public void visit(MonitorEnterStatement statement) { + resultStmt = statement; + } + + @Override + public void visit(MonitorExitStatement statement) { + resultStmt = statement; + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java index 30111b45d..bca649fd4 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/RedundantLabelEliminator.java @@ -121,4 +121,14 @@ class RedundantLabelEliminator implements StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java index 1e5f742af..218b8ea45 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ReferenceCountingVisitor.java @@ -115,4 +115,14 @@ class ReferenceCountingVisitor implements StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } 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 d71d3455b..a74505f75 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -55,6 +55,40 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext private DeferredCallSite prevCallSite; private boolean async; + @Override + public void visit(MonitorEnterStatement statement) { + if (async){ + try { + MethodReference monitorEnterRef = new MethodReference( + Object.class, "monitorEnter", Object.class, void.class); + + writer.appendMethodBody(monitorEnterRef).append("("); + statement.acceptVisitor(this); + writer.append(");").softNewLine(); + + } catch (IOException ex){ + throw new RenderingException("IO error occured", ex); + } + } + } + + @Override + public void visit(MonitorExitStatement statement) { + if (async){ + try { + MethodReference monitorExitRef = new MethodReference( + Object.class, "monitorExit", Object.class, void.class); + + writer.appendMethodBody(monitorExitRef).append("("); + statement.acceptVisitor(this); + writer.append(");").softNewLine(); + } catch (IOException ex){ + throw new RenderingException("IO error occured", ex); + } + + } + } + private static class InjectorHolder { public final Injector injector; diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java index 3595f4611..432bb0d5a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -670,10 +670,24 @@ class StatementGenerator implements InstructionVisitor { @Override public void visit(MonitorEnterInstruction insn) { + MonitorEnterStatement stmt = new MonitorEnterStatement(); + stmt.setLocation(currentLocation); + + VariableExpr expr = new VariableExpr(); + expr.setIndex(insn.getObjectRef().getIndex()); + expr.setLocation(currentLocation); + stmt.setObjectRef(expr); + statements.add(stmt); } @Override public void visit(MonitorExitInstruction insn) { - + MonitorExitStatement stmt = new MonitorExitStatement(); + stmt.setLocation(currentLocation); + VariableExpr expr = new VariableExpr(); + expr.setLocation(currentLocation); + expr.setIndex(insn.getObjectRef().getIndex()); + stmt.setObjectRef(expr); + statements.add(stmt); } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java b/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java index 7618fb355..4b54c49e2 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/TryCatchFinder.java @@ -114,4 +114,14 @@ class TryCatchFinder implements StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java index 719a1a842..57845257a 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/UnusedVariableEliminator.java @@ -228,4 +228,14 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor { @Override public void visit(RestoreAsyncStatement statement) { } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java new file mode 100644 index 000000000..1735e8d00 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java @@ -0,0 +1,60 @@ +/* + * 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.javascript.ast; + +/** + * + * @author shannah + */ +public class MonitorEnterStatement extends Statement { + + private NodeLocation location; + private VariableExpr objectRef; + + @Override + public void acceptVisitor(StatementVisitor visitor) { + visitor.visit(this); + } + + /** + * @return the location + */ + public NodeLocation getLocation() { + return location; + } + + /** + * @param location the location to set + */ + public void setLocation(NodeLocation location) { + this.location = location; + } + + /** + * @return the objectRef + */ + public VariableExpr getObjectRef() { + return objectRef; + } + + /** + * @param objectRef the objectRef to set + */ + public void setObjectRef(VariableExpr objectRef) { + this.objectRef = objectRef; + } + +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java new file mode 100644 index 000000000..b13fd370a --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java @@ -0,0 +1,60 @@ +/* + * 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.javascript.ast; + +/** + * + * @author shannah + */ +public class MonitorExitStatement extends Statement { + + private NodeLocation location; + private VariableExpr objectRef; + + @Override + public void acceptVisitor(StatementVisitor visitor) { + visitor.visit(this); + } + + /** + * @return the location + */ + public NodeLocation getLocation() { + return location; + } + + /** + * @param location the location to set + */ + public void setLocation(NodeLocation location) { + this.location = location; + } + + /** + * @return the objectRef + */ + public VariableExpr getObjectRef() { + return objectRef; + } + + /** + * @param objectRef the objectRef to set + */ + public void setObjectRef(VariableExpr objectRef) { + this.objectRef = objectRef; + } + +} diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java index cb3b363ec..402fe6d3c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RenamingVisitor.java @@ -198,4 +198,14 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor { statement.setReceiver(varNames[statement.getReceiver()]); } } + + @Override + public void visit(MonitorEnterStatement statement) { + + } + + @Override + public void visit(MonitorExitStatement statement) { + + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java index 8d984747f..86cbb8474 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/StatementVisitor.java @@ -45,4 +45,8 @@ public interface StatementVisitor { void visit(TryCatchStatement statement); void visit(RestoreAsyncStatement statement); + + void visit(MonitorEnterStatement statement); + + void visit(MonitorExitStatement statement); } diff --git a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java index 737f7963c..81c911488 100644 --- a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java +++ b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java @@ -16,6 +16,7 @@ package org.teavm.model; import java.util.*; +import org.teavm.model.instructions.AssignInstruction; import org.teavm.model.instructions.InstructionReader; /** @@ -66,7 +67,19 @@ public class BasicBlock implements BasicBlockReader { @Override public void add(int index, Instruction e) { if (e.getBasicBlock() != null) { - throw new IllegalArgumentException("This instruction is in some basic block"); + if (e instanceof AssignInstruction){ + AssignInstruction ae = (AssignInstruction)e; + System.out.println("Assignment "+ae.getReceiver()+" -> "+ae.getAssignee()); + System.out.println(ae.getReceiver().getDebugNames()); + System.out.println(ae.getReceiver().getIndex()); + System.out.println(ae.getReceiver().getProgram()); + System.out.println(ae.getAssignee().getDebugNames()); + System.out.println(ae.getAssignee().getIndex()); + System.out.println(ae.getAssignee().getProgram()); + + System.out.println(ae.getBasicBlock().getInstructions()); + } + throw new IllegalArgumentException("This instruction is in some basic block "+e+", "+e.getLocation()); } e.setBasicBlock(BasicBlock.this); instructions.add(index, e); diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java index 97d0e658c..65da6ac85 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java @@ -231,12 +231,12 @@ public abstract class InstructionVariableMapper implements InstructionVisitor { @Override public void visit(MonitorEnterInstruction insn) { - + insn.setObjectRef(map(insn.getObjectRef())); } @Override public void visit(MonitorExitInstruction insn) { - + insn.setObjectRef(map(insn.getObjectRef())); } diff --git a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java index a6d4ac1ca..51cdfd741 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java +++ b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java @@ -421,12 +421,14 @@ public class GlobalValueNumbering implements MethodOptimization { @Override public void visit(MonitorEnterInstruction insn) { - + int val = map[insn.getObjectRef().getIndex()]; + insn.setObjectRef(program.variableAt(val)); } @Override public void visit(MonitorExitInstruction insn) { - + int val = map[insn.getObjectRef().getIndex()]; + insn.setObjectRef(program.variableAt(val)); } }; } diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index f3ab0237b..8a9f92ea4 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -1556,10 +1556,19 @@ public class ProgramParser implements VariableDebugInformation { nextIndexes = new int[0]; return; } - case Opcodes.MONITORENTER: - case Opcodes.MONITOREXIT: - popSingle(); + case Opcodes.MONITORENTER: { + MonitorEnterInstruction insn = new MonitorEnterInstruction(); + insn.setObjectRef(getVariable(popSingle())); + addInstruction(insn); break; + } + case Opcodes.MONITOREXIT: { + MonitorExitInstruction insn = new MonitorExitInstruction(); + insn.setObjectRef(getVariable(popSingle())); + addInstruction(insn); + break; + } + } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java index b16afe881..a48a82dda 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java @@ -450,12 +450,12 @@ public class SSATransformer { @Override public void visit(MonitorEnterInstruction insn) { - + insn.setObjectRef(use(insn.getObjectRef())); } @Override public void visit(MonitorExitInstruction insn) { - + insn.setObjectRef(use(insn.getObjectRef())); } }; } diff --git a/teavm-samples/teavm-samples-async/nb-configuration.xml b/teavm-samples/teavm-samples-async/nb-configuration.xml new file mode 100644 index 000000000..792bc673f --- /dev/null +++ b/teavm-samples/teavm-samples-async/nb-configuration.xml @@ -0,0 +1,19 @@ + + + + + + maven + gfv3ee6 + + diff --git a/teavm-samples/teavm-samples-async/nbactions.xml b/teavm-samples/teavm-samples-async/nbactions.xml new file mode 100644 index 000000000..35d636f69 --- /dev/null +++ b/teavm-samples/teavm-samples-async/nbactions.xml @@ -0,0 +1,17 @@ + + + + build + + * + + + install + + + true + maven + + + + diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index 598de3fb1..89ead77cf 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -48,6 +48,20 @@ public final class AsyncProgram { }, "Test Thread"); t.start(); + + Thread t2 = new Thread(new Runnable(){ + + @Override + public void run() { + try { + doRun(lock); + } catch (InterruptedException ex){ + System.out.println(ex.getMessage()); + } + } + + }, "Test Thread 2"); + t2.start(); System.out.println("Should be main -> Current thread is "+Thread.currentThread().getName()); System.out.println("Now trying wait..."); @@ -68,6 +82,12 @@ public final class AsyncProgram { Thread.sleep(5000); System.out.println("Current thread is "+Thread.currentThread().getName()); System.out.println("Finished another 5 second sleep"); + + synchronized(lock){ + System.out.println("Inside locked section of thread "+Thread.currentThread().getName()); + Thread.sleep(2000); + System.out.println("Finished locked section of thread "+Thread.currentThread().getName()); + } } private static void withoutAsync() { @@ -113,4 +133,6 @@ public final class AsyncProgram { System.out.println("Thread.yield called"); throw new IllegalStateException(); } + + } From e2b6b7b2df6757345a0e70628ea9090d17b16477 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Fri, 6 Feb 2015 17:07:01 -0800 Subject: [PATCH 08/12] Fixed monitorExit to work with more than one enter/exit. --- .../main/java/org/teavm/classlib/java/lang/TObject.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index a343528ed..9ca2ef4e4 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -51,10 +51,13 @@ public class TObject { } static void monitorExit(TObject o){ - o.owner = null; + o.monitorCount--; - if ( o.monitorLock != null ){ - o.monitorLock.notifyAll(); + if ( o.monitorCount == 0 ){ + if ( o.monitorLock != null ){ + o.owner = null; + o.monitorLock.notifyAll(); + } } } From 68aa193728edb43879faabf897fa4d7976081116 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Sat, 7 Feb 2015 07:22:13 -0800 Subject: [PATCH 09/12] Made some changes based on Alexey's comments of previous changes. Still getting same error on build. --- .../main/java/org/teavm/cache/ProgramIO.java | 26 +++++++++++++++++-- .../dependency/DependencyGraphBuilder.java | 14 ++++++++++ .../javascript/ast/MonitorEnterStatement.java | 6 ++--- .../javascript/ast/MonitorExitStatement.java | 6 ++--- .../model/instructions/InstructionReader.java | 4 +++ .../model/util/InstructionStringifier.java | 10 +++++++ .../org/teavm/model/util/ProgramUtils.java | 16 ++++++++++++ .../tooling/ProgramSourceAggregator.java | 10 +++++++ 8 files changed, 84 insertions(+), 8 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java index 19978b16d..b4689db64 100644 --- a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java @@ -597,12 +597,24 @@ public class ProgramIO { @Override public void visit(MonitorEnterInstruction insn) { - + try { + output.writeByte(39); + output.writeShort(insn.getObjectRef().getIndex()); + + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } } @Override public void visit(MonitorExitInstruction insn) { - + try { + output.writeByte(40); + output.writeShort(insn.getObjectRef().getIndex()); + + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } } } @@ -908,6 +920,16 @@ public class ProgramIO { insn.setValue(program.variableAt(input.readShort())); return insn; } + case 39: { + MonitorEnterInstruction insn = new MonitorEnterInstruction(); + insn.setObjectRef(program.variableAt(input.readShort())); + return insn; + } + case 40: { + MonitorExitInstruction insn = new MonitorExitInstruction(); + insn.setObjectRef(program.variableAt(input.readShort())); + return insn; + } default: throw new RuntimeException("Unknown instruction type: " + insnType); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 232548688..5e13cca03 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -490,5 +490,19 @@ class DependencyGraphBuilder { new CallLocation(caller.getMethod(), currentLocation)).use(); currentExceptionConsumer.consume(dependencyChecker.getType("java.lang.NullPointerException")); } + + @Override + public void monitorEnter(VariableReader objectRef) { + dependencyChecker.linkMethod( + new MethodReference(Object.class, "monitorEnter", Object.class, void.class), + new CallLocation(caller.getMethod(), currentLocation)).use(); + } + + @Override + public void monitorExit(VariableReader objectRef) { + dependencyChecker.linkMethod( + new MethodReference(Object.class, "monitorExit", Object.class, void.class), + new CallLocation(caller.getMethod(), currentLocation)).use(); + } }; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java index 1735e8d00..9051f32f0 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorEnterStatement.java @@ -22,7 +22,7 @@ package org.teavm.javascript.ast; public class MonitorEnterStatement extends Statement { private NodeLocation location; - private VariableExpr objectRef; + private Expr objectRef; @Override public void acceptVisitor(StatementVisitor visitor) { @@ -46,14 +46,14 @@ public class MonitorEnterStatement extends Statement { /** * @return the objectRef */ - public VariableExpr getObjectRef() { + public Expr getObjectRef() { return objectRef; } /** * @param objectRef the objectRef to set */ - public void setObjectRef(VariableExpr objectRef) { + public void setObjectRef(Expr objectRef) { this.objectRef = objectRef; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java index b13fd370a..2f6d61fdc 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/MonitorExitStatement.java @@ -22,7 +22,7 @@ package org.teavm.javascript.ast; public class MonitorExitStatement extends Statement { private NodeLocation location; - private VariableExpr objectRef; + private Expr objectRef; @Override public void acceptVisitor(StatementVisitor visitor) { @@ -46,14 +46,14 @@ public class MonitorExitStatement extends Statement { /** * @return the objectRef */ - public VariableExpr getObjectRef() { + public Expr getObjectRef() { return objectRef; } /** * @param objectRef the objectRef to set */ - public void setObjectRef(VariableExpr objectRef) { + public void setObjectRef(Expr objectRef) { this.objectRef = objectRef; } diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java index c2c191b66..2b022cf8b 100644 --- a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java +++ b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java @@ -100,4 +100,8 @@ public interface InstructionReader { void initClass(String className); void nullCheck(VariableReader receiver, VariableReader value); + + void monitorEnter(VariableReader objectRef); + + void monitorExit(VariableReader objectRef); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java index 053c7372c..c3a2a1a54 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java @@ -352,4 +352,14 @@ public class InstructionStringifier implements InstructionReader { public void nullCheck(VariableReader receiver, VariableReader value) { sb.append("@").append(receiver.getIndex()).append(" := nullCheck @").append(value.getIndex()); } + + @Override + public void monitorEnter(VariableReader objectRef) { + sb.append("monitorenter @").append(objectRef.getIndex()); + } + + @Override + public void monitorExit(VariableReader objectRef) { + sb.append("monitorexit @").append(objectRef.getIndex()); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java index a570efe8b..4f5a2b80e 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -495,5 +495,21 @@ public final class ProgramUtils { copy = insnCopy; copy.setLocation(location); } + + @Override + public void monitorEnter(VariableReader objectRef) { + MonitorEnterInstruction insnCopy = new MonitorEnterInstruction(); + insnCopy.setObjectRef(copyVar(objectRef)); + copy = insnCopy; + copy.setLocation(location); + } + + @Override + public void monitorExit(VariableReader objectRef) { + MonitorExitInstruction insnCopy = new MonitorExitInstruction(); + insnCopy.setObjectRef(copyVar(objectRef)); + copy = insnCopy; + copy.setLocation(location); + } } } diff --git a/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java b/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java index de340d0cc..9dc33d3d6 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java +++ b/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java @@ -88,4 +88,14 @@ class ProgramSourceAggregator implements InstructionReader { @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } @Override public void initClass(String className) { } @Override public void nullCheck(VariableReader receiver, VariableReader value) { } + + @Override + public void monitorEnter(VariableReader objectRef) { + + } + + @Override + public void monitorExit(VariableReader objectRef) { + + } } From d37da2b07876e599a2e9c70425c3aa5297749354 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Sat, 7 Feb 2015 07:34:02 -0800 Subject: [PATCH 10/12] Made small change to statement generator for monitor instructions. --- .../java/org/teavm/javascript/StatementGenerator.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java index 432bb0d5a..d341d27f6 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -673,10 +673,7 @@ class StatementGenerator implements InstructionVisitor { MonitorEnterStatement stmt = new MonitorEnterStatement(); stmt.setLocation(currentLocation); - VariableExpr expr = new VariableExpr(); - expr.setIndex(insn.getObjectRef().getIndex()); - expr.setLocation(currentLocation); - stmt.setObjectRef(expr); + stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); statements.add(stmt); } @@ -684,10 +681,8 @@ class StatementGenerator implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { MonitorExitStatement stmt = new MonitorExitStatement(); stmt.setLocation(currentLocation); - VariableExpr expr = new VariableExpr(); - expr.setLocation(currentLocation); - expr.setIndex(insn.getObjectRef().getIndex()); - stmt.setObjectRef(expr); + + stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); statements.add(stmt); } } From 21468ef419664d9b72f907425c79ba4106877116 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Sat, 7 Feb 2015 10:00:48 -0800 Subject: [PATCH 11/12] Fixed issue with the instruction copier. Now it builds ok with synchronized instruction. Getting an error at runtime... --- teavm-core/src/main/java/org/teavm/javascript/Renderer.java | 4 ++-- .../src/main/java/org/teavm/model/InstructionReadVisitor.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 a74505f75..e1e24e13f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -63,7 +63,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext Object.class, "monitorEnter", Object.class, void.class); writer.appendMethodBody(monitorEnterRef).append("("); - statement.acceptVisitor(this); + statement.getObjectRef().acceptVisitor(this); writer.append(");").softNewLine(); } catch (IOException ex){ @@ -80,7 +80,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext Object.class, "monitorExit", Object.class, void.class); writer.appendMethodBody(monitorExitRef).append("("); - statement.acceptVisitor(this); + statement.getObjectRef().acceptVisitor(this); writer.append(");").softNewLine(); } catch (IOException ex){ throw new RenderingException("IO error occured", ex); diff --git a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java index 446953241..5d7627469 100644 --- a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -204,11 +204,11 @@ class InstructionReadVisitor implements InstructionVisitor { @Override public void visit(MonitorEnterInstruction insn) { - + reader.monitorEnter(insn.getObjectRef()); } @Override public void visit(MonitorExitInstruction insn) { - + reader.monitorExit(insn.getObjectRef()); } } From a1df42878cfe0549b899008dfc0ce29f9f0f1be8 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Mon, 9 Feb 2015 10:54:06 -0800 Subject: [PATCH 12/12] Changed native functions to use new AsyncCallback approach. --- .../org/teavm/classlib/java/lang/TObject.java | 79 ++++++++++++++----- .../org/teavm/classlib/java/lang/TThread.java | 45 ++++++----- 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index d289eb974..e801bd696 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -15,19 +15,18 @@ */ package org.teavm.classlib.java.lang; -<<<<<<< HEAD +import org.teavm.dom.browser.Window; +import org.teavm.javascript.spi.Async; -import org.teavm.dependency.PluggableDependency; -import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.javascript.ni.InjectedBy; -import org.teavm.javascript.ni.Rename; -import org.teavm.javascript.ni.Superclass; -import org.teavm.runtime.Async; -======= import org.teavm.javascript.spi.Rename; import org.teavm.javascript.spi.Superclass; +import org.teavm.jso.JS; +import org.teavm.jso.JSArray; +import org.teavm.jso.JSFunctor; +import org.teavm.jso.JSObject; import org.teavm.platform.Platform; ->>>>>>> dd25ae4759716d735fe6f93a54c8bfab2e7fc7bf +import org.teavm.platform.async.AsyncCallback; + /** * @@ -39,6 +38,13 @@ public class TObject { private TThread owner; private TObject monitorLock; private int monitorCount=0; + private JSArray notifyListeners; + private final Window window = (Window)JS.getGlobal(); + + @JSFunctor + private static interface NotifyListener extends JSObject{ + void handleNotify(); + } static void monitorEnter(TObject o){ if ( o.monitorLock == null ){ @@ -59,11 +65,9 @@ public class TObject { static void monitorExit(TObject o){ o.monitorCount--; - if ( o.monitorCount == 0 ){ - if ( o.monitorLock != null ){ - o.owner = null; - o.monitorLock.notifyAll(); - } + if ( o.monitorCount == 0 && o.monitorLock != null){ + o.owner = null; + o.monitorLock.notifyAll(); } } @@ -114,14 +118,27 @@ public class TObject { return Platform.clone(this); } - @GeneratedBy(ObjectNativeGenerator.class) @Rename("notify") - public native final void notify0(); + public final void notify0(){ + if (notifyListeners != null && notifyListeners.getLength() > 0){ + notifyListeners.shift().handleNotify(); + } + } - @GeneratedBy(ObjectNativeGenerator.class) @Rename("notifyAll") - public native final void notifyAll0(); + public final void notifyAll0(){ + if (notifyListeners != null){ + JSArray listeners = window.newArray(); + while (notifyListeners.getLength() > 0 ){ + listeners.push(notifyListeners.shift()); + } + while ( listeners.getLength() > 0 ){ + listeners.shift().handleNotify(); + } + } + + } @Rename("wait") @@ -134,15 +151,37 @@ public class TObject { } @Async - @GeneratedBy(ObjectNativeGenerator.class) @Rename("wait") public native final void wait0(long timeout, int nanos) throws TInterruptedException; + + @Rename("wait") + public final void wait0(long timeout, int nanos, final AsyncCallback callback){ + if ( notifyListeners == null ){ + notifyListeners = window.newArray(); + } + final TThread currentThread = TThread.currentThread(); + notifyListeners.push(new NotifyListener(){ + + @Override + public void handleNotify() { + TThread.setCurrentThread(currentThread); + try { + callback.complete(null); + } finally { + TThread.setCurrentThread(TThread.getMainThread()); + } + + } + + }); + } + @Rename("wait") public final void wait0() throws TInterruptedException { try { wait(0l); - } catch (InterruptedException ex) { + } catch ( InterruptedException ex){ throw new TInterruptedException(); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index 5e81ff8ca..1c5bacaa7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -15,33 +15,26 @@ */ package org.teavm.classlib.java.lang; -<<<<<<< HEAD -import org.teavm.dependency.PluggableDependency; -import org.teavm.javascript.ni.GeneratedBy; -import org.teavm.runtime.Async; -======= import org.teavm.dom.browser.TimerHandler; import org.teavm.dom.browser.Window; import org.teavm.javascript.spi.Async; import org.teavm.jso.JS; import org.teavm.platform.async.AsyncCallback; ->>>>>>> dd25ae4759716d735fe6f93a54c8bfab2e7fc7bf + /** * * @author Alexey Andreev */ public class TThread extends TObject implements TRunnable { -<<<<<<< HEAD + + private static Window window = (Window)JS.getGlobal(); private static TThread mainThread = new TThread(TString.wrap("main")); private static TThread currentThread = mainThread; private static long nextId = 1; private static int activeCount = 1; private long id; -======= - private static Window window = (Window)JS.getGlobal(); - private static TThread currentThread = new TThread(TString.wrap("main")); ->>>>>>> dd25ae4759716d735fe6f93a54c8bfab2e7fc7bf + private TString name; private TRunnable target; @@ -63,9 +56,13 @@ public class TThread extends TObject implements TRunnable { id=nextId++; } - @PluggableDependency(ThreadNativeGenerator.class) - @GeneratedBy(ThreadNativeGenerator.class) - public native void start(); + public void start(){ + window.setTimeout(new TimerHandler() { + @Override public void onTimer() { + launch(TThread.this); + } + }, 0); + } private static void launch(TThread thread) { try { @@ -80,10 +77,10 @@ public class TThread extends TObject implements TRunnable { } - private static void setCurrentThread(TThread thread){ + static void setCurrentThread(TThread thread){ currentThread = thread; } - private static TThread getMainThread(){ + static TThread getMainThread(){ return mainThread; } @@ -106,9 +103,12 @@ public class TThread extends TObject implements TRunnable { public static native void yield(); private static void yield(final AsyncCallback callback) { + final TThread current = currentThread(); window.setTimeout(new TimerHandler() { @Override public void onTimer() { + setCurrentThread(current); callback.complete(null); + setCurrentThread(mainThread); } }, 0); } @@ -136,21 +136,20 @@ public class TThread extends TObject implements TRunnable { return TObject.holdsLock(obj); } + @Async -<<<<<<< HEAD - @GeneratedBy(ThreadNativeGenerator.class) - private static native void sleep(double millis) throws TInterruptedException; - - -======= public static native void sleep(long millis) throws TInterruptedException; private static void sleep(long millis, final AsyncCallback callback) { + final TThread current = currentThread(); + window.setTimeout(new TimerHandler() { @Override public void onTimer() { + setCurrentThread(current); callback.complete(null); + setCurrentThread(mainThread); } }, millis); } ->>>>>>> dd25ae4759716d735fe6f93a54c8bfab2e7fc7bf + }