Merge remote-tracking branch 'origin/shannah_threads' into shannah_threads

This commit is contained in:
konsoletyper 2015-02-09 23:14:25 +04:00
commit 74a76804fb
53 changed files with 1643 additions and 27 deletions

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}
}

View File

@ -15,9 +15,18 @@
*/ */
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import org.teavm.dom.browser.Window;
import org.teavm.javascript.spi.Async;
import org.teavm.javascript.spi.Rename; import org.teavm.javascript.spi.Rename;
import org.teavm.javascript.spi.Superclass; 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; import org.teavm.platform.Platform;
import org.teavm.platform.async.AsyncCallback;
/** /**
* *
@ -25,6 +34,47 @@ import org.teavm.platform.Platform;
*/ */
@Superclass("") @Superclass("")
public class TObject { public class TObject {
private TThread owner;
private TObject monitorLock;
private int monitorCount=0;
private JSArray<NotifyListener> 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 ){
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.monitorCount--;
if ( o.monitorCount == 0 && o.monitorLock != null){
o.owner = null;
o.monitorLock.notifyAll();
}
}
static boolean holdsLock(TObject o){
return o.owner == TThread.currentThread();
}
@Rename("fakeInit") @Rename("fakeInit")
public TObject() { public TObject() {
} }
@ -70,25 +120,71 @@ public class TObject {
} }
@Rename("notify") @Rename("notify")
public final void notify0() { public final void notify0(){
if (notifyListeners != null && notifyListeners.getLength() > 0){
notifyListeners.shift().handleNotify();
}
} }
@Rename("notifyAll") @Rename("notifyAll")
public final void notifyAll0() { public final void notifyAll0(){
if (notifyListeners != null){
JSArray<NotifyListener> listeners = window.newArray();
while (notifyListeners.getLength() > 0 ){
listeners.push(notifyListeners.shift());
}
while ( listeners.getLength() > 0 ){
listeners.shift().handleNotify();
}
}
} }
@SuppressWarnings("unused")
@Rename("wait") @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
@Rename("wait") @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(long timeout, int nanos, final AsyncCallback<Void> 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") @Rename("wait")
public final void wait0() throws TInterruptedException { public final void wait0() throws TInterruptedException {
try {
wait(0l);
} catch ( InterruptedException ex){
throw new TInterruptedException();
}
} }
@Override @Override

View File

@ -21,13 +21,20 @@ import org.teavm.javascript.spi.Async;
import org.teavm.jso.JS; import org.teavm.jso.JS;
import org.teavm.platform.async.AsyncCallback; import org.teavm.platform.async.AsyncCallback;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class TThread extends TObject implements TRunnable { public class TThread extends TObject implements TRunnable {
private static Window window = (Window)JS.getGlobal(); private static Window window = (Window)JS.getGlobal();
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 TString name;
private TRunnable target; private TRunnable target;
@ -36,16 +43,45 @@ public class TThread extends TObject implements TRunnable {
} }
public TThread(TString name) { public TThread(TString name) {
this(name, null); this(null, name);
} }
public TThread(TRunnable target) { 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.name = name;
this.target = target; this.target = target;
id=nextId++;
}
public void start(){
window.setTimeout(new TimerHandler() {
@Override public void onTimer() {
launch(TThread.this);
}
}, 0);
}
private static void launch(TThread thread) {
try {
activeCount++;
setCurrentThread(thread);
thread.run();
} finally {
activeCount--;
setCurrentThread(mainThread);
}
}
static void setCurrentThread(TThread thread){
currentThread = thread;
}
static TThread getMainThread(){
return mainThread;
} }
@Override @Override
@ -67,9 +103,12 @@ public class TThread extends TObject implements TRunnable {
public static native void yield(); public static native void yield();
private static void yield(final AsyncCallback<Void> callback) { private static void yield(final AsyncCallback<Void> callback) {
final TThread current = currentThread();
window.setTimeout(new TimerHandler() { window.setTimeout(new TimerHandler() {
@Override public void onTimer() { @Override public void onTimer() {
setCurrentThread(current);
callback.complete(null); callback.complete(null);
setCurrentThread(mainThread);
} }
}, 0); }, 0);
} }
@ -86,25 +125,31 @@ public class TThread extends TObject implements TRunnable {
} }
public static int activeCount() { public static int activeCount() {
return 1; return activeCount;
} }
public long getId() { public long getId() {
return 1; return id;
} }
public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) { public static boolean holdsLock(TObject obj) {
return true; return TObject.holdsLock(obj);
} }
@Async @Async
public static native void sleep(long millis) throws TInterruptedException; public static native void sleep(long millis) throws TInterruptedException;
private static void sleep(long millis, final AsyncCallback<Void> callback) { private static void sleep(long millis, final AsyncCallback<Void> callback) {
final TThread current = currentThread();
window.setTimeout(new TimerHandler() { window.setTimeout(new TimerHandler() {
@Override public void onTimer() { @Override public void onTimer() {
setCurrentThread(current);
callback.complete(null); callback.complete(null);
setCurrentThread(mainThread);
} }
}, millis); }, millis);
} }
} }

