Merge branch 'async'

This commit is contained in:
konsoletyper 2015-02-26 23:48:31 +03:00
commit 1c0acf61d4
322 changed files with 7474 additions and 2454 deletions

View File

@ -82,6 +82,7 @@
<module>teavm-platform</module>
<module>teavm-cli</module>
<module>teavm-chrome-rdp</module>
<module>teavm-tests</module>
</modules>
<dependencyManagement>

View File

@ -465,6 +465,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
for (PropertyDescriptorDTO property : properties) {
RemoteObjectDTO remoteValue = property.getValue();
RDPValue value;
if (remoteValue != null && remoteValue.getType() != null) {
switch (remoteValue.getType()) {
case "undefined":
value = new RDPValue(this, "undefined", "undefined", null, false);
@ -478,6 +479,9 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
remoteValue.getObjectId(), false);
break;
}
} else {
value = new RDPValue(this, "null", "null", "null", false);
}
RDPLocalVariable var = new RDPLocalVariable(property.getName(), value);
variables.add(var);

View File

@ -49,6 +49,16 @@
<artifactId>teavm-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-jso</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-dom</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
@ -74,34 +84,6 @@
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.teavm</groupId>
<artifactId>teavm-maven-plugin</artifactId>
<version>${project.version}</version>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-platform</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>generate-javascript-tests</id>
<goals>
<goal>build-test-javascript</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<minifying>false</minifying>
<properties>
<java.util.Locale.available>en, en_US, en_GB, ru, ru_RU</java.util.Locale.available>
</properties>
<incremental>${teavm.classlib.test.incremental}</incremental>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
@ -135,15 +117,6 @@
</arguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>org/teavm/platform/metadata/*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>

View File

@ -0,0 +1,40 @@
/*
* 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.classlib.impl;
import java.util.HashMap;
import java.util.Map;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class DeclaringClassMetadataGenerator implements ClassScopedMetadataGenerator {
@Override
public Map<String, Resource> generateMetadata(MetadataGeneratorContext context, MethodReference method) {
Map<String, Resource> result = new HashMap<>();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
if (cls.getOwnerName() != null) {
result.put(clsName, context.createClassResource(cls.getOwnerName()));
}
}
return result;
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.impl;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.javascript.ni.PreserveOriginalName;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev
*/
public class EnumTransformer implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
if (cls.getParent() != null && !cls.getParent().equals("java.lang.Enum")) {
return;
}
MethodHolder method = cls.getMethod(new MethodDescriptor("values",
ValueType.arrayOf(ValueType.object(cls.getName()))));
if (method == null) {
return;
}
method.getAnnotations().add(new AnnotationHolder(PreserveOriginalName.class.getName()));
}
}

View File

@ -18,6 +18,7 @@ package org.teavm.classlib.impl;
import java.util.ServiceLoader;
import org.teavm.classlib.impl.unicode.CLDRReader;
import org.teavm.model.MethodReference;
import org.teavm.platform.PlatformClass;
import org.teavm.vm.spi.TeaVMHost;
import org.teavm.vm.spi.TeaVMPlugin;
@ -28,15 +29,10 @@ import org.teavm.vm.spi.TeaVMPlugin;
public class JCLPlugin implements TeaVMPlugin {
@Override
public void install(TeaVMHost host) {
host.add(new EnumDependencySupport());
host.add(new EnumTransformer());
host.add(new ClassLookupDependencySupport());
host.add(new NewInstanceDependencySupport());
host.add(new ObjectEnrichRenderer());
ServiceLoaderSupport serviceLoaderSupp = new ServiceLoaderSupport(host.getClassLoader());
host.add(serviceLoaderSupp);
MethodReference loadServicesMethod = new MethodReference(ServiceLoader.class, "loadServices",
Class.class, Object[].class);
PlatformClass.class, Object[].class);
host.add(loadServicesMethod, serviceLoaderSupp);
JavacSupport javacSupport = new JavacSupport();
host.add(javacSupport);

View File

@ -1,62 +0,0 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.impl;
import java.io.IOException;
import org.teavm.javascript.RenderingContext;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReader;
import org.teavm.vm.BuildTarget;
import org.teavm.vm.spi.RendererListener;
/**
*
* @author Alexey Andreev
*/
public class ObjectEnrichRenderer implements RendererListener {
private RenderingContext context;
@Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
this.context = context;
}
@Override
public void beforeClass(ClassReader cls) throws IOException {
}
@Override
public void afterClass(ClassReader cls) throws IOException {
if (cls.getName().equals("java.lang.Object")) {
MethodReader toString = cls.getMethod(new MethodDescriptor("toString", String.class));
if (toString != null) {
String clsName = context.getNaming().getNameFor(cls.getName());
String toStringName = context.getNaming().getNameFor(toString.getReference());
context.getWriter().append(clsName).append(".prototype.toString").ws().append('=').ws()
.append("function()").ws().append('{').indent().softNewLine();
context.getWriter().append("return this.").append(toStringName).ws().append('?').ws()
.append("$rt_ustr(this.").append(toStringName).append("())").ws().append(':')
.append("Object.prototype.toString.call(this);").softNewLine();
context.getWriter().outdent().append("}").newLine();
}
}
}
@Override
public void complete() throws IOException {
}
}

View File

@ -23,8 +23,8 @@ import java.net.URL;
import java.util.*;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
@ -65,7 +65,7 @@ public class ServiceLoaderSupport implements Generator, DependencyListener {
}
writer.outdent().append("}").softNewLine();
String param = context.getParameterName(1);
writer.append("var cls = " + param + ".$data;").softNewLine();
writer.append("var cls = " + param + ";").softNewLine();
writer.append("if (!cls.$$serviceList$$) {").indent().softNewLine();
writer.append("return $rt_createArray($rt_objcls(), 0);").softNewLine();
writer.outdent().append("}").softNewLine();

View File

