Support Java 11

This commit is contained in:
Alexey Andreev 2018-11-12 18:59:28 +03:00
parent d4b145a523
commit 064888c9a1
11 changed files with 164 additions and 16 deletions

View File

@ -73,6 +73,18 @@ public class JCLPlugin implements TeaVMPlugin {
ValueType.arrayOf(ValueType.object("java.lang.Object")),
ValueType.object("java.lang.invoke.CallSite")), lms);
StringConcatFactorySubstritutor stringConcatSubstitutor = new StringConcatFactorySubstritutor();
host.add(new MethodReference("java.lang.invoke.StringConcatFactory", "makeConcat",
ValueType.object("java.lang.invoke.MethodHandles$Lookup"), ValueType.object("java.lang.String"),
ValueType.object("java.lang.invoke.MethodType"), ValueType.object("java.lang.invoke.CallSite")),
stringConcatSubstitutor);
host.add(new MethodReference("java.lang.invoke.StringConcatFactory", "makeConcatWithConstants",
ValueType.object("java.lang.invoke.MethodHandles$Lookup"), ValueType.object("java.lang.String"),
ValueType.object("java.lang.invoke.MethodType"), ValueType.object("java.lang.String"),
ValueType.arrayOf(ValueType.object("java.lang.Object")),
ValueType.object("java.lang.invoke.CallSite")),
stringConcatSubstitutor);
if (!isBootstrap()) {
host.add(new ScalaHacks());
}

View File

