add support for openjdk=$JDK8_HOME

All tests pass for the process=compile build.  Next step: process=interpret.
This commit is contained in:
Joel Dice 2015-08-06 13:24:06 -06:00
parent 2465459079
commit 8a7944d25c
12 changed files with 247 additions and 139 deletions

View File

@ -1,6 +1,9 @@
language: cpp language: cpp
cache: apt cache: apt
jdk:
- oraclejdk8
os: os:
- linux - linux
- osx - osx

View File

@ -45,6 +45,8 @@ public class Classes {
public static native VMClass toVMClass(Class c); public static native VMClass toVMClass(Class c);
public static native VMMethod toVMMethod(Method m);
private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec)
throws ClassNotFoundException; throws ClassNotFoundException;

View File

@ -155,7 +155,19 @@ public class LambdaMetafactory {
write1(out, p.position() + 1); write1(out, p.position() + 1);
} }
write1(out, invokestatic); switch (implementation.kind) {
case MethodHandle.REF_invokeStatic:
write1(out, invokestatic);
break;
case MethodHandle.REF_invokeSpecial:
write1(out, invokespecial);
break;
default: throw new AssertionError
("todo: implement per http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.5");
}
write2(out, ConstantPool.addMethodRef write2(out, ConstantPool.addMethodRef
(pool, (pool,
Classes.makeString(implementation.method.class_.name, 0, Classes.makeString(implementation.method.class_.name, 0,
@ -213,11 +225,9 @@ public class LambdaMetafactory {
try { try {
methodTable.add methodTable.add
(new MethodData (new MethodData
(Modifier.STATIC, (Modifier.PUBLIC | Modifier.STATIC,
ConstantPool.addUtf8(pool, "make"), ConstantPool.addUtf8(pool, "make"),
ConstantPool.addUtf8(pool, Classes.makeString ConstantPool.addUtf8(pool, invokedType.toMethodDescriptorString()),
(invokedType.spec, 0,
invokedType.spec.length - 1)),
makeFactoryCode(pool, className, constructorSpec, invokedType))); makeFactoryCode(pool, className, constructorSpec, invokedType)));
methodTable.add methodTable.add
@ -231,9 +241,7 @@ public class LambdaMetafactory {
(new MethodData (new MethodData
(Modifier.PUBLIC, (Modifier.PUBLIC,
ConstantPool.addUtf8(pool, invokedName), ConstantPool.addUtf8(pool, invokedName),
ConstantPool.addUtf8(pool, Classes.makeString ConstantPool.addUtf8(pool, methodType.toMethodDescriptorString()),
(methodType.spec, 0,
methodType.spec.length - 1)),
makeInvocationCode(pool, className, constructorSpec, invokedType, makeInvocationCode(pool, className, constructorSpec, invokedType,
methodType, methodImplementation))); methodType, methodImplementation)));
} catch (IOException e) { } catch (IOException e) {
@ -262,10 +270,11 @@ public class LambdaMetafactory {
try { try {
return new CallSite return new CallSite
(new MethodHandle (new MethodHandle
(invokedType.loader, avian.SystemClassLoader.getClass (MethodHandle.REF_invokeStatic, invokedType.loader, Classes.toVMMethod
(avian.Classes.defineVMClass (avian.SystemClassLoader.getClass
(invokedType.loader, classData, 0, classData.length)) (avian.Classes.defineVMClass
.getMethod("make", invokedType.parameterArray()).vmMethod)); (invokedType.loader, classData, 0, classData.length))
.getMethod("make", invokedType.parameterArray()))));
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
AssertionError error = new AssertionError(); AssertionError error = new AssertionError();
error.initCause(e); error.initCause(e);

View File

@ -1,17 +1,34 @@
package java.lang.invoke; package java.lang.invoke;
import avian.Classes;
public class MethodHandle { public class MethodHandle {
static final int REF_invokeStatic = 6;
static final int REF_invokeSpecial = 7;
final int kind;
private final ClassLoader loader; private final ClassLoader loader;
final avian.VMMethod method; final avian.VMMethod method;
private volatile MethodType type; private volatile MethodType type;
MethodHandle(ClassLoader loader, avian.VMMethod method) { MethodHandle(int kind, ClassLoader loader, avian.VMMethod method) {
this.kind = kind;
this.loader = loader; this.loader = loader;
this.method = method; this.method = method;
} }
public String toString() { public String toString() {
return new java.lang.reflect.Method(method).toString(); StringBuilder sb = new StringBuilder();
if (method.class_ != null) {
sb.append(Classes.makeString(method.class_.name, 0,
method.class_.name.length - 1));
sb.append(".");
}
sb.append(Classes.makeString(method.name, 0,
method.name.length - 1));
sb.append(Classes.makeString(method.spec, 0,
method.spec.length - 1));
return sb.toString();
} }
public MethodType type() { public MethodType type() {

View File

@ -2,12 +2,18 @@ package java.lang.invoke;
import static avian.Assembler.*; import static avian.Assembler.*;
import avian.Assembler;
import avian.Classes; import avian.Classes;
import avian.VMClass;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
public final class MethodType implements java.io.Serializable { public final class MethodType implements java.io.Serializable {
private static final char[] Primitives = new char[] {
'V', 'Z', 'B', 'C', 'S', 'I', 'F', 'J', 'D'
};
final ClassLoader loader; final ClassLoader loader;
final byte[] spec; final byte[] spec;
private volatile List<Parameter> parameters; private volatile List<Parameter> parameters;
@ -19,6 +25,77 @@ public final class MethodType implements java.io.Serializable {
this.spec = spec; this.spec = spec;
} }
public String toMethodDescriptorString() {
return Classes.makeString(spec, 0, spec.length - 1);
}
private static String spec(Class c) {
if (c.isPrimitive()) {
VMClass vmc = Classes.toVMClass(c);
for (char p: Primitives) {
if (vmc == Classes.primitiveClass(p)) {
return String.valueOf(p);
}
}
throw new AssertionError();
} else if (c.isArray()) {
return "[" + spec(c.getComponentType());
} else {
return "L" + c.getName().replace('.', '/') + ";";
}
}
private MethodType(Class rtype,
Class ... ptypes)
{
loader = rtype.getClassLoader();
StringBuilder sb = new StringBuilder();
sb.append('(');
parameters = new ArrayList(ptypes.length);
int position = 0;
for (int i = 0; i < ptypes.length; ++i) {
String spec = spec(ptypes[i]);
sb.append(spec);
Type type = type(spec);
parameters.add(new Parameter(i,
position,
spec,
ptypes[i],
type.load));
position += type.size;
}
sb.append(')');
footprint = position;
String spec = spec(rtype);
sb.append(spec);
result = new Result(spec, rtype, type(spec).return_);
this.spec = sb.toString().getBytes();
}
public static MethodType methodType(Class rtype,
Class ptype0,
Class ... ptypes)
{
Class[] array = new Class[ptypes.length + 1];
array[0] = ptype0;
System.arraycopy(ptypes, 0, array, 1, ptypes.length);
return methodType(rtype, array);
}
public static MethodType methodType(Class rtype,
Class ... ptypes)
{
return new MethodType(rtype, ptypes);
}
public String toString() { public String toString() {
return Classes.makeString(spec, 0, spec.length - 1); return Classes.makeString(spec, 0, spec.length - 1);
} }
@ -53,21 +130,14 @@ public final class MethodType implements java.io.Serializable {
int index = 0; int index = 0;
int position = 0; int position = 0;
for (i = 1; spec[i] != ')'; ++i) { for (i = 1; spec[i] != ')'; ++i) {
int start = i;
switch (spec[i]) { switch (spec[i]) {
case 'L': { case 'L': {
int start = i;
++ i; ++ i;
while (spec[i] != ';') ++ i; while (spec[i] != ';') ++ i;
list.add(new Parameter
(index,
position,
Classes.makeString(spec, start, (i - start) + 1),
aload));
} break; } break;
case '[': { case '[': {
int start = i;
++ i; ++ i;
while (spec[i] == '[') ++ i; while (spec[i] == '[') ++ i;
@ -80,12 +150,6 @@ public final class MethodType implements java.io.Serializable {
default: default:
break; break;
} }
list.add(new Parameter
(index,
position,
Classes.makeString(spec, start, (i - start) + 1),
aload));
} break; } break;
case 'Z': case 'Z':
@ -93,107 +157,38 @@ public final class MethodType implements java.io.Serializable {
case 'S': case 'S':
case 'C': case 'C':
case 'I': case 'I':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
iload));
break;
case 'F': case 'F':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
fload));
break;
case 'J': case 'J':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
lload));
++ position;
break;
case 'D': case 'D':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
dload));
++ position;
break; break;
default: throw new AssertionError(); default: throw new AssertionError();
} }
String paramSpec = Classes.makeString(spec, start, (i - start) + 1);
Type type = type(paramSpec);
list.add(new Parameter
(index,
position,
paramSpec,
Classes.forCanonicalName(loader, paramSpec),
type.load));
++ index; ++ index;
++ position; position += type.size;
} }
footprint = position; footprint = position;
++ i; ++ i;
switch (spec[i]) { String paramSpec = Classes.makeString(spec, i, spec.length - i - 1);
case 'L': { Type type = type(paramSpec);
int start = i;
++ i;
while (spec[i] != ';') ++ i;
result = new Result result = new Result(paramSpec,
(Classes.makeString(spec, start, (i - start) + 1), areturn); Classes.forCanonicalName(loader, paramSpec),
} break; type.return_);
case '[': {
int start = i;
++ i;
while (spec[i] == '[') ++ i;
switch (spec[i]) {
case 'L':
++ i;
while (spec[i] != ';') ++ i;
break;
default:
break;
}
result = new Result(Classes.makeString(spec, start, (i - start) + 1),
areturn);
} break;
case 'V':
result = new Result(Classes.makeString(spec, i, 1), return_);
break;
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
result = new Result(Classes.makeString(spec, i, 1), ireturn);
break;
case 'F':
result = new Result(Classes.makeString(spec, i, 1), freturn);
break;
case 'J':
result = new Result(Classes.makeString(spec, i, 1), lreturn);
break;
case 'D':
result = new Result(Classes.makeString(spec, i, 1), dreturn);
break;
default: throw new AssertionError();
}
parameters = list; parameters = list;
} }
@ -207,7 +202,55 @@ public final class MethodType implements java.io.Serializable {
return result; return result;
} }
public class Parameter { private static Type type(String spec) {
switch (spec.charAt(0)) {
case 'L':
case '[':
return Type.ObjectType;
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
return Type.IntegerType;
case 'F':
return Type.FloatType;
case 'J':
return Type.LongType;
case 'D':
return Type.DoubleType;
case 'V':
return Type.VoidType;
default: throw new AssertionError();
}
}
private static enum Type {
ObjectType(aload, areturn, 1),
IntegerType(iload, ireturn, 1),
FloatType(fload, freturn, 1),
LongType(lload, lreturn, 1),
DoubleType(dload, dreturn, 1),
VoidType(-1, Assembler.return_, -1);
public final int load;
public final int return_;
public final int size;
private Type(int load, int return_, int size) {
this.load = load;
this.return_ = return_;
this.size = size;
}
}
public static class Parameter {
private final int index; private final int index;
private final int position; private final int position;
private final String spec; private final String spec;
@ -217,12 +260,13 @@ public final class MethodType implements java.io.Serializable {
private Parameter(int index, private Parameter(int index,
int position, int position,
String spec, String spec,
Class type,
int load) int load)
{ {
this.index = index; this.index = index;
this.position = position; this.position = position;
this.spec = spec; this.spec = spec;
this.type = Classes.forCanonicalName(loader, spec); this.type = type;
this.load = load; this.load = load;
} }
@ -243,14 +287,14 @@ public final class MethodType implements java.io.Serializable {
} }
} }
public class Result { public static class Result {
private final String spec; private final String spec;
private final Class type; private final Class type;
private final int return_; private final int return_;
public Result(String spec, int return_) { public Result(String spec, Class type, int return_) {
this.spec = spec; this.spec = spec;
this.type = Classes.forCanonicalName(loader, spec); this.type = type;
this.return_ = return_; this.return_ = return_;
} }

View File

@ -59,18 +59,6 @@ public class Method<T> extends AccessibleObject implements Member {
return getSpec(vmMethod); return getSpec(vmMethod);
} }
public String toString() {
StringBuilder sb = new StringBuilder();
if (vmMethod.class_ != null) {
sb.append(Classes.makeString(vmMethod.class_.name, 0,
vmMethod.class_.name.length - 1));
sb.append(".");
}
sb.append(getName());
sb.append(getSpec());
return sb.toString();
}
public static String getSpec(VMMethod vmMethod) { public static String getSpec(VMMethod vmMethod) {
return Classes.makeString(vmMethod.spec, 0, vmMethod.spec.length - 1); return Classes.makeString(vmMethod.spec, 0, vmMethod.spec.length - 1);
} }

View File

@ -1473,7 +1473,12 @@ ifneq ($(classpath),avian)
$(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMField.java \
$(classpath-src)/avian/VMMethod.java \ $(classpath-src)/avian/VMMethod.java \
$(classpath-src)/avian/avianvmresource/Handler.java \ $(classpath-src)/avian/avianvmresource/Handler.java \
$(classpath-src)/avian/file/Handler.java $(classpath-src)/avian/file/Handler.java \
$(classpath-src)/java/lang/invoke/MethodHandle.java \
$(classpath-src)/java/lang/invoke/MethodHandles.java \
$(classpath-src)/java/lang/invoke/MethodType.java \
$(classpath-src)/java/lang/invoke/LambdaMetafactory.java \
$(classpath-src)/java/lang/invoke/CallSite.java
ifeq ($(openjdk),) ifeq ($(openjdk),)
classpath-sources := $(classpath-sources) \ classpath-sources := $(classpath-sources) \

View File

@ -263,6 +263,16 @@ const unsigned ACC_INTERFACE = 1 << 9;
const unsigned ACC_ABSTRACT = 1 << 10; const unsigned ACC_ABSTRACT = 1 << 10;
const unsigned ACC_STRICT = 1 << 11; const unsigned ACC_STRICT = 1 << 11;
const unsigned REF_getField = 1;
const unsigned REF_getStatic = 2;
const unsigned REF_putField = 3;
const unsigned REF_putStatic = 4;
const unsigned REF_invokeVirtual = 5;
const unsigned REF_invokeStatic = 6;
const unsigned REF_invokeSpecial = 7;
const unsigned REF_newInvokeSpecial = 8;
const unsigned REF_invokeInterface = 9;
const int AVIAN_JNI_COMMIT = 1; const int AVIAN_JNI_COMMIT = 1;
const int AVIAN_JNI_ABORT = 2; const int AVIAN_JNI_ABORT = 2;

View File

@ -113,6 +113,13 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
cast<GcJclass>(t, reinterpret_cast<object>(arguments[0]))->vmClass()); cast<GcJclass>(t, reinterpret_cast<object>(arguments[0]))->vmClass());
} }
extern "C" AVIAN_EXPORT int64_t JNICALL
Avian_avian_Classes_toVMMethod(Thread* t, object, uintptr_t* arguments)
{
return reinterpret_cast<intptr_t>(t->m->classpath->getVMMethod(
t, cast<GcJmethod>(t, reinterpret_cast<object>(arguments[0]))));
}
extern "C" AVIAN_EXPORT void JNICALL extern "C" AVIAN_EXPORT void JNICALL
Avian_avian_Classes_initialize(Thread* t, object, uintptr_t* arguments) Avian_avian_Classes_initialize(Thread* t, object, uintptr_t* arguments)
{ {

View File

@ -484,6 +484,7 @@ class MyClasspath : public Classpath {
} }
oarray = charArray; oarray = charArray;
offset = 0;
} else { } else {
expect(t, objectClass(t, oarray) == type(t, GcCharArray::Type)); expect(t, objectClass(t, oarray) == type(t, GcCharArray::Type));
} }

View File

@ -7351,6 +7351,12 @@ GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
array->setBodyElement(t, i + argument, type); array->setBodyElement(t, i + argument, type);
} else if (strncmp(p, methodHandle, strlen(methodHandle)) == 0) { } else if (strncmp(p, methodHandle, strlen(methodHandle)) == 0) {
GcReference* reference = cast<GcReference>(
t,
singletonObject(
t, invocation->pool(), bootstrapArray->body()[i + 1]));
int kind = reference->kind();
GcMethod* method = cast<GcMethod>(t, GcMethod* method = cast<GcMethod>(t,
resolve(t, resolve(t,
c->loader(), c->loader(),
@ -7359,7 +7365,8 @@ GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
findMethodInClass, findMethodInClass,
GcNoSuchMethodError::Type)); GcNoSuchMethodError::Type));
GcMethodHandle* handle = makeMethodHandle(t, c->loader(), method, 0); GcMethodHandle* handle
= makeMethodHandle(t, kind, c->loader(), method, 0);
array->setBodyElement(t, i + argument, handle); array->setBodyElement(t, i + argument, handle);
} else { } else {
@ -7396,9 +7403,10 @@ GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
++i; ++i;
} }
GcMethodHandle* handle = (bootstrap->flags() & ACC_STATIC) GcMethodHandle* handle
? 0 = (bootstrap->flags() & ACC_STATIC)
: makeMethodHandle(t, c->loader(), bootstrap, 0); ? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
return cast<GcCallSite>( return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array)); t, t->m->processor->invokeArray(t, bootstrap, handle, array));

View File

@ -1,4 +1,10 @@
public class InvokeDynamic { public class InvokeDynamic {
private final int foo;
private InvokeDynamic(int foo) {
this.foo = foo;
}
private interface Operation { private interface Operation {
int operate(int a, int b); int operate(int a, int b);
} }
@ -10,6 +16,14 @@ public class InvokeDynamic {
public static void main(String[] args) { public static void main(String[] args) {
int c = 4; int c = 4;
Operation op = (a, b) -> a + b - c; Operation op = (a, b) -> a + b - c;
expect(op.operate(2, 3) == 1); expect(op.operate(2, 3) == (2 + 3) - 4);
new InvokeDynamic(3).test();
}
private void test() {
int c = 2;
Operation op = (a, b) -> ((a + b) * c) - foo;
expect(op.operate(2, 3) == ((2 + 3) * 2) - foo);
} }
} }