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
cache: apt
jdk:
- oraclejdk8
os:
- linux
- osx

View File

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

View File

@ -155,7 +155,19 @@ public class LambdaMetafactory {
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
(pool,
Classes.makeString(implementation.method.class_.name, 0,
@ -213,11 +225,9 @@ public class LambdaMetafactory {
try {
methodTable.add
(new MethodData
(Modifier.STATIC,
(Modifier.PUBLIC | Modifier.STATIC,
ConstantPool.addUtf8(pool, "make"),
ConstantPool.addUtf8(pool, Classes.makeString
(invokedType.spec, 0,
invokedType.spec.length - 1)),
ConstantPool.addUtf8(pool, invokedType.toMethodDescriptorString()),
makeFactoryCode(pool, className, constructorSpec, invokedType)));
methodTable.add
@ -231,9 +241,7 @@ public class LambdaMetafactory {
(new MethodData
(Modifier.PUBLIC,
ConstantPool.addUtf8(pool, invokedName),
ConstantPool.addUtf8(pool, Classes.makeString
(methodType.spec, 0,
methodType.spec.length - 1)),
ConstantPool.addUtf8(pool, methodType.toMethodDescriptorString()),
makeInvocationCode(pool, className, constructorSpec, invokedType,
methodType, methodImplementation)));
} catch (IOException e) {
@ -262,10 +270,11 @@ public class LambdaMetafactory {
try {
return new CallSite
(new MethodHandle
(invokedType.loader, avian.SystemClassLoader.getClass
(avian.Classes.defineVMClass
(invokedType.loader, classData, 0, classData.length))
.getMethod("make", invokedType.parameterArray()).vmMethod));
(MethodHandle.REF_invokeStatic, invokedType.loader, Classes.toVMMethod
(avian.SystemClassLoader.getClass
(avian.Classes.defineVMClass
(invokedType.loader, classData, 0, classData.length))
.getMethod("make", invokedType.parameterArray()))));
} catch (NoSuchMethodException e) {
AssertionError error = new AssertionError();
error.initCause(e);

View File

@ -1,18 +1,35 @@
package java.lang.invoke;
import avian.Classes;
public class MethodHandle {
static final int REF_invokeStatic = 6;
static final int REF_invokeSpecial = 7;
final int kind;
private final ClassLoader loader;
final avian.VMMethod method;
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.method = method;
}
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() {
if (type == null) {

View File

@ -2,12 +2,18 @@ package java.lang.invoke;
import static avian.Assembler.*;
import avian.Assembler;
import avian.Classes;
import avian.VMClass;
import java.util.List;
import java.util.ArrayList;
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 byte[] spec;
private volatile List<Parameter> parameters;
@ -19,6 +25,77 @@ public final class MethodType implements java.io.Serializable {
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() {
return Classes.makeString(spec, 0, spec.length - 1);
}
@ -53,21 +130,14 @@ public final class MethodType implements java.io.Serializable {
int index = 0;
int position = 0;
for (i = 1; spec[i] != ')'; ++i) {
int start = i;
switch (spec[i]) {
case 'L': {
int start = i;
++ i;
while (spec[i] != ';') ++ i;
list.add(new Parameter
(index,
position,
Classes.makeString(spec, start, (i - start) + 1),
aload));
} break;
case '[': {
int start = i;
++ i;
while (spec[i] == '[') ++ i;
@ -80,12 +150,6 @@ public final class MethodType implements java.io.Serializable {
default:
break;
}
list.add(new Parameter
(index,
position,
Classes.makeString(spec, start, (i - start) + 1),
aload));
} break;
case 'Z':
@ -93,107 +157,38 @@ public final class MethodType implements java.io.Serializable {
case 'S':
case 'C':
case 'I':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
iload));
break;
case 'F':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
fload));
break;
case 'J':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
lload));
++ position;
break;
case 'D':
list.add(new Parameter
(index,
position,
Classes.makeString(spec, i, 1),
dload));
++ position;
break;
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;
++ position;
position += type.size;
}
footprint = position;
++ i;
switch (spec[i]) {
case 'L': {
int start = i;
++ i;
while (spec[i] != ';') ++ i;
result = new Result
(Classes.makeString(spec, start, (i - start) + 1), areturn);
} break;
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();
}
String paramSpec = Classes.makeString(spec, i, spec.length - i - 1);
Type type = type(paramSpec);
result = new Result(paramSpec,
Classes.forCanonicalName(loader, paramSpec),
type.return_);
parameters = list;
}
@ -207,7 +202,55 @@ public final class MethodType implements java.io.Serializable {
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 position;
private final String spec;
@ -217,12 +260,13 @@ public final class MethodType implements java.io.Serializable {
private Parameter(int index,
int position,
String spec,
Class type,
int load)
{
this.index = index;
this.position = position;
this.spec = spec;
this.type = Classes.forCanonicalName(loader, spec);
this.type = type;
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 Class type;
private final int return_;
public Result(String spec, int return_) {
public Result(String spec, Class type, int return_) {
this.spec = spec;
this.type = Classes.forCanonicalName(loader, spec);
this.type = type;
this.return_ = return_;
}

View File

@ -58,18 +58,6 @@ public class Method<T> extends AccessibleObject implements Member {
private String getSpec() {
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) {
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/VMMethod.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),)
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_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_ABORT = 2;

View File

@ -113,6 +113,13 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
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
Avian_avian_Classes_initialize(Thread* t, object, uintptr_t* arguments)
{

View File

@ -484,6 +484,7 @@ class MyClasspath : public Classpath {
}
oarray = charArray;
offset = 0;
} else {
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);
} 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,
resolve(t,
c->loader(),
@ -7359,7 +7365,8 @@ GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
findMethodInClass,
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);
} else {
@ -7396,9 +7403,10 @@ GcCallSite* resolveDynamic(MyThread* t, GcInvocation* invocation)
++i;
}
GcMethodHandle* handle = (bootstrap->flags() & ACC_STATIC)
? 0
: makeMethodHandle(t, c->loader(), bootstrap, 0);
GcMethodHandle* handle
= (bootstrap->flags() & ACC_STATIC)
? 0
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
return cast<GcCallSite>(
t, t->m->processor->invokeArray(t, bootstrap, handle, array));

View File

@ -1,4 +1,10 @@
public class InvokeDynamic {
private final int foo;
private InvokeDynamic(int foo) {
this.foo = foo;
}
private interface Operation {
int operate(int a, int b);
}
@ -10,6 +16,14 @@ public class InvokeDynamic {
public static void main(String[] args) {
int c = 4;
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);
}
}