@ -0,0 +1,125 @@
/*
* Copyright 2018 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.dependency.BootstrapMethodSubstitutor;
import org.teavm.dependency.DynamicCallSite;
import org.teavm.model.MethodReference;
import org.teavm.model.RuntimeConstant;
import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.emit.ValueEmitter;
public class StringConcatFactorySubstritutor implements BootstrapMethodSubstitutor {
private static final String STRING_BUILDER = "java.lang.StringBuilder";
private static final char VALUE_ARGUMENT = '\1';
private static final char CONST_ARGUMENT = '\2';
@Override
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter pe) {
ValueEmitter sb = pe.construct(STRING_BUILDER);
if (callSite.getBootstrapMethod().getName().equals("makeConcatWithConstants")) {
appendArgumentWithRecipe(sb, callSite);
} else {
appendSimpleArguments(sb, callSite);
}
return sb.invokeSpecial("toString", ValueType.object("java.lang.String"));
}
private ValueEmitter appendSimpleArguments(ValueEmitter sb, DynamicCallSite callSite) {
int parameterCount = callSite.getCalledMethod().parameterCount();
for (int i = 0; i < parameterCount; ++i) {
sb = appendArgument(sb, callSite.getCalledMethod().parameterType(i), callSite.getArguments().get(i));
}
return sb;
}
private ValueEmitter appendArgumentWithRecipe(ValueEmitter sb, DynamicCallSite callSite) {
String recipe = callSite.getBootstrapArguments().get(0).getString();
int charCount = recipe.length();
int constantIndex = 0;
int valueIndex = 0;
int paramIndex = 0;
StringBuilder acc = new StringBuilder();
for (int i = 0; i < charCount; ++i) {
char c = recipe.charAt(i);
switch (c) {
case VALUE_ARGUMENT: {
sb = flushAcc(sb, acc);
ValueType type = callSite.getCalledMethod().parameterType(paramIndex++);
sb = appendArgument(sb, type, callSite.getArguments().get(valueIndex++));
break;
}
case CONST_ARGUMENT: {
sb = flushAcc(sb, acc);
ValueType type = callSite.getCalledMethod().parameterType(paramIndex++);
RuntimeConstant poolConstant = callSite.getBootstrapArguments().get(1 + constantIndex++);
sb = appendArgument(sb, type, constant(sb.getProgramEmitter(), poolConstant));
break;
}
default:
acc.append(c);
break;
}
}
sb = flushAcc(sb, acc);
return sb;
}
private ValueEmitter flushAcc(ValueEmitter sb, StringBuilder acc) {
if (acc.length() == 0) {
return sb;
} else if (acc.length() == 1) {
sb = appendArgument(sb, ValueType.CHARACTER, sb.getProgramEmitter().constant(acc.charAt(0))
.cast(ValueType.CHARACTER));
} else {
sb = appendArgument(sb, ValueType.object("java.lang.Object"),
sb.getProgramEmitter().constant(acc.toString()));
}
acc.setLength(0);
return sb;
}
private ValueEmitter appendArgument(ValueEmitter sb, ValueType type, ValueEmitter argument) {
if (!(type instanceof ValueType.Primitive)) {
type = ValueType.object("java.lang.Object");
}
MethodReference method = new MethodReference(STRING_BUILDER, "append", type, ValueType.object(STRING_BUILDER));
return sb.invokeSpecial(method, argument);
}
private ValueEmitter constant(ProgramEmitter pe, RuntimeConstant value) {
switch (value.getKind()) {
case RuntimeConstant.STRING:
return pe.constant(value.getString());
case RuntimeConstant.TYPE:
return pe.constant(value.getValueType());
case RuntimeConstant.INT:
return pe.constant(value.getInt());
case RuntimeConstant.LONG:
return pe.constant(value.getLong());
case RuntimeConstant.FLOAT:
return pe.constant(value.getFloat());
case RuntimeConstant.DOUBLE:
return pe.constant(value.getDouble());
default:
throw new IllegalArgumentException("Unsupported constant type: " + value.getKind());
}
}
}

View File

@ -28,7 +28,7 @@ class JCLComparisonVisitor extends ClassVisitor {
private JCLClass jclClass;
public JCLComparisonVisitor(ClassReaderSource classSource, Map<String, JCLPackage> packageMap) {
super(Opcodes.ASM5);
super(Opcodes.ASM7);
this.classSource = classSource;
this.packageMap = packageMap;
}

View File

@ -67,7 +67,7 @@ public class Parser {
}
public MethodHolder parseMethod(MethodNode node, String fileName) {
MethodNode nodeWithoutJsr = new MethodNode(Opcodes.ASM5, node.access, node.name, node.desc, node.signature,
MethodNode nodeWithoutJsr = new MethodNode(Opcodes.ASM7, node.access, node.name, node.desc, node.signature,
node.exceptions.toArray(new String[0]));
JSRInlinerAdapter adapter = new JSRInlinerAdapter(nodeWithoutJsr, node.access, node.name, node.desc,
node.signature, node.exceptions.toArray(new String[0]));

View File

@ -435,7 +435,7 @@ public class ProgramParser {
}
// TODO: invokedynamic support (a great task, involving not only parser, but every layer of TeaVM)
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM5) {
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM7) {
@Override
public void visitVarInsn(int opcode, int local) {
switch (opcode) {

View File

@ -206,7 +206,7 @@ final class TeaVMPluginReader {
PluginDescriptor descriptor;
public PluginDescriptorFiller(PluginDescriptor descriptor) {
super(Opcodes.ASM5);
super(Opcodes.ASM7);
this.descriptor = descriptor;
}
@ -223,12 +223,12 @@ final class TeaVMPluginReader {
}
private AnnotationVisitor readClassArray(Consumer<String[]> resultConsumer) {
return new AnnotationVisitor(Opcodes.ASM5) {
return new AnnotationVisitor(Opcodes.ASM7) {
@Override
public AnnotationVisitor visitArray(String name) {
List<String> values = new ArrayList<>();
if (name.equals("value")) {
return new AnnotationVisitor(Opcodes.ASM5) {
return new AnnotationVisitor(Opcodes.ASM7) {
@Override
public void visit(String name, Object value) {
values.add(((Type) value).getClassName());

View File

@ -129,7 +129,7 @@ public class MetaprogrammingClassLoader extends ClassLoader {
boolean compileTime;
CompileTimeClassVisitor() {
super(Opcodes.ASM5, null);
super(Opcodes.ASM7, null);
}
@Override

View File

@ -46,7 +46,7 @@ public class MetaprogrammingInstrumentation {
class ClassTransformer extends ClassVisitor {
ClassTransformer(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
super(Opcodes.ASM7, cv);
}
@Override
@ -60,7 +60,7 @@ public class MetaprogrammingInstrumentation {
private boolean instrumented;
MethodTransformer(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
super(Opcodes.ASM7, mv);
}
@Override

13
pom.xml
View File

@ -71,7 +71,8 @@
<selenium.version>2.47.2</selenium.version>
<jackson.version>2.6.2</jackson.version>
<idea.version>2017.3.5</idea.version>
<asm.version>6.1.1</asm.version>
<asm.version>7.0</asm.version>
<java.version>1.8</java.version>
<rhino.version>1.7.7</rhino.version>
<teavm.test.incremental>false</teavm.test.incremental>
@ -216,16 +217,16 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.0</version>
<version>3.0.1</version>
<executions>
<execution>
<id>build-javadoc</id>
@ -289,7 +290,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.5.3</version>
<version>4.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -162,6 +162,16 @@ public class VMTest {
assertEquals("SECOND ", ClassWithStaticField.foo(false));
}
@Test
public void stringConcat() {
assertEquals("(23)", surroundWithParentheses(23));
assertEquals("(42)", surroundWithParentheses(42));
}
private String surroundWithParentheses(int value) {
return "(" + value + ")";
}
@Test
public void variableReadInCatchBlock() {
int n = foo();

View File

@ -85,7 +85,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5.1</version>
<version>3.6.0</version>
<configuration>
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
<goalPrefix>teavm</goalPrefix>