View File

@ -508,6 +508,16 @@ public class AstIO {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }
private NodeLocation readLocation(DataInput input) throws IOException { private NodeLocation readLocation(DataInput input) throws IOException {

View File

@ -153,5 +153,15 @@ public class DiskProgramCache implements ProgramCache {
@Override public void visit(IsInstanceInstruction insn) { } @Override public void visit(IsInstanceInstruction insn) { }
@Override public void visit(InitClassInstruction insn) { } @Override public void visit(InitClassInstruction insn) { }
@Override public void visit(NullCheckInstruction insn) { } @Override public void visit(NullCheckInstruction insn) { }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
} }

View File

@ -261,6 +261,16 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }
static class Item { static class Item {

View File

@ -594,6 +594,28 @@ public class ProgramIO {
throw new IOExceptionWrapper(e); throw new IOExceptionWrapper(e);
} }
} }
@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);
}
}
} }
private static class IOExceptionWrapper extends RuntimeException { private static class IOExceptionWrapper extends RuntimeException {
@ -898,6 +920,16 @@ public class ProgramIO {
insn.setValue(program.variableAt(input.readShort())); insn.setValue(program.variableAt(input.readShort()));
return insn; 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: default:
throw new RuntimeException("Unknown instruction type: " + insnType); throw new RuntimeException("Unknown instruction type: " + insnType);
} }

View File

@ -490,5 +490,19 @@ class DependencyGraphBuilder {
new CallLocation(caller.getMethod(), currentLocation)).use(); new CallLocation(caller.getMethod(), currentLocation)).use();
currentExceptionConsumer.consume(dependencyChecker.getType("java.lang.NullPointerException")); 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();
}
}; };
} }

View File

@ -116,4 +116,14 @@ class BreakToContinueReplacer implements StatementVisitor {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -111,4 +111,14 @@ class CertainBlockCountVisitor implements StatementVisitor {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -618,4 +618,14 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
resultStmt = statement; resultStmt = statement;
} }
@Override
public void visit(MonitorEnterStatement statement) {
resultStmt = statement;
}
@Override
public void visit(MonitorExitStatement statement) {
resultStmt = statement;
}
} }

View File

@ -121,4 +121,14 @@ class RedundantLabelEliminator implements StatementVisitor {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -115,4 +115,14 @@ class ReferenceCountingVisitor implements StatementVisitor {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -59,6 +59,40 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
private Diagnostics diagnostics; private Diagnostics diagnostics;
private boolean async; 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.getObjectRef().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.getObjectRef().acceptVisitor(this);
writer.append(");").softNewLine();
} catch (IOException ex){
throw new RenderingException("IO error occured", ex);
}
}
}
private static class InjectorHolder { private static class InjectorHolder {
public final Injector injector; public final Injector injector;

View File

@ -666,4 +666,23 @@ class StatementGenerator implements InstructionVisitor {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), insn.getReceiver()); assign(Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), insn.getReceiver());
} }
@Override
public void visit(MonitorEnterInstruction insn) {
MonitorEnterStatement stmt = new MonitorEnterStatement();
stmt.setLocation(currentLocation);
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
statements.add(stmt);
}
@Override
public void visit(MonitorExitInstruction insn) {
MonitorExitStatement stmt = new MonitorExitStatement();
stmt.setLocation(currentLocation);
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
statements.add(stmt);
}
} }

