mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Merge branch 'async'
This commit is contained in:
commit
1c0acf61d4
1
pom.xml
1
pom.xml
|
@ -82,6 +82,7 @@
|
|||
<module>teavm-platform</module>
|
||||
<module>teavm-cli</module>
|
||||
<module>teavm-chrome-rdp</module>
|
||||
<module>teavm-tests</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
|
@ -465,18 +465,22 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
|
|||
for (PropertyDescriptorDTO property : properties) {
|
||||
RemoteObjectDTO remoteValue = property.getValue();
|
||||
RDPValue value;
|
||||
switch (remoteValue.getType()) {
|
||||
case "undefined":
|
||||
value = new RDPValue(this, "undefined", "undefined", null, false);
|
||||
break;
|
||||
case "object":
|
||||
case "function":
|
||||
value = new RDPValue(this, null, remoteValue.getType(), remoteValue.getObjectId(), true);
|
||||
break;
|
||||
default:
|
||||
value = new RDPValue(this, remoteValue.getValue().asText(), remoteValue.getType(),
|
||||
remoteValue.getObjectId(), false);
|
||||
break;
|
||||
if (remoteValue != null && remoteValue.getType() != null) {
|
||||
switch (remoteValue.getType()) {
|
||||
case "undefined":
|
||||
value = new RDPValue(this, "undefined", "undefined", null, false);
|
||||
break;
|
||||
case "object":
|
||||
case "function":
|
||||
value = new RDPValue(this, null, remoteValue.getType(), remoteValue.getObjectId(), true);
|
||||
break;
|
||||
default:
|
||||
value = new RDPValue(this, remoteValue.getValue().asText(), remoteValue.getType(),
|
||||
remoteValue.getObjectId(), false);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
value = new RDPValue(this, "null", "null", "null", false);
|
||||
}
|
||||
|
||||
RDPLocalVariable var = new RDPLocalVariable(property.getName(), value);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -34,7 +34,7 @@ public class TFilterInputStream extends TInputStream {
|
|||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
public void mark(int readlimit) {
|
||||
in.mark(readlimit);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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("\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,31 +159,36 @@ 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")
|
||||
public static TClass<?> forName(TString name, boolean initialize, TClassLoader loader)
|
||||
throws TClassNotFoundException {
|
||||
throws TClassNotFoundException {
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
import org.teavm.javascript.spi.GeneratedBy;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
import org.teavm.javascript.spi.GeneratedBy;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
import org.teavm.javascript.spi.GeneratedBy;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.Superclass;
|
||||
import org.teavm.javascript.spi.Superclass;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -57,45 +57,49 @@ 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
return alias;
|
||||
} else {
|
||||
String key = method.getDescriptor().toString();
|
||||
String alias = aliases.get(key);
|
||||
if (alias == null) {
|
||||
alias = aliasProvider.getAlias(method);
|
||||
aliases.put(key, alias);
|
||||
}
|
||||
return alias;
|
||||
return getNameFor(method, 'S');
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameForAsync(MethodReference method) throws NamingException {
|
||||
return getNameFor(method, 'A');
|
||||
}
|
||||
|
||||
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);
|
||||
aliases.put(key, alias);
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullNameFor(MethodReference method) throws NamingException {
|
||||
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;
|
||||
if (!minifying) {
|
||||
return getNameFor(method.getClassName()) + "_" + getNameFor(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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
155
teavm-core/src/main/java/org/teavm/common/DJGraph.java
Normal file
155
teavm-core/src/main/java/org/teavm/common/DJGraph.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,4 +27,6 @@ public interface DominatorTree {
|
|||
boolean dominates(int a, int b);
|
||||
|
||||
int immediateDominatorOf(int a);
|
||||
|
||||
int levelOf(int a);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ public interface DependencyInfo {
|
|||
|
||||
MethodDependencyInfo getMethod(MethodReference methodRef);
|
||||
|
||||
MethodDependencyInfo getMethodImplementation(MethodReference methodRef);
|
||||
|
||||
ClassDependencyInfo getClass(String className);
|
||||
|
||||
CallGraph getCallGraph();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
40
teavm-core/src/main/java/org/teavm/javascript/Priority.java
Normal file
40
teavm-core/src/main/java/org/teavm/javascript/Priority.java
Normal 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
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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,8 +550,15 @@ class StatementGenerator implements InstructionVisitor {
|
|||
} else {
|
||||
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
|
||||
}
|
||||
if (insn.getReceiver() != null) {
|
||||
assign(invocationExpr, insn.getReceiver());
|
||||
invocationExpr.setAsyncTarget(asyncTarget);
|
||||
if (asyncTarget == null) {
|
||||
if (insn.getReceiver() != null) {
|
||||
assign(invocationExpr, insn.getReceiver());
|
||||
} else {
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
} else {
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue
Block a user