@ -25,7 +25,7 @@ public abstract class Charset {
public abstract void decode(ByteBuffer source, CharBuffer dest);
public static Charset get(String name) {
if (name.equals("UTF-8")) {
if (name.toUpperCase().equals("UTF-8")) {
return new UTF8Charset();
}
return null;

View File

@ -39,7 +39,7 @@ public class TBufferedInputStream extends TFilterInputStream {
}
@Override
public synchronized int available() throws TIOException {
public int available() throws TIOException {
TInputStream localIn = in;
if (buf == null || localIn == null) {
throw new TIOException(TString.wrap("Stream is closed"));

View File

@ -51,7 +51,7 @@ public class TByteArrayOutputStream extends TOutputStream {
private void ensureCapacity(int capacity) {
if (buf.length < capacity) {
capacity = TMath.min(capacity, buf.length * 3 / 2);
capacity = TMath.max(capacity, buf.length * 3 / 2);
buf = TArrays.copyOf(buf, capacity);
}
}

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,381 @@
/*
* 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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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()
*/
@Override
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, 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, 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

@ -34,7 +34,7 @@ public class TFilterInputStream extends TInputStream {
}
@Override
public synchronized void mark(int readlimit) {
public void mark(int readlimit) {
in.mark(readlimit);
}

View File

@ -0,0 +1,125 @@
/*
* 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.classlib.java.io;
import org.teavm.classlib.impl.charset.ByteBuffer;
import org.teavm.classlib.impl.charset.CharBuffer;
import org.teavm.classlib.impl.charset.Charset;
import org.teavm.classlib.java.lang.TString;
public class TOutputStreamWriter extends TWriter {
private TOutputStream out;
private String encoding;
private Charset charset;
private byte[] bufferData = new byte[512];
private ByteBuffer buffer = new ByteBuffer(bufferData);
public TOutputStreamWriter(TOutputStream out) {
this(out, "UTF-8");
}
public TOutputStreamWriter(TOutputStream out, final String enc) throws TUnsupportedEncodingException {
super(out);
if (enc == null) {
throw new NullPointerException();
}
this.out = out;
charset = Charset.get(enc);
if (charset == null) {
throw new TUnsupportedEncodingException(TString.wrap(enc));
}
encoding = enc;
}
@Override
public void close() throws TIOException {
if (charset != null) {
flush();
charset = null;
out.flush();
out.close();
}
}
@Override
public void flush() throws TIOException {
checkStatus();
if (buffer.position() > 0) {
out.write(bufferData, 0, buffer.position());
buffer.rewind(0);
}
out.flush();
}
private void checkStatus() throws TIOException {
if (charset == null) {
throw new TIOException(TString.wrap("Writer already closed"));
}
}
public String getEncoding() {
return encoding;
}
@Override
public void write(char[] buf, int offset, int count) throws TIOException {
synchronized (lock) {
checkStatus();
if (buf == null) {
throw new NullPointerException();
}
if (offset < 0 || offset > buf.length - count || count < 0) {
throw new IndexOutOfBoundsException();
}
CharBuffer input = new CharBuffer(buf, offset, offset + count);
while (!input.end()) {
if (buffer.available() < 6) {
out.write(bufferData, 0, buffer.position());
buffer.rewind(0);
}
charset.encode(input, buffer);
}
}
}
@Override
public void write(int oneChar) throws TIOException {
synchronized (lock) {
checkStatus();
CharBuffer input = new CharBuffer(new char[] { (char)oneChar }, 0, 1);
while (!input.end()) {
if (buffer.available() < 6) {
out.write(bufferData, 0, buffer.position());
buffer.rewind(0);
}
charset.encode(input, buffer);
}
}
}
@Override
public void write(String str, int offset, int count) throws TIOException {
if (str == null) {
throw new NullPointerException();
}
if (count < 0) {
throw new IndexOutOfBoundsException("Negative count: " + count);
}
char[] chars = new char[count];
str.getChars(offset, offset + count, chars, 0);
write(chars);
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.classlib.java.io;
import org.teavm.classlib.java.lang.TAppendable;
import org.teavm.classlib.java.lang.TCharSequence;
public abstract class TWriter implements TAppendable, TCloseable, TFlushable {
protected Object lock;
protected TWriter() {
super();
lock = this;
}
protected TWriter(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
public void write(char buf[]) throws TIOException {
write(buf, 0, buf.length);
}
public abstract void write(char buf[], int offset, int count) throws TIOException;
public void write(int oneChar) throws TIOException {
synchronized (lock) {
char oneCharArray[] = new char[1];
oneCharArray[0] = (char) oneChar;
write(oneCharArray);
}
}
public void write(String str) throws TIOException {
write(str, 0, str.length());
}
public void write(String str, int offset, int count) throws TIOException {
if (count < 0) {
throw new StringIndexOutOfBoundsException();
}
char buf[] = new char[count];
str.getChars(offset, offset + count, buf, 0);
synchronized (lock) {
write(buf, 0, buf.length);
}
}
@Override
public TWriter append(char c) throws TIOException {
write(c);
return this;
}
@Override
public TWriter append(TCharSequence csq) throws TIOException {
write(csq != null ? csq.toString() : "null");
return this;
}
@Override
public TWriter append(TCharSequence csq, int start, int end) throws TIOException {
write(csq != null ? csq.subSequence(start, end).toString() : "null");
return this;
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.classlib.java.lang;
import org.teavm.classlib.impl.unicode.UnicodeHelper;
import org.teavm.classlib.impl.unicode.UnicodeSupport;
import org.teavm.model.MethodReference;
import org.teavm.platform.metadata.MetadataGenerator;
import org.teavm.platform.metadata.MetadataGeneratorContext;
import org.teavm.platform.metadata.Resource;
import org.teavm.platform.metadata.StringResource;
/**
*
* @author Alexey Andreev
*/
public class CharacterMetadataGenerator implements MetadataGenerator {
@Override
public Resource generateMetadata(MetadataGeneratorContext context, MethodReference method) {
switch (method.getName()) {
case "obtainDigitMapping":
return generateObtainDigitMapping(context);
case "obtainClasses":
return generateObtainClasses(context);
default:
return null;
}
}
private Resource generateObtainDigitMapping(MetadataGeneratorContext context) {
StringResource res = context.createResource(StringResource.class);
res.setValue(UnicodeHelper.encodeIntByte(UnicodeSupport.getDigitValues()));
return res;
}
private Resource generateObtainClasses(MetadataGeneratorContext context) {
StringResource res = context.createResource(StringResource.class);
res.setValue(UnicodeHelper.compressRle(UnicodeSupport.getClasses()));
return res;
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 2014 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.classlib.impl.unicode.UnicodeHelper;
import org.teavm.classlib.impl.unicode.UnicodeSupport;
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 CharacterNativeGenerator implements Generator, DependencyPlugin {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "toLowerCase":
writer.append("return String.fromCharCode(").append(context.getParameterName(1))
.append(").toLowerCase().charCodeAt(0)|0;").softNewLine();
break;
case "toUpperCase":
writer.append("return String.fromCharCode(").append(context.getParameterName(1))
.append(").toUpperCase().charCodeAt(0)|0;").softNewLine();
break;
case "obtainDigitMapping":
generateObtainDigitMapping(writer);
break;
case "obtainClasses":
generateObtainClasses(writer);
break;
}
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "obtainDigitMapping":
case "obtainClasses":
method.getResult().propagate(agent.getType("java.lang.String"));
break;
}
}
private void generateObtainDigitMapping(SourceWriter writer) throws IOException {
String str = UnicodeHelper.encodeIntByte(UnicodeSupport.getDigitValues());
writer.append("return $rt_str(");
splitString(writer, str);
writer.append(");").softNewLine();
}
private void generateObtainClasses(SourceWriter writer) throws IOException {
String str = UnicodeHelper.compressRle(UnicodeSupport.getClasses());
writer.append("return $rt_str(");
splitString(writer, str);
writer.append(");").softNewLine();
}
private void splitString(SourceWriter writer, String str) throws IOException {
for (int i = 0; i < str.length(); i += 512) {
if (i > 0) {
writer.ws().append("+").newLine();
}
int j = Math.min(i + 512, str.length());
writer.append("\"").append(str.substring(i, j)).append("\"");
}
}
}

View File

@ -1,216 +0,0 @@
/*
* 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.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.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.*;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ClassNativeGenerator implements Generator, Injector, DependencyPlugin {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
throws IOException {
switch (methodRef.getName()) {
case "getComponentType0":
generateGetComponentType(context, writer);
break;
case "getSuperclass":
generateGetSuperclass(context, writer);
break;
case "forNameImpl":
generateForName(context, writer);
break;
case "newInstance":
generateNewInstance(context, writer);
break;
case "getDeclaringClass":
generateGetDeclaringClass(context, writer);
break;
}
}
private void generateGetComponentType(GeneratorContext context, SourceWriter writer) throws IOException {
String thisArg = context.getParameterName(0);
writer.append("var item = " + thisArg + ".$data.$meta.item;").softNewLine();
writer.append("return item != null ? $rt_cls(item) : null;").softNewLine();
}
private void generateGetSuperclass(GeneratorContext context, SourceWriter writer) throws IOException {
String thisArg = context.getParameterName(0);
writer.append("var superclass = " + thisArg + ".$data.$meta.superclass;").softNewLine();
writer.append("return superclass ? $rt_cls(superclass) : null;").softNewLine();
}
@Override
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "isInstance":
generateIsInstance(context);
break;
case "isAssignableFrom":
generateIsAssignableFrom(context);
break;
case "voidClass":
context.getWriter().append("$rt_cls($rt_voidcls())");
break;
case "booleanClass":
context.getWriter().append("$rt_cls($rt_booleancls())");
break;
case "charClass":
context.getWriter().append("$rt_cls($rt_charcls())");
break;
case "byteClass":
context.getWriter().append("$rt_cls($rt_bytecls())");
break;
case "shortClass":
context.getWriter().append("$rt_cls($rt_shortcls())");
break;
case "intClass":
context.getWriter().append("$rt_cls($rt_intcls())");
break;
case "longClass":
context.getWriter().append("$rt_cls($rt_longcls())");
break;
case "floatClass":
context.getWriter().append("$rt_cls($rt_floatcls())");
break;
case "doubleClass":
context.getWriter().append("$rt_cls($rt_doublecls())");
break;
case "wrapClass":
context.writeExpr(context.getArgument(0));
break;
case "getEnumConstantsImpl":
context.writeExpr(context.getArgument(0));
context.getWriter().append(".$data.values()");
break;
}
}
private void generateIsAssignableFrom(InjectorContext context) throws IOException {
SourceWriter writer = context.getWriter();
writer.append("$rt_isAssignable(");
context.writeExpr(context.getArgument(1));
writer.append(".$data,").ws();
context.writeExpr(context.getArgument(0));
writer.append(".$data)");
}
private void generateIsInstance(InjectorContext context) throws IOException {
SourceWriter writer = context.getWriter();
writer.append("$rt_isInstance(");
context.writeExpr(context.getArgument(1));
writer.append(",").ws();
context.writeExpr(context.getArgument(0));
writer.append(".$data)");
}
private void generateForName(GeneratorContext context, SourceWriter writer) throws IOException {
String param = context.getParameterName(1);
writer.append("switch ($rt_ustr(" + param + ")) {").softNewLine().indent();
for (String name : context.getClassSource().getClassNames()) {
writer.append("case \"" + name + "\": ").appendClass(name).append(".$clinit(); ")
.append("return $rt_cls(").appendClass(name).append(");").softNewLine();
}
writer.append("default: return null;").softNewLine();
writer.outdent().append("}").softNewLine();
}
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
String self = context.getParameterName(0);
writer.append("if (!").appendClass("java.lang.Class").append(".$$constructors$$) {").indent().softNewLine();
writer.appendClass("java.lang.Class").append(".$$constructors$$ = true;").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID));
if (method != null) {
writer.appendClass(clsName).append(".$$constructor$$ = ").appendMethodBody(method.getReference())
.append(";").softNewLine();
}
}
writer.outdent().append("}").softNewLine();
writer.append("var cls = " + self + ".$data;").softNewLine();
writer.append("var ctor = cls.$$constructor$$;").softNewLine();
writer.append("if (!ctor) {").indent().softNewLine();
writer.append("var ex = new ").appendClass(InstantiationException.class.getName()).append("();").softNewLine();
writer.appendMethodBody(new MethodReference(InstantiationException.class.getName(), new MethodDescriptor(
"<init>", ValueType.VOID))).append("(ex);").softNewLine();
writer.append("$rt_throw(ex);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("var instance = new cls();").softNewLine();
writer.append("ctor(instance);").softNewLine();
writer.append("return instance;").softNewLine();
}
private void generateGetDeclaringClass(GeneratorContext context, SourceWriter writer) throws IOException {
String self = context.getParameterName(0);
writer.append("if (!").appendClass("java.lang.Class").append(".$$owners$$) {").indent().softNewLine();
writer.appendClass("java.lang.Class").append(".$$owners$$ = true;").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
writer.appendClass(clsName).append(".$$owner$$ = ");
if (cls.getOwnerName() != null) {
writer.appendClass(cls.getOwnerName());
} else {
writer.append("null");
}
writer.append(";").softNewLine();
}
writer.outdent().append("}").softNewLine();
writer.append("var cls = " + self + ".$data;").softNewLine();
writer.append("return cls.$$owner$$ != null ? $rt_cls(cls.$$owner$$) : null;").softNewLine();
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency graph, CallLocation location) {
switch (graph.getReference().getName()) {
case "voidClass":
case "booleanClass":
case "byteClass":
case "shortClass":
case "charClass":
case "intClass":
case "longClass":
case "floatClass":
case "doubleClass":
case "wrapClass":
case "getSuperclass":
case "getComponentType0":
case "forNameImpl":
case "getDeclaringClass":
graph.getResult().propagate(agent.getType("java.lang.Class"));
break;
case "getName":
graph.getResult().propagate(agent.getType("java.lang.String"));
break;
case "newInstance":
agent.linkMethod(new MethodReference(InstantiationException.class, "<init>", void.class),
location).use();
break;
}
}
}

View File

@ -1,41 +0,0 @@
/*
* 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.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class ConsoleOutputStreamGenerator implements Generator {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
if (methodRef.getClassName().endsWith("_stderr")) {
if (methodRef.getName().equals("write")) {
writer.append("$rt_putStderr(").append(context.getParameterName(1)).append(");").softNewLine();
}
} else if (methodRef.getClassName().endsWith("_stdout")) {
if (methodRef.getName().equals("write")) {
writer.append("$rt_putStdout(").append(context.getParameterName(1)).append(");").softNewLine();
}
}
}
}

View File

@ -17,10 +17,10 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.javascript.spi.Injector;
import org.teavm.javascript.spi.InjectorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -17,10 +17,10 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.javascript.spi.Injector;
import org.teavm.javascript.spi.InjectorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -17,8 +17,8 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -17,8 +17,8 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -1,110 +0,0 @@
/*
* 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.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.ni.Injector;
import org.teavm.javascript.ni.InjectorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class ObjectNativeGenerator implements Generator, Injector, DependencyPlugin {
@Override
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
switch (methodRef.getDescriptor().getName()) {
case "<init>":
generateInit(context, writer);
break;
case "hashCode":
case "identity":
generateHashCode(context, writer);
break;
case "clone":
generateClone(context, writer);
break;
}
}
@Override
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
switch (methodRef.getName()) {
case "getClass":
generateGetClass(context);
break;
case "wrap":
generateWrap(context);
break;
}
}
@Override
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
switch (method.getReference().getName()) {
case "clone":
method.getVariable(0).connect(method.getResult());
break;
case "getClass":
achieveGetClass(agent, method);
break;
case "wrap":
method.getVariable(1).connect(method.getResult());
break;
}
}
private void generateInit(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append(context.getParameterName(0)).append(".$id = $rt_nextId();").softNewLine();
}
private void generateGetClass(InjectorContext context) throws IOException {
SourceWriter writer = context.getWriter();
writer.append("$rt_cls(");
context.writeExpr(context.getArgument(0));
writer.append(".constructor)");
}
private void achieveGetClass(DependencyAgent agent, MethodDependency method) {
MethodReference initMethod = new MethodReference(Class.class, "createNew", Class.class);
agent.linkMethod(initMethod, null).use();
method.getResult().propagate(agent.getType("java.lang.Class"));
}
private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("return ").append(context.getParameterName(0)).append(".$id;").softNewLine();
}
private void generateClone(GeneratorContext context, SourceWriter writer) throws IOException {
String obj = context.getParameterName(0);
writer.append("var copy = new ").append(obj).append(".constructor();").softNewLine();
writer.append("for (var field in " + obj + ") {").softNewLine().indent();
writer.append("if (!" + obj + ".hasOwnProperty(field)) {").softNewLine().indent();
writer.append("continue;").softNewLine().outdent().append("}").softNewLine();
writer.append("copy[field] = " + obj + "[field];").softNewLine().outdent().append("}").softNewLine();
writer.append("return copy;").softNewLine();
}
private void generateWrap(InjectorContext context) throws IOException {
context.writeExpr(context.getArgument(0));
}
}

View File

@ -18,8 +18,8 @@ package org.teavm.classlib.java.lang;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
@ -48,9 +48,6 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
.appendField(new FieldReference("java.lang.System", "err"))
.ws().append('=').ws().append(context.getParameterName(1)).append(";").softNewLine();
break;
case "identityHashCode":
writer.append("return ").append(context.getParameterName(1)).append(".$id;").softNewLine();
break;
}
}

View File

@ -16,7 +16,6 @@
package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.javascript.ni.GeneratedBy;
/**
*
@ -80,7 +79,6 @@ public class TBoolean extends TObject implements TSerializable, TComparable<TBoo
}
@Override
@GeneratedBy(ObjectNativeGenerator.class)
public int hashCode() {
return value ? 1231 : 1237;
}

View File

@ -17,8 +17,9 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.impl.charset.UTF16Helper;
import org.teavm.classlib.impl.unicode.UnicodeHelper;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.platform.Platform;
import org.teavm.platform.metadata.MetadataProvider;
import org.teavm.platform.metadata.StringResource;
/**
*
@ -222,18 +223,21 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
return UTF16Helper.lowSurrogate(codePoint);
}
// TODO: implement toLowerCase/toUpperCase/toTitleCase using UnicodeData.txt instead of built-in JS
@GeneratedBy(CharacterNativeGenerator.class)
public static native char toLowerCase(char ch);
public static char toLowerCase(char ch) {
return (char)toLowerCase((int)ch);
}
@GeneratedBy(CharacterNativeGenerator.class)
public static native int toLowerCase(int ch);
public static int toLowerCase(int ch) {
return Platform.stringFromCharCode(ch).toLowerCase().charCodeAt(0);
}
@GeneratedBy(CharacterNativeGenerator.class)
public static native char toUpperCase(char ch);
public static char toUpperCase(char ch) {
return (char)toUpperCase((int)ch);
}
@GeneratedBy(CharacterNativeGenerator.class)
public static native int toUpperCase(int codePoint);
public static int toUpperCase(int codePoint) {
return Platform.stringFromCharCode(codePoint).toUpperCase().charCodeAt(0);
}
public static int digit(char ch, int radix) {
return digit((int)ch, radix);
@ -286,25 +290,23 @@ public class TCharacter extends TObject implements TComparable<TCharacter> {
private static int[] getDigitMapping() {
if (digitMapping == null) {
digitMapping = UnicodeHelper.decodeIntByte(obtainDigitMapping());
digitMapping = UnicodeHelper.decodeIntByte(obtainDigitMapping().getValue());
}
return digitMapping;
}
@GeneratedBy(CharacterNativeGenerator.class)
@PluggableDependency(CharacterNativeGenerator.class)
private static native String obtainDigitMapping();
@MetadataProvider(CharacterMetadataGenerator.class)
private static native StringResource obtainDigitMapping();
private static UnicodeHelper.Range[] getClasses() {
if (classMapping == null) {
classMapping = UnicodeHelper.extractRle(obtainClasses());
classMapping = UnicodeHelper.extractRle(obtainClasses().getValue());
}
return classMapping;
}
@GeneratedBy(CharacterNativeGenerator.class)
@PluggableDependency(CharacterNativeGenerator.class)
private static native String obtainClasses();
@MetadataProvider(CharacterMetadataGenerator.class)
private static native StringResource obtainClasses();
public static int toChars(int codePoint, char[] dst, int dstIndex) {
if (codePoint >= UTF16Helper.SUPPLEMENTARY_PLANE) {

View File

@ -15,9 +15,11 @@
*/
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.classlib.impl.DeclaringClassMetadataGenerator;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformClass;
import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
/**
*
@ -25,113 +27,130 @@ import org.teavm.javascript.ni.InjectedBy;
*/
public class TClass<T> extends TObject {
TString name;
TString binaryName;
boolean primitive;
boolean array;
boolean isEnum;
private TClass<?> componentType;
private boolean componentTypeDirty = true;
private PlatformClass platformClass;
static TClass<?> createNew() {
return new TClass<>();
private TClass(PlatformClass platformClass) {
this.platformClass = platformClass;
platformClass.setJavaClass(Platform.getPlatformObject(this));
}
@InjectedBy(ClassNativeGenerator.class)
public native boolean isInstance(TObject obj);
public static TClass<?> getClass(PlatformClass cls) {
if (cls == null) {
return null;
}
TClass<?> result = (TClass<?>)(Object)Platform.asJavaClass(cls.getJavaClass());
if (result == null) {
result = new TClass<>(cls);
}
return result;
}
@InjectedBy(ClassNativeGenerator.class)
public native boolean isAssignableFrom(TClass<?> obj);
public PlatformClass getPlatformClass() {
return platformClass;
}
public boolean isInstance(TObject obj) {
return Platform.isInstance(Platform.getPlatformObject(obj), platformClass);
}
public boolean isAssignableFrom(TClass<?> obj) {
return Platform.isAssignable(obj.getPlatformClass(), platformClass);
}
@PluggableDependency(ClassNativeGenerator.class)
public TString getName() {
if (name == null) {
name = TString.wrap(platformClass.getMetadata().getName());
}
return name;
}
public boolean isPrimitive() {
return primitive;
return platformClass.getMetadata().isPrimitive();
}
public boolean isArray() {
return array;
return platformClass.getMetadata().getArrayItem() != null;
}
public boolean isEnum() {
return isEnum;
return platformClass.getMetadata().isEnum();
}
public TClass<?> getComponentType() {
if (componentTypeDirty) {
componentType = getComponentType0();
PlatformClass arrayItem = platformClass.getMetadata().getArrayItem();
componentType = arrayItem != null ? getClass(arrayItem) : null;
componentTypeDirty = false;
}
return componentType;
}
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
private native TClass<?> getComponentType0();
@SuppressWarnings("unchecked")
static TClass<TVoid> voidClass() {
return (TClass<TVoid>)getClass(Platform.getPrimitives().getVoidClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TVoid> voidClass();
@SuppressWarnings("unchecked")
static TClass<TBoolean> booleanClass() {
return (TClass<TBoolean>)getClass(Platform.getPrimitives().getBooleanClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TBoolean> booleanClass();
@SuppressWarnings("unchecked")
static TClass<TCharacter> charClass() {
return (TClass<TCharacter>)getClass(Platform.getPrimitives().getCharClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TCharacter> charClass();
@SuppressWarnings("unchecked")
static TClass<TByte> byteClass() {
return (TClass<TByte>)getClass(Platform.getPrimitives().getByteClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TByte> byteClass();
@SuppressWarnings("unchecked")
static TClass<TShort> shortClass() {
return (TClass<TShort>)getClass(Platform.getPrimitives().getShortClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TShort> shortClass();
@SuppressWarnings("unchecked")
static TClass<TInteger> intClass() {
return (TClass<TInteger>)getClass(Platform.getPrimitives().getIntClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TInteger> intClass();
@SuppressWarnings("unchecked")
static TClass<TLong> longClass() {
return (TClass<TLong>)getClass(Platform.getPrimitives().getLongClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TLong> longClass();
@SuppressWarnings("unchecked")
static TClass<TFloat> floatClass() {
return (TClass<TFloat>)getClass(Platform.getPrimitives().getFloatClass());
}
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TFloat> floatClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
static native TClass<TDouble> doubleClass();
@InjectedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public static native <S extends TObject> TClass<S> wrapClass(Class<S> cls);
@SuppressWarnings("unchecked")
static TClass<TDouble> doubleClass() {
return (TClass<TDouble>)getClass(Platform.getPrimitives().getDoubleClass());
}
public boolean desiredAssertionStatus() {
return true;
}
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public native TClass<? super T> getSuperclass();
public T[] getEnumConstants() {
return isEnum ? getEnumConstantsImpl() : null;
@SuppressWarnings("unchecked")
public TClass<? super T> getSuperclass() {
return (TClass<? super T>)getClass(platformClass.getMetadata().getSuperclass());
}
@InjectedBy(ClassNativeGenerator.class)
public native T[] getEnumConstantsImpl();
@SuppressWarnings("unchecked")
public T[] getEnumConstants() {
return isEnum() ? (T[])Platform.getEnumConstants(platformClass) : null;
}
@SuppressWarnings("unchecked")
public T cast(TObject obj) {
if (obj != null && !isAssignableFrom(TClass.wrapClass(obj.getClass()))) {
throw new TClassCastException(TString.wrap(new TStringBuilder()
.append(TClass.wrapClass(obj.getClass()).getName())
.append(TString.wrap(" is not subtype of ")).append(name).toString()));
if (obj != null && !isAssignableFrom((TClass<?>)(Object)obj.getClass())) {
throw new TClassCastException(TString.wrap(obj.getClass().getName() +
" is not subtype of " + name));
}
return (T)obj;
}
@ -140,16 +159,12 @@ public class TClass<T> extends TObject {
return TClassLoader.getSystemClassLoader();
}
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
private static native TClass<?> forNameImpl(TString name);
public static TClass<?> forName(TString name) throws TClassNotFoundException {
TClass<?> result = forNameImpl(name);
if (result == null) {
PlatformClass cls = Platform.lookupClass(name.toString());
if (cls == null) {
throw new TClassNotFoundException();
}
return result;
return getClass(cls);
}
@SuppressWarnings("unused")
@ -158,13 +173,22 @@ public class TClass<T> extends TObject {
return forName(name);
}
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public native T newInstance() throws TInstantiationException, TIllegalAccessException;
@SuppressWarnings("unchecked")
public T newInstance() throws TInstantiationException, TIllegalAccessException {
Object instance = Platform.newInstance(platformClass);
if (instance == null) {
throw new TInstantiationException();
}
return (T)instance;
}
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public native TClass<?> getDeclaringClass();
public TClass<?> getDeclaringClass() {
ClassResource res = getDeclaringClass(platformClass);
return res != null ? getClass(Platform.classFromResource(res)) : null;
}
@ClassScopedMetadataProvider(DeclaringClassMetadataGenerator.class)
private static native ClassResource getDeclaringClass(PlatformClass cls);
@SuppressWarnings("unchecked")
public <U> TClass<? extends U> asSubclass(TClass<U> clazz) {

View File

@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TIOException;
import org.teavm.classlib.java.io.TOutputStream;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.platform.Platform;
/**
*
@ -25,6 +25,7 @@ import org.teavm.javascript.ni.GeneratedBy;
*/
class TConsoleOutputStream_stderr extends TOutputStream {
@Override
@GeneratedBy(ConsoleOutputStreamGenerator.class)
public native void write(int b) throws TIOException;
public void write(int b) throws TIOException {
Platform.getConsole().error(b);
}
}

View File

@ -17,7 +17,7 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TIOException;
import org.teavm.classlib.java.io.TOutputStream;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.platform.Platform;
/**
*
@ -25,6 +25,7 @@ import org.teavm.javascript.ni.GeneratedBy;
*/
class TConsoleOutputStream_stdout extends TOutputStream {
@Override
@GeneratedBy(ConsoleOutputStreamGenerator.class)
public native void write(int b) throws TIOException;
public void write(int b) throws TIOException {
Platform.getConsole().output(b);
}
}

View File

@ -15,8 +15,8 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.InjectedBy;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.InjectedBy;
/**
*

View File

@ -16,7 +16,7 @@
package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
*
@ -61,7 +61,7 @@ public abstract class TEnum<E extends TEnum<E>> extends TObject implements TComp
@SuppressWarnings("unchecked")
public final TClass<E> getDeclaringClass() {
return (TClass<E>)TClass.wrapClass(getClass());
return (TClass<E>)(Object)getClass();
}
@Override

View File

@ -15,7 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

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

View File

@ -15,7 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -15,7 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -15,11 +15,15 @@
*/
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.dom.browser.TimerHandler;
import org.teavm.javascript.spi.Async;
import org.teavm.javascript.spi.Rename;
import org.teavm.javascript.spi.Superclass;
import org.teavm.javascript.spi.Sync;
import org.teavm.platform.Platform;
import org.teavm.platform.PlatformQueue;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
/**
*
@ -27,22 +31,121 @@ import org.teavm.javascript.ni.Superclass;
*/
@Superclass("")
public class TObject {
Monitor monitor;
static class Monitor {
PlatformQueue<PlatformRunnable> enteringThreads;
PlatformQueue<NotifyListener> notifyListeners;
TThread owner;
int count;
public Monitor() {
this.owner = TThread.currentThread();
enteringThreads = Platform.createQueue();
notifyListeners = Platform.createQueue();
}
}
interface NotifyListener extends PlatformRunnable {
boolean expired();
}
static void monitorEnter(TObject o) {
monitorEnter(o, 1);
}
@Async
static native void monitorEnter(TObject o, int count);
static void monitorEnter(final TObject o, final int count, final AsyncCallback<Void> callback) {
if (o.monitor == null) {
o.monitor = new Monitor();
}
if (o.monitor.owner == null) {
o.monitor.owner = TThread.currentThread();
}
if (o.monitor.owner != TThread.currentThread()) {
final TThread thread = TThread.currentThread();
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
}
});
} else {
o.monitor.count += count;
callback.complete(null);
}
}
@Sync
static void monitorExit(final TObject o) {
monitorExit(o, 1);
}
@Sync
static void monitorExit(final TObject o, int count) {
if (o.isEmptyMonitor() || o.monitor.owner != TThread.currentThread()) {
throw new TIllegalMonitorStateException();
}
o.monitor.count -= count;
if (o.monitor.count > 0) {
return;
}
o.monitor.owner = null;
if (!o.monitor.enteringThreads.isEmpty()) {
Platform.startThread(new PlatformRunnable() {
@Override public void run() {
if (o.isEmptyMonitor() || o.monitor.owner != null) {
return;
}
if (!o.monitor.enteringThreads.isEmpty()) {
o.monitor.enteringThreads.remove().run();
}
}
});
} else {
o.isEmptyMonitor();
}
}
boolean isEmptyMonitor() {
if (monitor == null) {
return true;
}
if (monitor.owner == null && monitor.enteringThreads.isEmpty() && monitor.notifyListeners.isEmpty()) {
monitor = null;
return true;
} else {
return false;
}
}
static boolean holdsLock(TObject o) {
return o.monitor != null && o.monitor.owner == TThread.currentThread();
}
@Rename("fakeInit")
public TObject() {
}
@GeneratedBy(ObjectNativeGenerator.class)
@Rename("<init>")
private native void init();
private void init() {
Platform.getPlatformObject(this).setId(Platform.nextObjectId());
}
@InjectedBy(ObjectNativeGenerator.class)
@Rename("getClass")
@PluggableDependency(ObjectNativeGenerator.class)
public native final TClass<?> getClass0();
public final TClass<?> getClass0() {
return TClass.getClass(Platform.getPlatformObject(this).getPlatformClass());
}
@Override
@GeneratedBy(ObjectNativeGenerator.class)
public native int hashCode();
public int hashCode() {
return identity();
}
@Rename("equals")
public boolean equals0(TObject other) {
@ -54,41 +157,134 @@ public class TObject {
return getClass().getName() + "@" + TInteger.toHexString(identity());
}
@GeneratedBy(ObjectNativeGenerator.class)
native int identity();
int identity() {
return Platform.getPlatformObject(this).getId();
}
@GeneratedBy(ObjectNativeGenerator.class)
@PluggableDependency(ObjectNativeGenerator.class)
@Override
protected native Object clone() throws TCloneNotSupportedException;
protected Object clone() throws TCloneNotSupportedException {
if (!(this instanceof TCloneable) && Platform.getPlatformObject(this)
.getPlatformClass().getMetadata().getArrayItem() == null) {
throw new TCloneNotSupportedException();
}
Object result = Platform.clone(this);
Platform.getPlatformObject(result).setId(Platform.nextObjectId());
return result;
}
@Sync
@Rename("notify")
public final void notify0() {
if (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
TThread thread = TThread.currentThread();
PlatformQueue<NotifyListener> listeners = monitor.notifyListeners;
while (!listeners.isEmpty()) {
NotifyListener listener = listeners.remove();
if (!listener.expired()) {
Platform.startThread(listener);
break;
}
}
TThread.setCurrentThread(thread);
}
@Sync
@Rename("notifyAll")
public final void notifyAll0() {
if (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
PlatformQueue<NotifyListener> listeners = monitor.notifyListeners;
while (!listeners.isEmpty()) {
NotifyListener listener = listeners.remove();
if (!listener.expired()) {
Platform.startThread(listener);
}
}
}
@SuppressWarnings("unused")
@Rename("wait")
public final void wait0(long timeout) throws TInterruptedException{
try {
wait(timeout, 0);
} catch (InterruptedException ex) {
throw new TInterruptedException();
}
}
@SuppressWarnings("unused")
@Async
@Rename("wait")
public final void wait0(long timeout, int nanos) throws TInterruptedException {
private 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 (!holdsLock(this)) {
throw new TIllegalMonitorStateException();
}
final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count);
monitor.notifyListeners.add(listener);
if (timeout > 0 || nanos > 0) {
listener.timerId = Platform.schedule(listener, timeout >= Integer.MAX_VALUE ? Integer.MAX_VALUE :
(int)timeout);
}
monitorExit(this, monitor.count);
}
private static class NotifyListenerImpl implements NotifyListener, TimerHandler, PlatformRunnable {
final TObject obj;
final AsyncCallback<Void> callback;
final TThread currentThread = TThread.currentThread();
int timerId = -1;
boolean expired;
int lockCount;
public NotifyListenerImpl(TObject obj, AsyncCallback<Void> callback, int lockCount) {
this.obj = obj;
this.callback = callback;
this.lockCount = lockCount;
}
@Override
public boolean expired() {
boolean result = expired;
expired = true;
return result;
}
@Override
public void onTimer() {
if (!expired()) {
Platform.startThread(this);
}
}
@Override
public void run() {
if (timerId >= 0) {
Platform.killSchedule(timerId);
timerId = -1;
}
TThread.setCurrentThread(currentThread);
monitorEnter(obj, lockCount, callback);
}
}
@Rename("wait")
public final void wait0() throws TInterruptedException {
try {
wait(0l);
} catch (InterruptedException ex) {
throw new TInterruptedException();
}
}
@Override
protected void finalize() throws TThrowable {
}
@InjectedBy(ObjectNativeGenerator.class)
@PluggableDependency(ObjectNativeGenerator.class)
public static native TObject wrap(Object obj);
public static TObject wrap(Object obj) {
return (TObject)obj;
}
}

View File

@ -15,7 +15,7 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.javascript.ni.Superclass;
import org.teavm.javascript.spi.Superclass;
/**
*

View File

@ -23,8 +23,6 @@ import org.teavm.classlib.java.util.TComparator;
import org.teavm.classlib.java.util.THashMap;
import org.teavm.classlib.java.util.TMap;
import org.teavm.classlib.java.util.regex.TPattern;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.InjectedBy;
/**
*
@ -592,9 +590,9 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
return hashCode;
}
@InjectedBy(StringNativeGenerator.class)
@PluggableDependency(StringNativeGenerator.class)
public static native TString wrap(String str);
public static TString wrap(String str) {
return (TString)(Object)str;
}
public TString toLowerCase() {
if (isEmpty()) {

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TPrintStream;
import org.teavm.classlib.java.lang.reflect.TArray;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*
@ -47,6 +47,15 @@ public final class TSystem extends TObject {
}
if (srcType != targetType) {
if (!srcType.isPrimitive() && !targetType.isPrimitive()) {
Object[] srcArray = (Object[])(Object)src;
int pos = srcPos;
for (int i = 0; i < length; ++i) {
Object elem = srcArray[pos++];
if (!targetType.isInstance(elem)) {
doArrayCopy(src, srcPos, dest, destPos, i);
throw new TArrayStoreException();
}
}
doArrayCopy(src, srcPos, dest, destPos, length);
return;
} else if (!srcType.isPrimitive() || !targetType.isPrimitive()) {
@ -93,9 +102,9 @@ public final class TSystem extends TObject {
return currentTimeMillis() * 10000000;
}
@GeneratedBy(SystemNativeGenerator.class)
@PluggableDependency(SystemNativeGenerator.class)
public static native int identityHashCode(Object x);
public static int identityHashCode(Object x) {
return ((TObject)x).identity();
}
public static TString lineSeparator() {
return TString.wrap("\n");

View File

@ -15,30 +15,70 @@
*/
package org.teavm.classlib.java.lang;
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.Platform;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
/**
*
* @author Alexey Andreev
*/
public class TThread extends TObject implements TRunnable {
private static TThread currentThread = new TThread(TString.wrap("main"));
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 int priority = 0;
private TString name;
private TRunnable target;
TRunnable target;
public TThread() {
this(null, null);
}
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++;
}
public void start(){
Platform.startThread(new PlatformRunnable() {
@Override
public void run() {
try {
activeCount++;
setCurrentThread(TThread.this);
TThread.this.run();
} finally {
activeCount--;
setCurrentThread(mainThread);
}
}
});
}
static void setCurrentThread(TThread thread){
currentThread = thread;
}
static TThread getMainThread(){
return mainThread;
}
@Override
@ -56,7 +96,11 @@ public class TThread extends TObject implements TRunnable {
return name;
}
public static void yield() {
@Async
public static native void yield();
private static void yield(final AsyncCallback<Void> callback) {
callback.complete(null);
}
public void interrupt() {
@ -71,14 +115,36 @@ 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) {
return true;
public static boolean holdsLock(TObject obj) {
return TObject.holdsLock(obj);
}
@Async
public static native void sleep(long millis) throws TInterruptedException;
private static void sleep(long millis, final AsyncCallback<Void> callback) {
final TThread current = currentThread();
window.setTimeout(new TimerHandler() {
@Override public void onTimer() {
setCurrentThread(current);
callback.complete(null);
}
}, millis);
}
public final void setPriority(int newPriority){
this.priority = newPriority;
}
public final int getPriority(){
return this.priority;
}
}

View File

@ -17,9 +17,9 @@ package org.teavm.classlib.java.lang;
import org.teavm.classlib.java.io.TPrintStream;
import org.teavm.classlib.java.util.TArrays;
import org.teavm.javascript.ni.Remove;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.ni.Superclass;
import org.teavm.javascript.spi.Remove;
import org.teavm.javascript.spi.Rename;
import org.teavm.javascript.spi.Superclass;
/**
*
@ -101,7 +101,7 @@ public class TThrowable extends RuntimeException {
}
@Override
public synchronized Throwable fillInStackTrace() {
public Throwable fillInStackTrace() {
return this;
}
@ -116,7 +116,7 @@ public class TThrowable extends RuntimeException {
}
@Override
public synchronized TThrowable getCause() {
public TThrowable getCause() {
return cause != this ? cause : null;
}
@ -126,7 +126,7 @@ public class TThrowable extends RuntimeException {
@Remove
public native TString toString0();
public synchronized TThrowable initCause(TThrowable cause) {
public TThrowable initCause(TThrowable cause) {
if (this.cause != this && this.cause != null) {
throw new TIllegalStateException(TString.wrap("Cause already set"));
}

View File

@ -18,8 +18,8 @@ package org.teavm.classlib.java.lang.reflect;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.dependency.*;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.MethodDescriptor;
@ -93,15 +93,14 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin {
private void generateNewInstance(GeneratorContext context, SourceWriter writer) throws IOException {
String type = context.getParameterName(1);
String length = context.getParameterName(2);
writer.append("var cls = " + type + ".$data;").softNewLine();
writer.append("if (cls.primitive) {").softNewLine().indent();
writer.append("if (").append(type).append(".$meta.primitive) {").softNewLine().indent();
for (String primitive : primitives) {
writer.append("if (cls == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine();
writer.append("if (" + type + " == $rt_" + primitive.toLowerCase() + "cls()) {").indent().softNewLine();
writer.append("return $rt_create" + primitive + "Array(" + length + ");").softNewLine();
writer.outdent().append("}").softNewLine();
}
writer.outdent().append("} else {").indent().softNewLine();
writer.append("return $rt_createArray(cls, " + length + ")").softNewLine();
writer.append("return $rt_createArray(" + type + ", " + length + ")").softNewLine();
writer.outdent().append("}").softNewLine();
}

View File

@ -17,7 +17,8 @@ package org.teavm.classlib.java.lang.reflect;
import org.teavm.classlib.java.lang.*;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.platform.PlatformClass;
/**
*
@ -38,12 +39,12 @@ public final class TArray extends TObject {
if (length < 0) {
throw new TNegativeArraySizeException();
}
return newInstanceImpl(componentType, length);
return newInstanceImpl(componentType.getPlatformClass(), length);
}
@GeneratedBy(ArrayNativeGenerator.class)
@PluggableDependency(ArrayNativeGenerator.class)
private static native TObject newInstanceImpl(TClass<?> componentType, int length);
private static native TObject newInstanceImpl(PlatformClass componentType, int length);
public static TObject get(TObject array, int index) throws TIllegalArgumentException,
TArrayIndexOutOfBoundsException {

View File

@ -21,7 +21,7 @@ import org.teavm.classlib.java.lang.TException;
import org.teavm.classlib.java.lang.TIllegalArgumentException;
import org.teavm.classlib.java.lang.TNullPointerException;
import org.teavm.classlib.java.lang.TString;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
* A {@code URISyntaxException} will be thrown if some information could not be parsed

View File

@ -20,8 +20,8 @@ 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.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;

View File

@ -17,8 +17,8 @@ package org.teavm.classlib.java.util;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -16,7 +16,7 @@
package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.*;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
*

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.util;
import java.util.Arrays;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.*;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
*

View File

@ -17,7 +17,7 @@ package org.teavm.classlib.java.util;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.*;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
*

View File

@ -293,7 +293,7 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
return value;
}
public static synchronized TLocale[] getAvailableLocales() {
public static TLocale[] getAvailableLocales() {
return TLocale.getAvailableLocales();
}
@ -303,11 +303,11 @@ public abstract class TCalendar implements TSerializable, TCloneable, TComparabl
abstract public int getGreatestMinimum(int field);
public static synchronized TCalendar getInstance() {
public static TCalendar getInstance() {
return new TGregorianCalendar();
}
public static synchronized TCalendar getInstance(TLocale locale) {
public static TCalendar getInstance(TLocale locale) {
return new TGregorianCalendar(locale);
}

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.TComparable;
import org.teavm.classlib.java.lang.TSystem;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -35,13 +35,10 @@ package org.teavm.classlib.java.util;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneNotSupportedException;
import org.teavm.classlib.java.lang.TIllegalArgumentException;
import org.teavm.classlib.java.lang.TIllegalStateException;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.javascript.ni.Rename;
import org.teavm.classlib.java.lang.*;
import org.teavm.javascript.spi.Rename;
public class THashMap<K, V> extends TAbstractMap<K, V> implements TSerializable {
public class THashMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TSerializable {
transient int elementCount;
transient HashEntry<K, V>[] elementData;
transient int modCount = 0;

View File

@ -20,7 +20,7 @@ import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneNotSupportedException;
import org.teavm.classlib.java.lang.TCloneable;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.javascript.ni.Rename;
import org.teavm.javascript.spi.Rename;
/**
*

View File

@ -244,11 +244,11 @@ public final class TLocale implements TCloneable, TSerializable {
}
@Override
public synchronized int hashCode() {
public int hashCode() {
return countryCode.hashCode() + languageCode.hashCode() + variantCode.hashCode();
}
public synchronized static void setDefault(TLocale locale) {
public static void setDefault(TLocale locale) {
if (locale != null) {
defaultLocale = locale;
} else {

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.util;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TMath;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -16,6 +16,7 @@
package org.teavm.classlib.java.util;
import org.teavm.classlib.java.lang.*;
import org.teavm.platform.PlatformClass;
/**
*
@ -48,7 +49,7 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
}
public static <S> TServiceLoader<S> load(TClass<S> service) {
return new TServiceLoader<>(loadServices(service));
return new TServiceLoader<>(loadServices(service.getPlatformClass()));
}
public static <S> TServiceLoader<S> load(TClass<S> service, @SuppressWarnings("unused") TClassLoader loader) {
@ -59,7 +60,7 @@ public final class TServiceLoader<S> extends TObject implements TIterable<S> {
return load(service);
}
private static native <T> T[] loadServices(TClass<T> serviceType);
private static native <T> T[] loadServices(PlatformClass cls);
public void reload() {
// Do nothing, services are bound at build time

View File

@ -19,7 +19,7 @@ import org.teavm.classlib.java.lang.TIllegalStateException;
import org.teavm.classlib.java.lang.TObject;
import org.teavm.classlib.java.lang.TString;
import org.teavm.dependency.PluggableDependency;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -21,8 +21,8 @@ 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.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;

View File

@ -17,8 +17,8 @@ package org.teavm.classlib.java.util.logging;
import java.io.IOException;
import org.teavm.codegen.SourceWriter;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.GeneratorContext;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.GeneratorContext;
import org.teavm.model.MethodReference;
/**

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.util.logging;
import org.teavm.classlib.java.lang.*;
import org.teavm.classlib.java.util.THashMap;
import org.teavm.classlib.java.util.TMap;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.spi.GeneratedBy;
/**
*

View File

@ -109,7 +109,7 @@ class TDecomposedCharSet extends TJointSet {
* Read testString until we met a decomposed char boundary and
* decompose obtained portion of testString
*/
while ((readCodePoints < TLexer.MAX_DECOMPOSITION_LENGTH) && !TLexer.isDecomposedCharBoundary(curChar)) {
while ((readCodePoints < TLexer.MAX_DECOMPOSITION_LENGTH)) {
if (TLexer.hasDecompositionNonNullCanClass(curChar)) {
@ -146,30 +146,6 @@ class TDecomposedCharSet extends TJointSet {
}
}
/*
* Some optimization since length of decomposed char is <= 3 usually
*/
switch (readCodePoints) {
case 0:
case 1:
case 2:
break;
case 3:
int i1 = TLexer.getCanonicalClass(decCodePoint[1]);
int i2 = TLexer.getCanonicalClass(decCodePoint[2]);
if ((i2 != 0) && (i1 > i2)) {
i1 = decCodePoint[1];
decCodePoint[1] = decCodePoint[2];
decCodePoint[2] = i1;
}
break;
default:
decCodePoint = TLexer.getCanonicalOrder(decCodePoint, readCodePoints);
}
/*
* Compare decomposedChar with decomposed char that was just read from
* testString

View File

@ -146,12 +146,6 @@ class TLexer {
// table that contains canonical decomposition mappings
private static TIntArrHash decompTable = null;
// table that contains canonical combining classes
private static TIntHash canonClassesTable = null;
private static int canonClassesTableSize;
/*
* Table that contains information about Unicode codepoints with single
* codepoint decomposition
@ -330,51 +324,6 @@ class TLexer {
return input;
}
/**
* Rearrange codepoints according to canonical order.
*
* @param inputInts
* - array that contains Unicode codepoints
* @param length
* - index of last Unicode codepoint plus 1
*
* @return array that contains rearranged codepoints.
*/
static int[] getCanonicalOrder(int[] inputInts, int length) {
int inputLength = (length < inputInts.length) ? length : inputInts.length;
/*
* Simple bubble-sort algorithm. Note that many codepoints have 0
* canonical class, so this algorithm works almost lineary in
* overwhelming majority of cases. This is due to specific of Unicode
* combining classes and codepoints.
*/
for (int i = 1; i < inputLength; i++) {
int j = i - 1;
int iCanonicalClass = getCanonicalClass(inputInts[i]);
int ch;
if (iCanonicalClass == 0) {
continue;
}
while (j > -1) {
if (getCanonicalClass(inputInts[j]) > iCanonicalClass) {
j = j - 1;
} else {
break;
}
}
ch = inputInts[i];
for (int k = i; k > j + 1; k--) {
inputInts[k] = inputInts[k - 1];
}
inputInts[j + 1] = ch;
}
return inputInts;
}
/**
* Reread current character, may be require if previous token changes mode
@ -1062,20 +1011,6 @@ class TLexer {
}
}
/**
* Gets canonical class for given codepoint from decomposition mappings
* table.
*
* @param - ch Unicode codepoint
* @return canonical class for given Unicode codepoint that is represented
* by ch.
*/
static int getCanonicalClass(int ch) {
int canClass = canonClassesTable.get(ch);
return (canClass == canonClassesTableSize) ? 0 : canClass;
}
/**
* Tests if given codepoint is a canonical decomposition of another
* codepoint.
@ -1126,23 +1061,6 @@ class TLexer {
return high;
}
/**
* Tests Unicode codepoint if it is a boundary of decomposed Unicode
* codepoint.
*
* @param ch
* - Unicode codepoint to test
* @return true if given codepoint is a boundary.
*/
static boolean isDecomposedCharBoundary(int ch) {
int canClass = canonClassesTable.get(ch);
// Lexer.getCanonicalClass(ch) == 0
boolean isBoundary = (canClass == canonClassesTableSize);
return isBoundary;
}
/**
* Returns the curr. character index.
*/

View File

@ -561,8 +561,7 @@ public final class TPattern implements Serializable {
} else {
readCodePoints++;
while ((readCodePoints < TLexer.MAX_DECOMPOSITION_LENGTH) && !lexemes.isEmpty() && lexemes.isLetter() &&
!TLexer.isDecomposedCharBoundary(lexemes.peek())) {
while ((readCodePoints < TLexer.MAX_DECOMPOSITION_LENGTH) && !lexemes.isEmpty() && lexemes.isLetter()) {
codePoints[readCodePoints++] = lexemes.next();
}

View File

@ -40,6 +40,11 @@
<groupId>org.ow2.asm</groupId>
<artifactId>asm-debug-all</artifactId>
</dependency>
<dependency>
<groupId>com.carrotsearch</groupId>
<artifactId>hppc</artifactId>
<version>0.6.1</version>
</dependency>
</dependencies>
<name>TeaVM core</name>

View File

@ -59,7 +59,6 @@ public class AstIO {
}
}
}
output.writeBoolean(method.isOriginalNamePreserved());
try {
method.getBody().acceptVisitor(new NodeWriter(output));
} catch (IOExceptionWrapper e) {
@ -83,7 +82,6 @@ public class AstIO {
}
node.getParameterDebugNames().add(debugNames);
}
node.setOriginalNamePreserved(input.readBoolean());
node.setBody(readStatement(input));
return node;
}
@ -306,6 +304,16 @@ public class AstIO {
}
}
@Override
public void visit(RestoreAsyncStatement statement) {
try {
output.writeByte(17);
output.writeShort(statement.getReceiver() != null ? statement.getReceiver() : -1);
} catch (IOException e) {
throw new IOExceptionWrapper(e);
}
}
@Override
public void visit(BinaryExpr expr) {
try {
@ -498,6 +506,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 {
@ -651,6 +669,12 @@ public class AstIO {
readSequence(input, stmt.getHandler());
return stmt;
}
case 17: {
short var = input.readShort();
RestoreAsyncStatement stmt = new RestoreAsyncStatement();
stmt.setReceiver(var >= 0 ? (int)var : null);
return stmt;
}
default:
throw new RuntimeException("Unexpected statement type: " + type);
}

View File

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

View File

@ -257,6 +257,20 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache {
@Override
public void visit(StaticClassExpr expr) {
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}
static class Item {

View File

@ -594,6 +594,28 @@ public class ProgramIO {
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 {
@ -898,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);
}

View File

@ -57,25 +57,16 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override
public String getNameFor(MethodReference method) {
MethodReference origMethod = method;
method = getRealMethod(method);
if (method == null) {
throw new NamingException("Can't provide name for method as it was not found: " + origMethod);
return getNameFor(method, 'S');
}
ClassReader clsHolder = classSource.get(method.getClassName());
MethodReader methodHolder = clsHolder.getMethod(method.getDescriptor());
if (methodHolder.hasModifier(ElementModifier.STATIC) ||
method.getDescriptor().getName().equals("<init>") ||
methodHolder.getLevel() == AccessLevel.PRIVATE) {
String key = method.toString();
String alias = privateAliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(method);
privateAliases.put(key, alias);
@Override
public String getNameForAsync(MethodReference method) throws NamingException {
return getNameFor(method, 'A');
}
return alias;
} else {
String key = method.getDescriptor().toString();
private String getNameFor(MethodReference method, char classifier) {
String key = classifier + method.getDescriptor().toString();
String alias = aliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(method);
@ -83,19 +74,32 @@ public class DefaultNamingStrategy implements NamingStrategy {
}
return alias;
}
}
@Override
public String getFullNameFor(MethodReference method) throws NamingException {
MethodReference originalMethod = method;
if (!minifying) {
return getNameFor(method.getClassName()) + "_" + getNameFor(method);
return getFullNameFor(method, 'S');
}
@Override
public String getFullNameForAsync(MethodReference method) throws NamingException {
return getFullNameFor(method, 'A');
}
@Override
public String getNameForInit(MethodReference method) throws NamingException {
return getFullNameFor(method, 'I');
}
private String getFullNameFor(MethodReference method, char classifier) throws NamingException {
MethodReference originalMethod = method;
method = getRealMethod(method);
if (method == null) {
throw new NamingException("Can't provide name for method as it was not found: " + originalMethod);
}
String key = method.toString();
if (!minifying) {
return getNameFor(method.getClassName()) + "_" + getNameFor(method, classifier);
}
String key = classifier + method.toString();
String alias = privateAliases.get(key);
if (alias == null) {
alias = aliasProvider.getAlias(method);

View File

@ -27,7 +27,13 @@ public interface NamingStrategy {
String getNameFor(MethodReference method) throws NamingException;
String getNameForAsync(MethodReference method) throws NamingException;
String getNameForInit(MethodReference method) throws NamingException;
String getFullNameFor(MethodReference method) throws NamingException;
String getFullNameForAsync(MethodReference method) throws NamingException;
String getNameFor(FieldReference field) throws NamingException;
}

View File

@ -103,6 +103,10 @@ public class SourceWriter implements Appendable, LocationProvider {
return append(naming.getNameFor(cls));
}
public SourceWriter appendClass(Class<?> cls) throws NamingException, IOException {
return append(naming.getNameFor(cls.getName()));
}
public SourceWriter appendField(FieldReference field) throws NamingException, IOException {
return append(naming.getNameFor(field));
}
@ -113,7 +117,12 @@ public class SourceWriter implements Appendable, LocationProvider {
public SourceWriter appendMethod(String className, String name, ValueType... params)
throws NamingException, IOException {
return append(naming.getNameFor(new MethodReference(className, new MethodDescriptor(name, params))));
return append(naming.getNameFor(new MethodReference(className, name, params)));
}
public SourceWriter appendMethod(Class<?> cls, String name, Class<?>... params)
throws NamingException, IOException {
return append(naming.getNameFor(new MethodReference(cls, name, params)));
}
public SourceWriter appendMethodBody(MethodReference method) throws NamingException, IOException {
@ -125,6 +134,11 @@ public class SourceWriter implements Appendable, LocationProvider {
return append(naming.getFullNameFor(new MethodReference(className, new MethodDescriptor(name, params))));
}
public SourceWriter appendMethodBody(Class<?> cls, String name, Class<?>... params)
throws NamingException, IOException {
return append(naming.getFullNameFor(new MethodReference(cls, name, params)));
}
private void appendIndent() throws IOException {
if (minified) {
return;

View File

@ -0,0 +1,155 @@
/*
* 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.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class DJGraph {
private DominatorTree domTree;
private Graph graph;
private LCATree spanningTree;
private int[] spanningTreeNode;
private int[] spanningTreeIndex;
private int[][] levelContent;
public DJGraph(Graph src) {
domTree = GraphUtils.buildDominatorTree(src);
buildGraph(src);
buildLevels();
dfs();
}
private void buildGraph(Graph graph) {
GraphBuilder builder = new GraphBuilder(graph.size());
// Add join edges
for (int i = 0; i < graph.size(); ++i) {
for (int j : graph.outgoingEdges(i)) {
builder.addEdge(i, j);
}
}
// Add dom edges
for (int i = 1; i < graph.size(); ++i) {
int j = domTree.immediateDominatorOf(i);
builder.addEdge(j, i);
}
graph = builder.build();
}
private void buildLevels() {
List<IntegerArray> builder = new ArrayList<>();
for (int i = 0; i < graph.size(); ++i) {
int level = domTree.levelOf(i);
while (level >= builder.size()) {
builder.add(new IntegerArray(1));
}
builder.get(level).add(i);
}
levelContent = new int[builder.size()][];
for (int i = 0; i < builder.size(); ++i) {
levelContent[i] = builder.get(i).getAll();
}
}
private void dfs() {
spanningTreeNode = new int[graph.size()];
spanningTreeIndex = new int[graph.size()];
Arrays.fill(spanningTreeIndex, -1);
Arrays.fill(spanningTreeNode, -1);
boolean[] visited = new boolean[graph.size()];
IntegerStack stack = new IntegerStack(graph.size() * 2);
stack.push(0);
stack.push(-1);
while (!stack.isEmpty()) {
int node = stack.pop();
int source = stack.pop();
if (visited[node]) {
continue;
}
int index = spanningTree.addNode(spanningTreeIndex[source]);
spanningTreeNode[index] = node;
spanningTreeIndex[node] = index;
visited[node] = true;
for (int succ : graph.outgoingEdges(node)) {
stack.push(node);
stack.push(succ);
}
}
}
public DominatorTree getDomTree() {
return domTree;
}
public Graph getGraph() {
return graph;
}
public boolean isAncestorInSpanningTree(int anc, int node) {
anc = spanningTreeIndex[anc];
node = spanningTreeIndex[node];
if (anc < 0 || node < 0) {
return false;
}
return spanningTree.lcaOf(anc, node) == anc;
}
public boolean isDomEdge(int i, int j) {
return domTree.immediateDominatorOf(j) == i;
}
public boolean isJoinEdge(int i, int j) {
return !isDomEdge(i, j);
}
public boolean isBackJoin(int i, int j) {
return isJoinEdge(i, j) && !domTree.dominates(j, i);
}
public boolean isCrossJoin(int i, int j) {
return isJoinEdge(i, j) && domTree.dominates(j, i);
}
public boolean isSpanningBack(int i, int j) {
return spanningTree.lcaOf(i, j) == j;
}
public boolean isSpanningCross(int i, int j) {
int c = spanningTree.lcaOf(i, j);
return c != i && c != j;
}
public int levelOf(int node) {
return domTree.levelOf(node);
}
public int[] level(int level) {
int[] result = levelContent[level];
return Arrays.copyOf(result, result.length);
}
public int levelCount() {
return levelContent.length;
}
}

View File

@ -21,42 +21,42 @@ package org.teavm.common;
*/
class DefaultDominatorTree implements DominatorTree {
private LCATree lcaTree;
private int[] indexes;
private int[] nodes;
private int[] unodes;
public DefaultDominatorTree(int[] dominators, int[] vertices) {
lcaTree = new LCATree(dominators.length + 1);
indexes = new int[dominators.length + 1];
nodes = new int[dominators.length + 1];
unodes = new int[dominators.length + 1];
nodes[0] = -1;
indexes[0] = -1;
for (int i = 0; i < dominators.length; ++i) {
int v = vertices[i];
if (v < 0) {
continue;
}
int dom = nodes[dominators[v] + 1];
int dom = indexes[dominators[v] + 1];
int node = lcaTree.addNode(dom);
nodes[v + 1] = node;
unodes[node] = v;
indexes[v + 1] = node;
nodes[node] = v;
}
}
@Override
public boolean directlyDominates(int a, int b) {
a = nodes[a + 1];
b = nodes[b + 1];
a = indexes[a + 1];
b = indexes[b + 1];
return lcaTree.lcaOf(a, b) == a;
}
@Override
public int commonDominatorOf(int a, int b) {
return unodes[lcaTree.lcaOf(nodes[a + 1], nodes[b + 1])];
return nodes[lcaTree.lcaOf(indexes[a + 1], indexes[b + 1])];
}
@Override
public boolean dominates(int a, int b) {
a = nodes[a + 1];
b = nodes[b + 1];
a = indexes[a + 1];
b = indexes[b + 1];
return lcaTree.lcaOf(a, b) == a;
}
@ -65,7 +65,13 @@ class DefaultDominatorTree implements DominatorTree {
if (a == 0) {
return -1;
}
int result = lcaTree.parentOf(nodes[a + 1]);
return result >= 0 ? unodes[result] : -1;
int result = lcaTree.parentOf(indexes[a + 1]);
return result >= 0 ? nodes[result] : -1;
}
@Override
public int levelOf(int a) {
int index = indexes[a];
return lcaTree.depthOf(index);
}
}

View File

@ -27,4 +27,6 @@ public interface DominatorTree {
boolean dominates(int a, int b);
int immediateDominatorOf(int a);
int levelOf(int a);
}

View File

@ -15,6 +15,8 @@
*/
package org.teavm.common;
import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -26,14 +28,14 @@ import java.util.List;
*/
public class GraphBuilder {
private GraphImpl builtGraph;
private List<IntegerArray> addedEdges = new ArrayList<>();
private List<IntSet> addedEdges = new ArrayList<>();
private int sz;
public GraphBuilder() {
}
public GraphBuilder(int sz) {
addedEdges.addAll(Collections.<IntegerArray>nCopies(sz, null));
addedEdges.addAll(Collections.<IntSet>nCopies(sz, null));
this.sz = sz;
}
@ -49,14 +51,14 @@ public class GraphBuilder {
sz = Math.max(sz, Math.max(from, to) + 1);
builtGraph = null;
if (addedEdges.size() == from) {
addedEdges.add(IntegerArray.of(to));
addedEdges.add(IntOpenHashSet.from(to));
} else if (addedEdges.size() <= from) {
addedEdges.addAll(Collections.<IntegerArray>nCopies(from - addedEdges.size(), null));
addedEdges.add(IntegerArray.of(to));
addedEdges.addAll(Collections.<IntSet>nCopies(from - addedEdges.size(), null));
addedEdges.add(IntOpenHashSet.from(to));
} else {
IntegerArray set = addedEdges.get(from);
IntSet set = addedEdges.get(from);
if (set == null) {
addedEdges.set(from, IntegerArray.of(to));
addedEdges.set(from, IntOpenHashSet.from(to));
} else {
set.add(to);
}
@ -65,14 +67,15 @@ public class GraphBuilder {
public Graph build() {
if (builtGraph == null) {
IntegerArray[] incomingEdges = new IntegerArray[sz];
IntSet[] incomingEdges = new IntSet[sz];
for (int i = 0; i < sz; ++i) {
incomingEdges[i] = new IntegerArray(1);
incomingEdges[i] = new IntOpenHashSet();
}
int[][] outgoingEdgeList = new int[sz][];
for (int i = 0; i < addedEdges.size(); ++i) {
IntegerArray edgeList = addedEdges.get(i);
outgoingEdgeList[i] = edgeList != null ? edgeList.getAll() : new int[0];
IntSet edgeList = addedEdges.get(i);
outgoingEdgeList[i] = edgeList != null ? edgeList.toArray() : new int[0];
Arrays.sort(outgoingEdgeList[i]);
for (int j : outgoingEdgeList[i]) {
incomingEdges[j].add(i);
}
@ -82,7 +85,8 @@ public class GraphBuilder {
}
int[][] incomingEdgeList = new int[sz][];
for (int i = 0; i < sz; ++i) {
incomingEdgeList[i] = incomingEdges[i].getAll();
incomingEdgeList[i] = incomingEdges[i].toArray();
Arrays.sort(incomingEdgeList[i]);
}
builtGraph = new GraphImpl(incomingEdgeList, outgoingEdgeList);
}

View File

@ -61,6 +61,10 @@ public class LCATree {
return path.length > 0 ? path[0] : -1;
}
public int depthOf(int node) {
return depths[node];
}
public int lcaOf(int a, int b) {
if (a == b) {
return a;

View File

@ -0,0 +1,97 @@
/*
* 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.common;
import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet;
import com.carrotsearch.hppc.cursors.IntCursor;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class MutableDirectedGraph implements Graph {
private List<IntSet> successors = new ArrayList<>();
private List<IntSet> predecessors = new ArrayList<>();
public MutableDirectedGraph() {
}
public MutableDirectedGraph(Graph graph) {
int[] data = new int[graph.size()];
for (int i = 0; i < graph.size(); ++i) {
int sz = graph.copyOutgoingEdges(i, data);
for (int j = 0; j < sz; ++j) {
addEdge(i, data[j]);
}
}
}
@Override
public int size() {
return successors.size();
}
public void addEdge(int from, int to) {
int max = Math.max(from, to);
while (max >= successors.size()) {
successors.add(new IntOpenHashSet(1));
predecessors.add(new IntOpenHashSet(1));
}
successors.get(from).add(to);
predecessors.get(to).add(from);
}
@Override
public int[] incomingEdges(int node) {
return predecessors.get(node).toArray();
}
@Override
public int copyIncomingEdges(int node, int[] target) {
int index = 0;
for (IntCursor cursor : predecessors.get(node)) {
target[index++] = cursor.value;
}
return index;
}
@Override
public int[] outgoingEdges(int node) {
return successors.get(node).toArray();
}
@Override
public int copyOutgoingEdges(int node, int[] target) {
int index = 0;
for (IntCursor cursor : successors.get(node)) {
target[index++] = cursor.value;
}
return index;
}
@Override
public int incomingEdgesCount(int node) {
return predecessors.get(node).size();
}
@Override
public int outgoingEdgesCount(int node) {
return successors.get(node).size();
}
}

View File

@ -205,7 +205,9 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
boolean added = true;
if (callLocation != null && callLocation.getMethod() != null) {
DefaultCallGraphNode callGraphNode = callGraph.getNode(callLocation.getMethod());
added = addClassAccess(callGraphNode, className, callLocation.getSourceLocation());
if (!addClassAccess(callGraphNode, className, callLocation.getSourceLocation())) {
added = false;
}
}
if (!dep.isMissing() && added) {
for (DependencyListener listener : listeners) {
@ -222,13 +224,13 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
ClassReader cls = classSource.get(className);
if (cls != null) {
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
return addClassAccess(node, cls.getParent(), loc);
addClassAccess(node, cls.getParent(), loc);
}
for (String iface : cls.getInterfaces()) {
return addClassAccess(node, iface, loc);
addClassAccess(node, iface, loc);
}
}
return false;
return true;
}
private ClassDependency createClassDependency(String className) {
@ -250,6 +252,10 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
if (methodRef == null) {
throw new IllegalArgumentException();
}
MethodReader methodReader = methodReaderCache.map(methodRef);
if (methodReader != null) {
methodRef = methodReader.getReference();
}
callGraph.getNode(methodRef);
boolean added = true;
if (callLocation != null && callLocation.getMethod() != null) {
@ -470,6 +476,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return methodCache.getKnown(methodRef);
}
@Override
public MethodDependency getMethodImplementation(MethodReference methodRef) {
MethodReader method = methodReaderCache.map(methodRef);
return method != null ? methodCache.getKnown(method.getReference()) : null;
}
public void processDependencies() {
interrupted = false;
int index = 0;

View File

@ -349,6 +349,7 @@ class DependencyGraphBuilder {
@Override
public void create(VariableReader receiver, String type) {
dependencyChecker.linkClass(type, new CallLocation(caller.getMethod(), currentLocation));
nodes[receiver.getIndex()].propagate(dependencyChecker.getType(type));
}
@ -427,8 +428,9 @@ class DependencyGraphBuilder {
private void invokeSpecial(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments) {
MethodDependency methodDep = dependencyChecker.linkMethod(method,
new CallLocation(caller.getMethod(), currentLocation));
CallLocation callLocation = new CallLocation(caller.getMethod(), currentLocation);
dependencyChecker.linkClass(method.getClassName(), callLocation).initClass(callLocation);
MethodDependency methodDep = dependencyChecker.linkMethod(method, callLocation);
if (methodDep.isMissing()) {
return;
}
@ -490,5 +492,21 @@ class DependencyGraphBuilder {
new CallLocation(caller.getMethod(), currentLocation)).use();
currentExceptionConsumer.consume(dependencyChecker.getType("java.lang.NullPointerException"));
}
@Override
public void monitorEnter(VariableReader objectRef) {
MethodDependency methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorEnter", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
}
@Override
public void monitorExit(VariableReader objectRef) {
MethodDependency methodDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "monitorExit", Object.class, void.class), null);
nodes[objectRef.getIndex()].connect(methodDep.getVariable(1));
methodDep.use();
}
};
}

View File

@ -40,6 +40,8 @@ public interface DependencyInfo {
MethodDependencyInfo getMethod(MethodReference methodRef);
MethodDependencyInfo getMethodImplementation(MethodReference methodRef);
ClassDependencyInfo getClass(String className);
CallGraph getCallGraph();

View File

@ -22,5 +22,5 @@ import org.teavm.model.CallLocation;
* @author Alexey Andreev
*/
public interface DependencyPlugin {
void methodAchieved(DependencyAgent checker, MethodDependency method, CallLocation location);
void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location);
}

View File

@ -0,0 +1,26 @@
/*
* 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;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public enum Associativity {
LEFT,
RIGHT,
NONE
}

View File

@ -0,0 +1,25 @@
/*
* 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;
/**
*
* @author Alexey Andreev
*/
public enum AsyncInvocationType {
COMPLETE,
ERROR
}

View File

@ -112,4 +112,18 @@ class BreakToContinueReplacer implements StatementVisitor {
visitSequence(statement.getProtectedBody());
visitSequence(statement.getHandler());
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

View File

@ -107,4 +107,18 @@ class CertainBlockCountVisitor implements StatementVisitor {
visit(statement.getProtectedBody());
visit(statement.getHandler());
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

View File

@ -18,11 +18,11 @@ package org.teavm.javascript;
import java.util.*;
import org.teavm.common.*;
import org.teavm.javascript.ast.*;
import org.teavm.javascript.ni.GeneratedBy;
import org.teavm.javascript.ni.Generator;
import org.teavm.javascript.ni.InjectedBy;
import org.teavm.javascript.ni.PreserveOriginalName;
import org.teavm.javascript.spi.GeneratedBy;
import org.teavm.javascript.spi.Generator;
import org.teavm.javascript.spi.InjectedBy;
import org.teavm.model.*;
import org.teavm.model.util.AsyncProgramSplitter;
import org.teavm.model.util.ProgramUtils;
/**
@ -45,10 +45,16 @@ public class Decompiler {
private Map<MethodReference, Generator> generators = new HashMap<>();
private Set<MethodReference> methodsToPass = new HashSet<>();
private RegularMethodNodeCache regularMethodCache;
private Set<MethodReference> asyncMethods;
private Set<MethodReference> splitMethods = new HashSet<>();
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader) {
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
Set<MethodReference> asyncFamilyMethods) {
this.classSource = classSource;
this.classLoader = classLoader;
this.asyncMethods = asyncMethods;
splitMethods.addAll(asyncMethods);
splitMethods.addAll(asyncFamilyMethods);
}
public RegularMethodNodeCache getRegularMethodCache() {
@ -143,9 +149,6 @@ public class Decompiler {
}
MethodNode methodNode = decompile(method);
clsNode.getMethods().add(methodNode);
if (method.getAnnotations().get(PreserveOriginalName.class.getName()) != null) {
methodNode.setOriginalNamePreserved(true);
}
}
clsNode.getInterfaces().addAll(cls.getInterfaces());
clsNode.getModifiers().addAll(mapModifiers(cls.getModifiers()));
@ -154,7 +157,7 @@ public class Decompiler {
public MethodNode decompile(MethodHolder method) {
return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method) :
decompileRegular(method);
!asyncMethods.contains(method.getReference()) ? decompileRegular(method) : decompileAsync(method);
}
public NativeMethodNode decompileNative(MethodHolder method) {
@ -179,6 +182,7 @@ public class Decompiler {
method.getDescriptor()));
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
methodNode.setGenerator(generator);
methodNode.setAsync(asyncMethods.contains(method.getReference()));
return methodNode;
}
@ -194,14 +198,65 @@ public class Decompiler {
return node;
}
public AsyncMethodNode decompileAsync(MethodHolder method) {
AsyncMethodNode node = new AsyncMethodNode(method.getReference());
AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods);
splitter.split(method.getProgram());
for (int i = 0; i < splitter.size(); ++i) {
Integer input = null;
if (i > 0) {
input = splitter.getInput(i);
if (input == null) {
input = -1;
}
}
AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i),
input);
node.getBody().add(part);
}
Program program = method.getProgram();
for (int i = 0; i < program.variableCount(); ++i) {
node.getVariables().add(program.variableAt(i).getRegister());
}
Optimizer optimizer = new Optimizer();
optimizer.optimize(node, program, splitter);
node.getModifiers().addAll(mapModifiers(method.getModifiers()));
int paramCount = Math.min(method.getSignature().length, program.variableCount());
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
node.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
}
return node;
}
public RegularMethodNode decompileRegularCacheMiss(MethodHolder method) {
RegularMethodNode methodNode = new RegularMethodNode(method.getReference());
Program program = method.getProgram();
int[] targetBlocks = new int[program.basicBlockCount()];
Arrays.fill(targetBlocks, -1);
methodNode.setBody(getRegularMethodStatement(program, targetBlocks, null).getStatement());
for (int i = 0; i < program.variableCount(); ++i) {
methodNode.getVariables().add(program.variableAt(i).getRegister());
}
Optimizer optimizer = new Optimizer();
optimizer.optimize(methodNode, method.getProgram());
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
int paramCount = Math.min(method.getSignature().length, program.variableCount());
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
}
return methodNode;
}
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, Integer inputVar) {
AsyncMethodPart result = new AsyncMethodPart();
lastBlockId = 1;
graph = ProgramUtils.buildControlFlowGraph(method.getProgram());
graph = ProgramUtils.buildControlFlowGraph(program);
indexer = new GraphIndexer(graph);
graph = indexer.getGraph();
loopGraph = new LoopGraph(this.graph);
unflatCode();
Program program = method.getProgram();
blockMap = new Block[program.basicBlockCount() * 2 + 1];
Deque<Block> stack = new ArrayDeque<>();
BlockStatement rootStmt = new BlockStatement();
@ -247,9 +302,17 @@ public class Decompiler {
int tmp = indexer.nodeAt(next);
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
generator.statements.clear();
if (node == 0 && inputVar != null) {
RestoreAsyncStatement restoreStmt = new RestoreAsyncStatement();
restoreStmt.setReceiver(inputVar >= 0 ? inputVar : null);
generator.statements.add(restoreStmt);
}
generator.asyncTarget = null;
InstructionLocation lastLocation = null;
NodeLocation nodeLocation = null;
for (Instruction insn : generator.currentBlock.getInstructions()) {
List<Instruction> instructions = generator.currentBlock.getInstructions();
for (int j = 0; j < instructions.size(); ++j) {
Instruction insn = generator.currentBlock.getInstructions().get(j);
if (insn.getLocation() != null && lastLocation != insn.getLocation()) {
lastLocation = insn.getLocation();
nodeLocation = new NodeLocation(lastLocation.getFileName(), lastLocation.getLine());
@ -257,6 +320,9 @@ public class Decompiler {
if (insn.getLocation() != null) {
generator.setCurrentLocation(nodeLocation);
}
if (targetBlocks[node] >= 0 && j == instructions.size() - 1) {
generator.asyncTarget = targetBlocks[node];
}
insn.acceptVisitor(generator);
}
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
@ -274,24 +340,10 @@ public class Decompiler {
block.body.addAll(generator.statements);
}
}
SequentialStatement result = new SequentialStatement();
result.getSequence().addAll(rootStmt.getBody());
MethodReference reference = new MethodReference(method.getOwnerName(), method.getDescriptor());
RegularMethodNode methodNode = new RegularMethodNode(reference);
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
methodNode.setBody(result);
for (int i = 0; i < program.variableCount(); ++i) {
methodNode.getVariables().add(program.variableAt(i).getRegister());
}
Optimizer optimizer = new Optimizer();
optimizer.optimize(methodNode, method.getProgram());
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
int paramCount = Math.min(method.getSignature().length, program.variableCount());
for (int i = 0; i < paramCount; ++i) {
Variable var = program.variableAt(i);
methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
}
return methodNode;
SequentialStatement resultBody = new SequentialStatement();
resultBody.getSequence().addAll(rootStmt.getBody());
result.setStatement(resultBody);
return result;
}
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {

View File

@ -15,9 +15,11 @@
*/
package org.teavm.javascript;
import org.teavm.javascript.ast.AsyncMethodNode;
import org.teavm.javascript.ast.AsyncMethodPart;
import org.teavm.javascript.ast.RegularMethodNode;
import org.teavm.model.Program;
import org.teavm.model.util.AsyncProgramSplitter;
/**
*
@ -40,4 +42,33 @@ public class Optimizer {
method.getVariables().set(i, i);
}
}
public void optimize(AsyncMethodNode method, Program program, AsyncProgramSplitter splitter) {
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
stats.analyze(program);
for (int i = 0; i < splitter.size(); ++i) {
Integer var = splitter.getInput(i);
if (var != null) {
stats.reads[var]++;
}
}
for (AsyncMethodPart part : method.getBody()) {
OptimizingVisitor optimizer = new OptimizingVisitor(stats.copy());
part.getStatement().acceptVisitor(optimizer);
part.setStatement(optimizer.resultStmt);
}
int paramCount = method.getReference().parameterCount();
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
for (AsyncMethodPart part : method.getBody()) {
part.getStatement().acceptVisitor(unusedEliminator);
}
method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear();
RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator();
for (AsyncMethodPart part : method.getBody()) {
part.getStatement().acceptVisitor(labelEliminator);
}
for (int i = 0; i < method.getVariables().size(); ++i) {
method.getVariables().set(i, i);
}
}
}

View File

@ -180,7 +180,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
}
private boolean tryApplyConstructor(InvocationExpr expr) {
if (!expr.getMethod().getName().equals("<init>")) {
if (expr.getAsyncTarget() != null || !expr.getMethod().getName().equals("<init>")) {
return false;
}
if (resultSequence == null || resultSequence.isEmpty()) {
@ -211,7 +211,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
}
Expr[] args = expr.getArguments().toArray(new Expr[0]);
args = Arrays.copyOfRange(args, 1, args.length);
Expr constructrExpr = Expr.constructObject(expr.getMethod(), args);
InvocationExpr constructrExpr = Expr.constructObject(expr.getMethod(), args);
constructrExpr.setLocation(expr.getLocation());
assignment.setRightValue(constructrExpr);
stats.reads[var.getIndex()]--;
@ -289,6 +289,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
List<Statement> backup = resultSequence;
resultSequence = new ArrayList<>();
processSequenceImpl(statements);
wieldTryCatch(resultSequence);
List<Statement> result = new ArrayList<>();
for (Statement part : resultSequence) {
if (part != null) {
@ -324,6 +325,41 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
return true;
}
private void wieldTryCatch(List<Statement> statements) {
for (int i = 0; i < statements.size() - 1; ++i) {
if (statements.get(i) instanceof TryCatchStatement && statements.get(i + 1) instanceof TryCatchStatement) {
TryCatchStatement first = (TryCatchStatement)statements.get(i);
TryCatchStatement second = (TryCatchStatement)statements.get(i + 1);
if (Objects.equals(first.getExceptionType(), second.getExceptionType()) &&
Objects.equals(first.getExceptionVariable(), second.getExceptionVariable()) &&
briefStatementComparison(first.getHandler(), second.getHandler())) {
first.getProtectedBody().addAll(second.getProtectedBody());
statements.remove(i + 1);
wieldTryCatch(first.getProtectedBody());
--i;
continue;
}
}
}
}
private boolean briefStatementComparison(List<Statement> firstSeq, List<Statement> secondSeq) {
if (firstSeq.isEmpty() && secondSeq.isEmpty()) {
return true;
}
if (firstSeq.size() != 1 || secondSeq.size() != 1) {
return false;
}
Statement first = firstSeq.get(0);
Statement second = secondSeq.get(0);
if (first instanceof BreakStatement && second instanceof BreakStatement) {
BreakStatement firstBreak = (BreakStatement)first;
BreakStatement secondBreak = (BreakStatement)second;
return firstBreak.getTarget() == secondBreak.getTarget();
}
return false;
}
private void eliminateRedundantBreaks(List<Statement> statements, IdentifiedStatement exit) {
if (statements.isEmpty()) {
return;
@ -577,4 +613,19 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
statement.getHandler().addAll(statements);
resultStmt = statement;
}
@Override
public void visit(RestoreAsyncStatement statement) {
resultStmt = statement;
}
@Override
public void visit(MonitorEnterStatement statement) {
resultStmt = statement;
}
@Override
public void visit(MonitorExitStatement statement) {
resultStmt = statement;
}
}

View File

@ -0,0 +1,40 @@
/*
* 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;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public enum Priority {
COMMA,
ASSIGNMENT,
CONDITIONAL,
LOGICAL_OR,
LOGICAL_AND,
BITWISE_OR,
BITWISE_XOR,
BITWISE_AND,
EQUALITY,
COMPARISON,
BITWISE_SHIFT,
ADDITION,
MULTIPLICATION,
UNARY,
FUNCTION_CALL,
MEMBER_ACCESS,
GROUPING
}

View File

@ -15,6 +15,7 @@
*/
package org.teavm.javascript;
import java.util.Arrays;
import org.teavm.model.*;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.UsageExtractor;
@ -27,11 +28,21 @@ class ReadWriteStatsBuilder {
public int[] reads;
public int[] writes;
private ReadWriteStatsBuilder() {
}
public ReadWriteStatsBuilder(int variableCount) {
reads = new int[variableCount];
writes = new int[variableCount];
}
public ReadWriteStatsBuilder copy() {
ReadWriteStatsBuilder result = new ReadWriteStatsBuilder();
result.reads = Arrays.copyOf(reads, reads.length);
result.writes = Arrays.copyOf(writes, writes.length);
return result;
}
public void analyze(Program program) {
DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor();

View File

@ -117,4 +117,18 @@ class RedundantLabelEliminator implements StatementVisitor {
visitSequence(statement.getProtectedBody());
visitSequence(statement.getHandler());
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

View File

@ -111,4 +111,18 @@ class ReferenceCountingVisitor implements StatementVisitor {
part.acceptVisitor(this);
}
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@ class StatementGenerator implements InstructionVisitor {
Program program;
ClassHolderSource classSource;
private NodeLocation currentLocation;
Integer asyncTarget;
public void setCurrentLocation(NodeLocation currentLocation) {
this.currentLocation = currentLocation;
@ -303,25 +304,17 @@ class StatementGenerator implements InstructionVisitor {
case FROM_INTEGER:
switch (insn.getTargetType()) {
case BYTE:
value = Expr.binary(BinaryOperation.BITWISE_AND, value, Expr.constant(0xFF));
value = Expr.unary(UnaryOperation.INT_TO_BYTE, value);
break;
case SHORT:
value = Expr.unary(UnaryOperation.INT_TO_SHORT, value);
break;
case CHARACTER:
value = Expr.binary(BinaryOperation.BITWISE_AND, value, Expr.constant(0xFFFF));
value = Expr.unary(UnaryOperation.INT_TO_CHAR, value);
break;
}
break;
case TO_INTEGER:
switch (insn.getTargetType()) {
case BYTE:
value = Expr.unary(UnaryOperation.BYTE_TO_INT, value);
break;
case SHORT:
value = Expr.unary(UnaryOperation.SHORT_TO_INT, value);
break;
case CHARACTER:
break;
}
break;
}
assign(value, insn.getReceiver());
@ -546,7 +539,7 @@ class StatementGenerator implements InstructionVisitor {
for (int i = 0; i < insn.getArguments().size(); ++i) {
exprArgs[i] = Expr.var(insn.getArguments().get(i).getIndex());
}
Expr invocationExpr;
InvocationExpr invocationExpr;
if (insn.getInstance() != null) {
if (insn.getType() == InvocationType.VIRTUAL) {
invocationExpr = Expr.invoke(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs);
@ -557,6 +550,8 @@ class StatementGenerator implements InstructionVisitor {
} else {
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
}
invocationExpr.setAsyncTarget(asyncTarget);
if (asyncTarget == null) {
if (insn.getReceiver() != null) {
assign(invocationExpr, insn.getReceiver());
} else {
@ -564,6 +559,11 @@ class StatementGenerator implements InstructionVisitor {
stmt.setLocation(currentLocation);
statements.add(stmt);
}
} else {
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
stmt.setLocation(currentLocation);
statements.add(stmt);
}
}
@Override
@ -658,4 +658,21 @@ 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) {
MonitorEnterStatement stmt = new MonitorEnterStatement();
stmt.setLocation(currentLocation);
stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex()));
stmt.setAsyncTarget(asyncTarget);
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

@ -110,4 +110,18 @@ class TryCatchFinder implements StatementVisitor {
public void visit(TryCatchStatement statement) {
tryCatchFound = true;
}
@Override
public void visit(RestoreAsyncStatement statement) {
}
@Override
public void visit(MonitorEnterStatement statement) {
}
@Override
public void visit(MonitorExitStatement statement) {
}
}

View File

@ -224,4 +224,21 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
}
}
}
@Override
public void visit(RestoreAsyncStatement statement) {
if (statement.getReceiver() != null) {
statement.setReceiver(renumber(statement.getReceiver()));
}
}
@Override
public void visit(MonitorEnterStatement statement) {
statement.getObjectRef().acceptVisitor(this);
}
@Override
public void visit(MonitorExitStatement statement) {
statement.getObjectRef().acceptVisitor(this);
}
}

View File

@ -0,0 +1,57 @@
/*
* 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;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.teavm.model.MethodReference;
/**
*
* @author Alexey Andreev
*/
public class AsyncMethodNode extends MethodNode {
private List<AsyncMethodPart> body = new ArrayList<>();
private List<Integer> variables = new ArrayList<>();
private List<Set<String>> parameterDebugNames = new ArrayList<>();
public AsyncMethodNode(MethodReference reference) {
super(reference);
}
public List<AsyncMethodPart> getBody() {
return body;
}
public List<Integer> getVariables() {
return variables;
}
public List<Set<String>> getParameterDebugNames() {
return parameterDebugNames;
}
@Override
public void acceptVisitor(MethodNodeVisitor visitor) {
visitor.visit(this);
}
@Override
public boolean isAsync() {
return true;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 Alexey Andreev
*/
public class AsyncMethodPart {
private Statement statement;
public Statement getStatement() {
return statement;
}
public void setStatement(Statement statement) {
this.statement = statement;
}
}

Some files were not shown because too many files have changed in this diff Show More