diff --git a/classpath/java/lang/InternalError.java b/classpath/java/lang/InternalError.java new file mode 100644 index 0000000000..69ac254db4 --- /dev/null +++ b/classpath/java/lang/InternalError.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2008-2015, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class InternalError extends VirtualMachineError { + public InternalError(String message) { + super(message); + } + + public InternalError() { + this(null); + } +} diff --git a/classpath/java/lang/TypeNotPresentException.java b/classpath/java/lang/TypeNotPresentException.java new file mode 100644 index 0000000000..eb1f31ed73 --- /dev/null +++ b/classpath/java/lang/TypeNotPresentException.java @@ -0,0 +1,21 @@ +/* Copyright (c) 2008-2015, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +public class TypeNotPresentException extends Exception { + public TypeNotPresentException(String message) { + super(message); + } + + public TypeNotPresentException() { + this(null); + } +} diff --git a/classpath/java/lang/invoke/CallSite.java b/classpath/java/lang/invoke/CallSite.java new file mode 100644 index 0000000000..a6c221e8de --- /dev/null +++ b/classpath/java/lang/invoke/CallSite.java @@ -0,0 +1,4 @@ +package java.lang.invoke; + +public abstract class CallSite { +} diff --git a/classpath/java/lang/invoke/LambdaConversionException.java b/classpath/java/lang/invoke/LambdaConversionException.java new file mode 100644 index 0000000000..4502b1c7d8 --- /dev/null +++ b/classpath/java/lang/invoke/LambdaConversionException.java @@ -0,0 +1,9 @@ +package java.lang.invoke; + +public class LambdaConversionException extends java.lang.Exception { + public LambdaConversionException() { throw new RuntimeException(); } + public LambdaConversionException(String s) { throw new RuntimeException(); } + public LambdaConversionException(String s, Throwable th) { throw new RuntimeException(); } + public LambdaConversionException(Throwable th) { throw new RuntimeException(); } + public LambdaConversionException(String s, Throwable th, boolean b, boolean b2) { throw new RuntimeException(); } +} diff --git a/classpath/java/lang/invoke/LambdaMetafactory.java b/classpath/java/lang/invoke/LambdaMetafactory.java new file mode 100644 index 0000000000..88c4b9129f --- /dev/null +++ b/classpath/java/lang/invoke/LambdaMetafactory.java @@ -0,0 +1,5 @@ +package java.lang.invoke; + +public class LambdaMetafactory { + public static CallSite metafactory(MethodHandles.Lookup l, String s, MethodType mt, MethodType mt2, MethodHandle mh, MethodType mt3) throws LambdaConversionException { throw new RuntimeException(); } +} diff --git a/classpath/java/lang/invoke/MethodHandle.java b/classpath/java/lang/invoke/MethodHandle.java new file mode 100644 index 0000000000..c0505c07fd --- /dev/null +++ b/classpath/java/lang/invoke/MethodHandle.java @@ -0,0 +1,3 @@ +package java.lang.invoke; +public abstract class MethodHandle { +} diff --git a/classpath/java/lang/invoke/MethodHandles.java b/classpath/java/lang/invoke/MethodHandles.java new file mode 100644 index 0000000000..bbe782dd3a --- /dev/null +++ b/classpath/java/lang/invoke/MethodHandles.java @@ -0,0 +1,5 @@ +package java.lang.invoke; +public class MethodHandles { + public static class Lookup { + } +} diff --git a/classpath/java/lang/invoke/MethodType.java b/classpath/java/lang/invoke/MethodType.java new file mode 100644 index 0000000000..58e59022db --- /dev/null +++ b/classpath/java/lang/invoke/MethodType.java @@ -0,0 +1,3 @@ +package java.lang.invoke; +public final class MethodType implements java.io.Serializable { +} diff --git a/invoke.sh b/invoke.sh new file mode 100644 index 0000000000..30c76e186c --- /dev/null +++ b/invoke.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +unzip -l /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home/jre/lib/rt.jar | \ + grep java/lang/invoke | \ + grep -E '\$' | \ + awk '{print $4}' | \ + sed -E -e 's/\.class//g' | \ + while read path; do + echo $path + name=$(echo $path | sed -e 's|/|.|g') + + if javap -public $name | grep -q "public.*interface"; then + javap -public $name | grep -v "Compiled from" | \ + sed -E \ + -e 's/java.lang.invoke.//g' \ + -e 's/java.lang.Object/Object o/g' \ + -e 's/java.lang.reflect.Method/Method o/g' \ + -e 's/java.lang.String/String s/g' \ + -e 's/java.lang.Throwable/Throwable/g' \ + -e 's/int/int i/g' \ + -e 's/byte/byte b/g' \ + -e 's/boolean/boolean b/g' \ + -e 's/MethodType/MethodType mt/g' \ + -e 's/MethodHandle/MethodHandle mh/g' \ + -e 's/java.lang.Class\<\?\>/Class\<\?\> c/g' \ + -e 's/;/ { throw new RuntimeException(); }/g' \ + -e 's/public String s/public String/g' \ + -e 's/public static String s/public static String/g' \ + -e 's/public abstract MethodHandle mh/public abstract MethodHandle/g' \ + -e 's/public abstract MethodHandle mh/public abstract MethodHandle/g' \ + -e 's/public boolean b/public boolean/g' \ + -e 's/public int i/public int/g' \ + -e 's/public static final int i/public static final int/g' \ + -e 's/public byte b/public byte/g' \ + -e 's/public Object o/public Object/g' \ + -e 's/public MethodType mt/public MethodType/g' \ + -e 's/public MethodHandle mh/public MethodHandle/g' \ + -e 's/Object o\.\.\./Object... o/g' \ + -e 's/public final native Object o/public final native Object/g' \ + -e 's/public Class c/public Class/g' \ + > classpath/${path}.java + fi + done diff --git a/makefile b/makefile index 906fafb89c..037724ad2e 100755 --- a/makefile +++ b/makefile @@ -1689,7 +1689,7 @@ $(classpath-dep): $(classpath-sources) $(classpath-jar-dep) classes="$(shell $(MAKE) -s --no-print-directory build=$(build) \ $(classpath-classes) arch=$(build-arch) platform=$(bootimage-platform))"; \ if [ -n "$${classes}" ]; then \ - $(javac) -source 1.6 -target 1.6 \ + $(javac) -source 1.8 -target 1.8 \ -d $(classpath-build) -bootclasspath $(boot-classpath) \ $${classes}; fi @touch $(@) @@ -1765,7 +1765,7 @@ $(test-dep): $(test-sources) $(test-library) @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ - $(javac) -source 1.6 -target 1.6 \ + $(javac) -source 1.8 -target 1.8 \ -classpath $(test-build) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ @@ -1777,7 +1777,7 @@ $(test-extra-dep): $(test-extra-sources) @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ if test -n "$${files}"; then \ - $(javac) -source 1.6 -target 1.6 \ + $(javac) -source 1.8 -target 1.8 \ -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk index 4e1d1bdf5e..f357df6520 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -49,6 +49,7 @@ openjdk-sources = \ $(openjdk-src)/share/native/java/util/zip/zip_util.c \ $(openjdk-src)/share/native/sun/management/VMManagementImpl.c \ $(openjdk-src)/share/native/sun/misc/GC.c \ + $(openjdk-src)/share/native/sun/misc/URLClassPath.c \ $(openjdk-src)/share/native/sun/misc/MessageUtils.c \ $(openjdk-src)/share/native/sun/misc/NativeSignalHandler.c \ $(openjdk-src)/share/native/sun/misc/Signal.c \ @@ -121,6 +122,7 @@ openjdk-headers-classes = \ sun.misc.VM \ sun.misc.VMSupport \ sun.misc.Version \ + sun.misc.URLClassPath \ sun.net.spi.DefaultProxySelector \ sun.nio.ch.FileKey \ sun.nio.ch.FileChannelImpl \ diff --git a/src/avian/constants.h b/src/avian/constants.h index 7939a2ec68..d40d58b055 100644 --- a/src/avian/constants.h +++ b/src/avian/constants.h @@ -146,6 +146,7 @@ enum OpCode { imul = 0x68, ineg = 0x74, instanceof = 0xc1, + invokedynamic = 0xba, invokeinterface = 0xb9, invokespecial = 0xb7, invokestatic = 0xb8, diff --git a/src/avian/target-fields.h b/src/avian/target-fields.h index 10421f5ce0..ac4402ece1 100644 --- a/src/avian/target-fields.h +++ b/src/avian/target-fields.h @@ -30,7 +30,8 @@ #define TARGET_THREAD_HEAPIMAGE 2312 #define TARGET_THREAD_CODEIMAGE 2320 #define TARGET_THREAD_THUNKTABLE 2328 -#define TARGET_THREAD_STACKLIMIT 2376 +#define TARGET_THREAD_DYNAMICTABLE 2336 +#define TARGET_THREAD_STACKLIMIT 2384 #elif(TARGET_BYTES_PER_WORD == 4) @@ -50,7 +51,8 @@ #define TARGET_THREAD_HEAPIMAGE 2192 #define TARGET_THREAD_CODEIMAGE 2196 #define TARGET_THREAD_THUNKTABLE 2200 -#define TARGET_THREAD_STACKLIMIT 2224 +#define TARGET_THREAD_DYNAMICTABLE 2204 +#define TARGET_THREAD_STACKLIMIT 2228 #else #error diff --git a/src/bootimage-fields.cpp b/src/bootimage-fields.cpp index 761eef88e5..1cd72c73ea 100644 --- a/src/bootimage-fields.cpp +++ b/src/bootimage-fields.cpp @@ -34,6 +34,7 @@ FIELD(virtualThunks) THUNK_FIELD(default_); THUNK_FIELD(defaultVirtual); +THUNK_FIELD(defaultDynamic); THUNK_FIELD(native); THUNK_FIELD(aioob); THUNK_FIELD(stackOverflow); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 10a3f89204..946528aaca 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2091,12 +2091,21 @@ void interceptFileOperations(Thread* t, bool updateRuntimeData) if (fileInputStreamFdField) { cp->fileInputStreamFdField = fileInputStreamFdField->offset(); - intercept(t, - fileInputStreamClass, - "open", - "(Ljava/lang/String;)V", - voidPointer(openFile), - updateRuntimeData); + if (findMethodOrNull(t, fileInputStreamClass, "open0", "(Ljava/lang/String;)V") != 0) { + intercept(t, + fileInputStreamClass, + "open0", + "(Ljava/lang/String;)V", + voidPointer(openFile), + updateRuntimeData); + } else { + intercept(t, + fileInputStreamClass, + "open", + "(Ljava/lang/String;)V", + voidPointer(openFile), + updateRuntimeData); + } if (findMethodOrNull(t, fileInputStreamClass, "read0", "()I") != 0) { intercept(t, diff --git a/src/compile.cpp b/src/compile.cpp index 276481580c..be2cc48d4e 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -58,7 +58,7 @@ namespace { namespace local { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -83,6 +83,7 @@ const unsigned InitialZoneCapacityInBytes = 64 * 1024; enum ThunkIndex { compileMethodIndex, compileVirtualMethodIndex, + linkDynamicMethodIndex, invokeNativeIndex, throwArrayIndexOutOfBoundsIndex, throwStackOverflowIndex, @@ -295,6 +296,7 @@ class MyThread : public Thread { uintptr_t* heapImage; uint8_t* codeImage; void** thunkTable; + void** dynamicTable; CallTrace* trace; Reference* reference; avian::codegen::Architecture* arch; @@ -1278,6 +1280,93 @@ class Context { Slice argumentBuffer; }; +unsigned& dynamicIndex(MyThread* t); + +void**& dynamicTable(MyThread* t); + +void updateDynamicTable(MyThread* t, MyThread* o) +{ + o->dynamicTable = dynamicTable(t); + if (t->peer) + updateDynamicTable(static_cast(t->peer), o); + if (t->child) + updateDynamicTable(static_cast(t->child), o); +} + +uintptr_t defaultDynamicThunk(MyThread* t); + +uintptr_t compileVirtualThunk(MyThread* t, + unsigned index, + unsigned* size, + uintptr_t thunk, + const char* baseName); + + +unsigned addDynamic(MyThread* t, GcInvocation* invocation) +{ + ACQUIRE(t, t->m->classLock); + + int index = invocation->index(); + if (index == -1) { + index = dynamicIndex(t)++; + invocation->index() = index; + + unsigned oldCapacity = roots(t)->invocations() + ? roots(t)->invocations()->length() + : 0; + + if (static_cast(index) >= oldCapacity) { + unsigned newCapacity = oldCapacity ? 2 * oldCapacity : 4096; + + void** newTable = static_cast( + t->m->heap->allocate(newCapacity * BytesPerWord)); + + GcArray* newData = makeArray(t, newCapacity); + PROTECT(t, newData); + + GcWordArray* newThunks = makeWordArray(t, newCapacity * 2); + PROTECT(t, newThunks); + + if (dynamicTable(t)) { + memcpy(newTable, dynamicTable(t), oldCapacity * BytesPerWord); + + for(size_t i = 0; i < oldCapacity; i++) { + newData->setBodyElement(t, i, + roots(t)->invocations()->body()[i]); + } + + + mark(t, newData, ArrayBody, oldCapacity); + + memcpy(newThunks->body().begin(), + compileRoots(t)->dynamicThunks()->body().begin(), + compileRoots(t)->dynamicThunks()->length() * BytesPerWord); + } + + ENTER(t, Thread::ExclusiveState); + + dynamicTable(t) = newTable; + roots(t)->setInvocations(t, newData); + + updateDynamicTable(static_cast(t->m->rootThread), t); + + compileRoots(t)->setDynamicThunks(t, newThunks); + } + + unsigned size; + uintptr_t thunk = compileVirtualThunk( + t, index, &size, defaultDynamicThunk(t), "dynamicThunk"); + compileRoots(t)->dynamicThunks()->body()[index * 2] = thunk; + compileRoots(t)->dynamicThunks()->body()[(index * 2) + 1] = size; + + t->dynamicTable[index] = reinterpret_cast(thunk); + + roots(t)->invocations()->setBodyElement(t, index, invocation); + } + + return index; +} + unsigned translateLocalIndex(Context* context, unsigned footprint, unsigned index) @@ -4944,6 +5033,53 @@ loop: args(c->threadRegister(), frame->append(argument), instance))); } break; + case invokedynamic: { + context->leaf = false; + + uint16_t poolIndex = codeReadInt16(t, code, ip); + ip += 2; + + GcInvocation* invocation = cast( + t, + singletonObject(t, context->method->code()->pool(), poolIndex - 1)); + + PROTECT(t, invocation); + + invocation->setClass(t, context->method->class_()); + + unsigned index = addDynamic(t, invocation); + + GcMethod* template_ = invocation->template_(); + unsigned returnCode = template_->returnCode(); + unsigned rSize = resultSize(t, returnCode); + unsigned parameterFootprint = template_->parameterFootprint(); + + // TODO: can we allow tailCalls in general? + // e.g. what happens if the call site is later bound to a method that can't be tail called? + // NOTE: calling isTailCall right now would cause an segfault, since + // invocation->template_()->class_() will be null. + // bool tailCall + // = isTailCall(t, code, ip, context->method, invocation->template_()); + bool tailCall = false; + + // todo: do we need to tell the compiler to add a load barrier + // here for VolatileCallSite instances? + + ir::Value* result = c->stackCall( + c->memory(c->memory(c->threadRegister(), ir::Type::object(), + TARGET_THREAD_DYNAMICTABLE), + ir::Type::object(), index * TargetBytesPerWord), + tailCall ? Compiler::TailJump : 0, frame->trace(0, 0), + operandTypeForFieldCode(t, returnCode), + frame->peekMethodArguments(parameterFootprint)); + + frame->popFootprint(parameterFootprint); + + if (rSize) { + frame->pushReturnValue(returnCode, result); + } + } break; + case invokeinterface: { context->leaf = false; @@ -6914,13 +7050,13 @@ void finish(MyThread* t, FixedAllocator* allocator, Context* context) reinterpret_cast(context->method->spec()->body().begin())); // for debugging: - if (false + if (true and ::strcmp(reinterpret_cast( context->method->class_()->name()->body().begin()), - "java/lang/System") == 0 + "InvokeDynamic") == 0 and ::strcmp(reinterpret_cast( context->method->name()->body().begin()), - "") == 0) { + "main") == 0) { trap(); } syncInstructionCache(start, codeSize); @@ -8317,6 +8453,7 @@ class MyProcessor : public Processor { public: Thunk default_; Thunk defaultVirtual; + Thunk defaultDynamic; Thunk native; Thunk aioob; Thunk stackOverflow; @@ -8342,8 +8479,10 @@ class MyProcessor : public Processor { GcArithmeticException::FixedSize), codeAllocator(s, Slice(0, 0)), callTableSize(0), + dynamicIndex(0), useNativeFeatures(useNativeFeatures), - compilationHandlers(0) + compilationHandlers(0), + dynamicTable(0) { thunkTable[compileMethodIndex] = voidPointer(local::compileMethod); thunkTable[compileVirtualMethodIndex] = voidPointer(compileVirtualMethod); @@ -8429,6 +8568,10 @@ class MyProcessor : public Processor { TARGET_THREAD_THUNKTABLE, &MyThread::thunkTable, "TARGET_THREAD_THUNKTABLE") + + checkConstant(t, + TARGET_THREAD_DYNAMICTABLE, + &MyThread::dynamicTable, + "TARGET_THREAD_DYNAMICTABLE") + checkConstant(t, TARGET_THREAD_STACKLIMIT, &MyThread::stackLimit, @@ -8993,7 +9136,7 @@ class MyProcessor : public Processor { if (image and code) { local::boot(static_cast(t), image, code); } else { - roots = makeCompileRoots(t, 0, 0, 0, 0, 0, 0, 0, 0, 0); + roots = makeCompileRoots(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); { GcArray* ct = makeArray(t, 128); @@ -9096,11 +9239,23 @@ class MyProcessor : public Processor { ThunkCollection thunks; ThunkCollection bootThunks; unsigned callTableSize; + unsigned dynamicIndex; bool useNativeFeatures; void* thunkTable[dummyIndex + 1]; CompilationHandlerList* compilationHandlers; + void** dynamicTable; }; +unsigned& dynamicIndex(MyThread* t) +{ + return static_cast(t->m->processor)->dynamicIndex; +} + +void**& dynamicTable(MyThread* t) +{ + return static_cast(t->m->processor)->dynamicTable; +} + const char* stringOrNull(const char* str) { if (str) { @@ -9240,15 +9395,16 @@ bool isThunkUnsafeStack(MyProcessor::Thunk* thunk, void* ip) bool isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) { - const unsigned NamedThunkCount = 5; + const unsigned NamedThunkCount = 6; MyProcessor::Thunk table[NamedThunkCount + ThunkCount]; table[0] = thunks->default_; table[1] = thunks->defaultVirtual; - table[2] = thunks->native; - table[3] = thunks->aioob; - table[4] = thunks->stackOverflow; + table[2] = thunks->defaultDynamic; + table[3] = thunks->native; + table[4] = thunks->aioob; + table[5] = thunks->stackOverflow; for (unsigned i = 0; i < ThunkCount; ++i) { new (table + NamedThunkCount + i) @@ -9598,8 +9754,8 @@ void findThunks(MyThread* t, BootImage* image, uint8_t* code) MyProcessor* p = processor(t); p->bootThunks.default_ = thunkToThunk(image->thunks.default_, code); - p->bootThunks.defaultVirtual - = thunkToThunk(image->thunks.defaultVirtual, code); + p->bootThunks.defaultVirtual = thunkToThunk(image->thunks.defaultVirtual, code); + p->bootThunks.defaultDynamic = thunkToThunk(image->thunks.defaultDynamic, code); p->bootThunks.native = thunkToThunk(image->thunks.native, code); p->bootThunks.aioob = thunkToThunk(image->thunks.aioob, code); p->bootThunks.stackOverflow = thunkToThunk(image->thunks.stackOverflow, code); @@ -9807,6 +9963,68 @@ void compileCall(MyThread* t, Context* c, ThunkIndex index, bool call = true) } } +void compileDefaultThunk(MyThread* t, + FixedAllocator* allocator, + MyProcessor::Thunk* thunk, + const char* name, + ThunkIndex thunkIndex, + bool hasTarget) +{ + Context context(t); + avian::codegen::Assembler* a = context.assembler; + + if(hasTarget) { + lir::RegisterPair class_(t->arch->virtualCallTarget()); + lir::Memory virtualCallTargetSrc( + t->arch->stack(), + (t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()) + * TargetBytesPerWord); + + a->apply(lir::Move, + OperandInfo( + TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallTargetSrc), + OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &class_)); + + lir::Memory virtualCallTargetDst(t->arch->thread(), + TARGET_THREAD_VIRTUALCALLTARGET); + + a->apply( + lir::Move, + OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &class_), + OperandInfo( + TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallTargetDst)); + } + + lir::RegisterPair index(t->arch->virtualCallIndex()); + lir::Memory virtualCallIndex(t->arch->thread(), + TARGET_THREAD_VIRTUALCALLINDEX); + + a->apply( + lir::Move, + OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &index), + OperandInfo(TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallIndex)); + + a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); + + thunk->frameSavedOffset = a->length(); + + lir::RegisterPair thread(t->arch->thread()); + a->pushFrame(1, TargetBytesPerWord, lir::Operand::Type::RegisterPair, &thread); + + compileCall(t, &context, thunkIndex); + + a->popFrame(t->arch->alignFrameSize(1)); + + lir::RegisterPair result(t->arch->returnLow()); + a->apply(lir::Jump, + OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &result)); + + thunk->length = a->endBlock(false)->resolve(0, 0); + + thunk->start = finish( + t, allocator, a, name, thunk->length); +} + void compileThunks(MyThread* t, FixedAllocator* allocator) { MyProcessor* p = processor(t); @@ -9836,59 +10054,13 @@ void compileThunks(MyThread* t, FixedAllocator* allocator) = finish(t, allocator, a, "default", p->thunks.default_.length); } - { - Context context(t); - avian::codegen::Assembler* a = context.assembler; + compileDefaultThunk + (t, allocator, &(p->thunks.defaultVirtual), "defaultVirtual", + compileVirtualMethodIndex, true); - lir::RegisterPair class_(t->arch->virtualCallTarget()); - lir::Memory virtualCallTargetSrc( - t->arch->stack(), - (t->arch->frameFooterSize() + t->arch->frameReturnAddressSize()) - * TargetBytesPerWord); - - a->apply(lir::Move, - OperandInfo( - TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallTargetSrc), - OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &class_)); - - lir::Memory virtualCallTargetDst(t->arch->thread(), - TARGET_THREAD_VIRTUALCALLTARGET); - - a->apply( - lir::Move, - OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &class_), - OperandInfo( - TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallTargetDst)); - - lir::RegisterPair index(t->arch->virtualCallIndex()); - lir::Memory virtualCallIndex(t->arch->thread(), - TARGET_THREAD_VIRTUALCALLINDEX); - - a->apply( - lir::Move, - OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &index), - OperandInfo(TargetBytesPerWord, lir::Operand::Type::Memory, &virtualCallIndex)); - - a->saveFrame(TARGET_THREAD_STACK, TARGET_THREAD_IP); - - p->thunks.defaultVirtual.frameSavedOffset = a->length(); - - lir::RegisterPair thread(t->arch->thread()); - a->pushFrame(1, TargetBytesPerWord, lir::Operand::Type::RegisterPair, &thread); - - compileCall(t, &context, compileVirtualMethodIndex); - - a->popFrame(t->arch->alignFrameSize(1)); - - lir::RegisterPair result(t->arch->returnLow()); - a->apply(lir::Jump, - OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &result)); - - p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0); - - p->thunks.defaultVirtual.start = finish( - t, allocator, a, "defaultVirtual", p->thunks.defaultVirtual.length); - } + compileDefaultThunk + (t, allocator, &(p->thunks.defaultDynamic), "defaultDynamic", + linkDynamicMethodIndex, false); { Context context(t); @@ -10040,6 +10212,11 @@ uintptr_t defaultVirtualThunk(MyThread* t) return reinterpret_cast(processor(t)->thunks.defaultVirtual.start); } +uintptr_t defaultDynamicThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->thunks.defaultDynamic.start); +} + uintptr_t nativeThunk(MyThread* t) { return reinterpret_cast(processor(t)->thunks.native.start); @@ -10056,7 +10233,11 @@ bool unresolved(MyThread* t, uintptr_t methodAddress) or methodAddress == bootDefaultThunk(t); } -uintptr_t compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) +uintptr_t compileVirtualThunk(MyThread* t, + unsigned index, + unsigned* size, + uintptr_t thunk, + const char* baseName) { Context context(t); avian::codegen::Assembler* a = context.assembler; @@ -10069,11 +10250,10 @@ uintptr_t compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) OperandInfo(TargetBytesPerWord, lir::Operand::Type::Constant, &indexConstant), OperandInfo(TargetBytesPerWord, lir::Operand::Type::RegisterPair, &indexRegister)); - avian::codegen::ResolvedPromise defaultVirtualThunkPromise( - defaultVirtualThunk(t)); - lir::Constant thunk(&defaultVirtualThunkPromise); + avian::codegen::ResolvedPromise promise(thunk); + lir::Constant target(&promise); a->apply(lir::Jump, - OperandInfo(TargetBytesPerWord, lir::Operand::Type::Constant, &thunk)); + OperandInfo(TargetBytesPerWord, lir::Operand::Type::Constant, &target)); *size = a->endBlock(false)->resolve(0, 0); @@ -10083,8 +10263,7 @@ uintptr_t compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) a->setDestination(start); a->write(); - const char* const virtualThunkBaseName = "virtualThunk"; - const size_t virtualThunkBaseNameLength = strlen(virtualThunkBaseName); + const size_t virtualThunkBaseNameLength = strlen(baseName); const size_t maxIntStringLength = 10; THREAD_RUNTIME_ARRAY(t, @@ -10094,7 +10273,7 @@ uintptr_t compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) sprintf(RUNTIME_ARRAY_BODY(virtualThunkName), "%s%d", - virtualThunkBaseName, + baseName, index); logCompile(t, start, *size, 0, RUNTIME_ARRAY_BODY(virtualThunkName), 0); @@ -10120,7 +10299,7 @@ uintptr_t virtualThunk(MyThread* t, unsigned index) if (oldArray->body()[index * 2] == 0) { unsigned size; - uintptr_t thunk = compileVirtualThunk(t, index, &size); + uintptr_t thunk = compileVirtualThunk(t, index, &size, defaultVirtualThunk(t), "virtualThunk"); oldArray->body()[index * 2] = thunk; oldArray->body()[(index * 2) + 1] = size; } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5a7fc27d66..fdfe120347 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -3784,3 +3784,22 @@ extern "C" AVIAN_EXPORT jint JNICALL return run(*t, local::boot, 0) ? 0 : -1; } + +extern "C" AVIAN_EXPORT jstring JNICALL JVM_GetTemporaryDirectory(JNIEnv* e UNUSED) +{ + // Unimplemented + // This is used in newer builds of openjdk8, as a place to store statistics or something... + abort(); +} + +extern "C" AVIAN_EXPORT jboolean JNICALL JVM_KnownToNotExist(JNIEnv* e UNUSED, jobject loader UNUSED, jstring classname UNUSED) +{ + // Unimplemented + abort(); +} + +extern "C" AVIAN_EXPORT jintArray JNICALL JVM_GetResourceLookupCache(JNIEnv* e UNUSED, jobject loader UNUSED, jstring resourcename UNUSED) +{ + // Unimplemented + abort(); +} diff --git a/src/tools/bootimage-generator/main.cpp b/src/tools/bootimage-generator/main.cpp index 3a9736dc8e..9d5ab08769 100644 --- a/src/tools/bootimage-generator/main.cpp +++ b/src/tools/bootimage-generator/main.cpp @@ -398,7 +398,8 @@ GcTriple* makeCodeImage(Thread* t, RUNTIME_ARRAY_BODY(types)[1] = Type_intptr_t; for (unsigned i = 2; i < count + 2; ++i) { - switch (s.read1()) { + unsigned constType = s.read1(); + switch (constType) { case CONSTANT_Class: case CONSTANT_String: RUNTIME_ARRAY_BODY(types)[i] = Type_object; @@ -436,7 +437,25 @@ GcTriple* makeCodeImage(Thread* t, s.skip(s.read2()); break; + + + case CONSTANT_MethodHandle: + RUNTIME_ARRAY_BODY(types)[i] = Type_object; + s.skip(3); + break; + + case CONSTANT_MethodType: + RUNTIME_ARRAY_BODY(types)[i] = Type_object; + s.skip(2); + break; + + case CONSTANT_InvokeDynamic: + RUNTIME_ARRAY_BODY(types)[i] = Type_object; + s.skip(4); + break; + default: + fprintf(stderr, "unknown class constant: %d\n", constType); abort(t); } } diff --git a/src/types.def b/src/types.def index a140503eba..3e2a341955 100644 --- a/src/types.def +++ b/src/types.def @@ -78,7 +78,7 @@ (int32_t index) (object class) (object pool) - (object template) + (method template) (object site)) (type triple @@ -406,7 +406,8 @@ (finder virtualFileFinders) (field array virtualFiles) (field array arrayInterfaceTable) - (object threadTerminated)) + (object threadTerminated) + (field array invocations)) (type compileRoots (field array callTable) @@ -415,6 +416,7 @@ (object objectPools) (object staticTableArray) (wordArray virtualThunks) + (wordArray dynamicThunks) (method receiveMethod) (method windMethod) (method rewindMethod)) diff --git a/test/InvokeDynamic.java b/test/InvokeDynamic.java new file mode 100644 index 0000000000..6a222700ee --- /dev/null +++ b/test/InvokeDynamic.java @@ -0,0 +1,7 @@ +public class InvokeDynamic { + + public static void main(String[] args) { + Runnable r = () -> System.out.println("success"); + r.run(); + } +}