View File

@ -114,4 +114,14 @@ class TryCatchFinder implements StatementVisitor {
@Override @Override
public void visit(RestoreAsyncStatement statement) { public void visit(RestoreAsyncStatement statement) {
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -231,4 +231,14 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
statement.setReceiver(renumber(statement.getReceiver())); statement.setReceiver(renumber(statement.getReceiver()));
} }
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -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 Expr 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 Expr getObjectRef() {
return objectRef;
}
/**
* @param objectRef the objectRef to set
*/
public void setObjectRef(Expr objectRef) {
this.objectRef = objectRef;
}
}

View File

@ -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 Expr 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 Expr getObjectRef() {
return objectRef;
}
/**
* @param objectRef the objectRef to set
*/
public void setObjectRef(Expr objectRef) {
this.objectRef = objectRef;
}
}

View File

@ -198,4 +198,14 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
statement.setReceiver(varNames[statement.getReceiver()]); statement.setReceiver(varNames[statement.getReceiver()]);
} }
} }
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
} }

View File

@ -45,4 +45,8 @@ public interface StatementVisitor {
void visit(TryCatchStatement statement); void visit(TryCatchStatement statement);
void visit(RestoreAsyncStatement statement); void visit(RestoreAsyncStatement statement);
void visit(MonitorEnterStatement statement);
void visit(MonitorExitStatement statement);
} }

View File

@ -16,6 +16,7 @@
package org.teavm.model; package org.teavm.model;
import java.util.*; import java.util.*;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.InstructionReader; import org.teavm.model.instructions.InstructionReader;
/** /**
@ -66,7 +67,19 @@ public class BasicBlock implements BasicBlockReader {
@Override @Override
public void add(int index, Instruction e) { public void add(int index, Instruction e) {
if (e.getBasicBlock() != null) { 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); e.setBasicBlock(BasicBlock.this);
instructions.add(index, e); instructions.add(index, e);

View File

@ -201,4 +201,14 @@ class InstructionReadVisitor implements InstructionVisitor {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
reader.nullCheck(insn.getReceiver(), insn.getValue()); reader.nullCheck(insn.getReceiver(), insn.getValue());
} }
@Override
public void visit(MonitorEnterInstruction insn) {
reader.monitorEnter(insn.getObjectRef());
}
@Override
public void visit(MonitorExitInstruction insn) {
reader.monitorExit(insn.getObjectRef());
}
} }

View File

@ -100,4 +100,8 @@ public interface InstructionReader {
void initClass(String className); void initClass(String className);
void nullCheck(VariableReader receiver, VariableReader value); void nullCheck(VariableReader receiver, VariableReader value);
void monitorEnter(VariableReader objectRef);
void monitorExit(VariableReader objectRef);
} }

View File

@ -87,4 +87,8 @@ public interface InstructionVisitor {
void visit(InitClassInstruction insn); void visit(InitClassInstruction insn);
void visit(NullCheckInstruction insn); void visit(NullCheckInstruction insn);
void visit(MonitorEnterInstruction insn);
void visit(MonitorExitInstruction insn);
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -184,4 +184,18 @@ public abstract class BasicBlockMapper implements InstructionVisitor {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -202,4 +202,14 @@ public class DefinitionExtractor implements InstructionVisitor {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() }; definedVariables = new Variable[] { insn.getReceiver() };
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -352,4 +352,14 @@ public class InstructionStringifier implements InstructionReader {
public void nullCheck(VariableReader receiver, VariableReader value) { public void nullCheck(VariableReader receiver, VariableReader value) {
sb.append("@").append(receiver.getIndex()).append(" := nullCheck @").append(value.getIndex()); 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());
}
} }

View File

@ -204,4 +204,14 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
targets = null; targets = null;
} }
@Override
public void visit(MonitorEnterInstruction insn) {
targets = null;
}
@Override
public void visit(MonitorExitInstruction insn) {
targets = null;
}
} }

View File

@ -228,4 +228,18 @@ public abstract class InstructionVariableMapper implements InstructionVisitor {
insn.setReceiver(map(insn.getReceiver())); insn.setReceiver(map(insn.getReceiver()));
insn.setValue(map(insn.getValue())); insn.setValue(map(insn.getValue()));
} }
@Override
public void visit(MonitorEnterInstruction insn) {
insn.setObjectRef(map(insn.getObjectRef()));
}
@Override
public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(map(insn.getObjectRef()));
}
} }

View File

@ -310,5 +310,15 @@ public class MissingItemsProcessor {
@Override @Override
public void visit(EmptyInstruction insn) { public void visit(EmptyInstruction insn) {
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
}; };
} }

View File

@ -495,5 +495,21 @@ public final class ProgramUtils {
copy = insnCopy; copy = insnCopy;
copy.setLocation(location); 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);
}
} }
} }

View File

@ -206,4 +206,14 @@ public class UsageExtractor implements InstructionVisitor {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
usedVariables = new Variable[] { insn.getValue() }; 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()};
}
} }

View File

@ -418,5 +418,17 @@ public class GlobalValueNumbering implements MethodOptimization {
insn.setValue(program.variableAt(val)); insn.setValue(program.variableAt(val));
bind(insn.getReceiver().getIndex(), "nullCheck @" + val); bind(insn.getReceiver().getIndex(), "nullCheck @" + val);
} }
@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));
}
}; };
} }

View File

@ -379,6 +379,16 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
canMove = true; canMove = true;
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
private class CopyConstantVisitor implements InstructionVisitor { private class CopyConstantVisitor implements InstructionVisitor {
@ -561,5 +571,15 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
} }

View File

@ -248,5 +248,15 @@ public class UnusedVariableElimination implements MethodOptimization {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
requestUsage(insn.getReceiver()); requestUsage(insn.getReceiver());
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
} }

View File

@ -204,5 +204,15 @@ public final class VariableEscapeAnalyzer {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
} }

View File

@ -210,5 +210,15 @@ public final class VariableUsageGraphBuilder {
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
use(insn.getReceiver(), insn.getValue()); use(insn.getReceiver(), insn.getValue());
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }
} }

View File

@ -284,4 +284,14 @@ public class ClassRefsRenamer implements InstructionVisitor {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
} }
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
} }

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.JSRInlinerAdapter;
import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.*;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.optimization.UnreachableBasicBlockEliminator; import org.teavm.optimization.UnreachableBasicBlockEliminator;
@ -32,6 +33,12 @@ public final class Parser {
} }
public static MethodHolder parseMethod(MethodNode node, String className, String fileName) { 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); ValueType[] signature = MethodDescriptor.parseSignature(node.desc);
MethodHolder method = new MethodHolder(node.name, signature); MethodHolder method = new MethodHolder(node.name, signature);
parseModifiers(node.access, method); parseModifiers(node.access, method);
@ -59,8 +66,8 @@ public final class Parser {
cls.setParent(null); cls.setParent(null);
} }
if (node.interfaces != null) { if (node.interfaces != null) {
for (Object obj : node.interfaces) { for (String iface : node.interfaces) {
cls.getInterfaces().add(((String)obj).replace('/', '.')); cls.getInterfaces().add(iface.replace('/', '.'));
} }
} }
for (Object obj : node.fields) { for (Object obj : node.fields) {
@ -68,8 +75,7 @@ public final class Parser {
cls.addField(parseField(fieldNode)); cls.addField(parseField(fieldNode));
} }
String fullFileName = node.name.substring(0, node.name.lastIndexOf('/') + 1) + node.sourceFile; String fullFileName = node.name.substring(0, node.name.lastIndexOf('/') + 1) + node.sourceFile;
for (Object obj : node.methods) { for (MethodNode methodNode : node.methods) {
MethodNode methodNode = (MethodNode)obj;
cls.addMethod(parseMethod(methodNode, node.name, fullFileName)); cls.addMethod(parseMethod(methodNode, node.name, fullFileName));
} }
if (node.outerClass != null) { if (node.outerClass != null) {

View File

@ -1556,10 +1556,19 @@ public class ProgramParser implements VariableDebugInformation {
nextIndexes = new int[0]; nextIndexes = new int[0];
return; return;
} }
case Opcodes.MONITORENTER: case Opcodes.MONITORENTER: {
case Opcodes.MONITOREXIT: MonitorEnterInstruction insn = new MonitorEnterInstruction();
popSingle(); insn.setObjectRef(getVariable(popSingle()));
addInstruction(insn);
break; break;
}
case Opcodes.MONITOREXIT: {
MonitorExitInstruction insn = new MonitorExitInstruction();
insn.setObjectRef(getVariable(popSingle()));
addInstruction(insn);
break;
}
} }
} }

View File

@ -447,5 +447,15 @@ public class SSATransformer {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver()));
} }
@Override
public void visit(MonitorEnterInstruction insn) {
insn.setObjectRef(use(insn.getObjectRef()));
}
@Override
public void visit(MonitorExitInstruction insn) {
insn.setObjectRef(use(insn.getObjectRef()));
}
}; };
} }

View File

@ -88,4 +88,14 @@ class ProgramSourceAggregator implements InstructionReader {
@Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { }
@Override public void initClass(String className) { } @Override public void initClass(String className) { }
@Override public void nullCheck(VariableReader receiver, VariableReader value) { } @Override public void nullCheck(VariableReader receiver, VariableReader value) { }
@Override
public void monitorEnter(VariableReader objectRef) {
}
@Override
public void monitorExit(VariableReader objectRef) {
}
} }

View File

@ -347,6 +347,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
internDep.use(); internDep.use();
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).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(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( MethodDependency exceptionCons = dependencyChecker.linkMethod(new MethodReference(
NoClassDefFoundError.class, "<init>", String.class, void.class), null); NoClassDefFoundError.class, "<init>", String.class, void.class), null);
exceptionCons.use(); exceptionCons.use();
@ -426,6 +430,28 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
listener.begin(renderer, target); listener.begin(renderer, target);
} }
sourceWriter.append("\"use strict\";").newLine(); sourceWriter.append("\"use strict\";").newLine();
// Keep track of current running thread by overriding setTimeout
sourceWriter.append("function $rt_setTimeout(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("setTimeout(callback, interval);").softNewLine();
sourceWriter.outdent().append("};").softNewLine();
// END Thread stuff
renderer.renderRuntime(); renderer.renderRuntime();
for (ClassNode clsNode : clsNodes) { for (ClassNode clsNode : clsNodes) {
ClassReader cls = classSet.get(clsNode.getName()); ClassReader cls = classSet.get(clsNode.getName());

View File

@ -424,7 +424,7 @@ function $rt_asyncAdapter(f) {
return $return($rt_asyncResult(result)); return $return($rt_asyncResult(result));
} }
} }
function $rt_rootInvocationAdapter(f) { function $rt_rootInvocationAdapter(f, extraArgs) {
return function() { return function() {
var args = Array.prototype.slice.apply(arguments); var args = Array.prototype.slice.apply(arguments);
args.push(function(result) { args.push(function(result) {

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<ca-weblite-netbeans-mirah.project_5f_type>maven</ca-weblite-netbeans-mirah.project_5f_type>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>gfv3ee6</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
</properties>
</project-shared-configuration>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>build</actionName>
<packagings>
<packaging>*</packaging>
</packagings>
<goals>
<goal>install</goal>
</goals>
<properties>
<skipTests>true</skipTests>
<jpda.listen>maven</jpda.listen>
</properties>
</action>
</actions>

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.samples.async; package org.teavm.samples.async;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
@ -27,6 +28,66 @@ public final class AsyncProgram {
withoutAsync(); withoutAsync();
System.out.println(); System.out.println();
withAsync(); 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());
}
}
}, "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...");
lock.wait(20000);
System.out.println("Finished waiting");
}
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");
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() { private static void withoutAsync() {
@ -54,6 +115,9 @@ public final class AsyncProgram {
Thread.sleep(1000); Thread.sleep(1000);
} }
} }
System.out.println("2nd Thread.sleep in same method");
Thread.sleep(1000);
System.out.println("Complete async"); System.out.println("Complete async");
System.out.println("Throwing exception"); System.out.println("Throwing exception");
@ -69,4 +133,6 @@ public final class AsyncProgram {
System.out.println("Thread.yield called"); System.out.println("Thread.yield called");
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }