mirror of
https://github.com/corda/corda.git
synced 2025-01-01 02:36:44 +00:00
first pass at minimal invokedynamic support for Java 8 lambdas
This is a bunch of commits squashed into one per Josh's request. add dynamicTable field add invokedynamic instruction add defaultDynamic bootimage field add dummy invokedynamic support in bootimage-generator add defaultDynamic thunk check dynamicTable offset comment defaultDynamicThunk to fix unused function comment defaultDynamicThunk to fix unused function add dynamicTable / dynamicIndex stuff comment dynamicIndex and dynamicTable add invokedynamic instruction impl stub out addDynamic unstub addDynamic don't allow tail calls in invokedynamic implement stub JVM_GetTemporaryDirectory method (build broken) begin add InvokeDynamicTest Revert "(build broken) begin add InvokeDynamicTest" This reverts commit 77f9c54e32ac66d0803eeab93e4a10d3541987a8. add InternalError add URLClassPath.c for openjdk-src builds implement stub JVM_KnownToNotExist and JVM_GetResourceLookupCache methods intercept open0 / open for openjdk add basic java/lang/invoke stubs remove non-public java/lang/invoke classes fix invokedynamic example building <wip debugging>
This commit is contained in:
parent
4093036e6f
commit
792684b935
21
classpath/java/lang/InternalError.java
Normal file
21
classpath/java/lang/InternalError.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
21
classpath/java/lang/TypeNotPresentException.java
Normal file
21
classpath/java/lang/TypeNotPresentException.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
4
classpath/java/lang/invoke/CallSite.java
Normal file
4
classpath/java/lang/invoke/CallSite.java
Normal file
@ -0,0 +1,4 @@
|
||||
package java.lang.invoke;
|
||||
|
||||
public abstract class CallSite {
|
||||
}
|
@ -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(); }
|
||||
}
|
5
classpath/java/lang/invoke/LambdaMetafactory.java
Normal file
5
classpath/java/lang/invoke/LambdaMetafactory.java
Normal file
@ -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(); }
|
||||
}
|
3
classpath/java/lang/invoke/MethodHandle.java
Normal file
3
classpath/java/lang/invoke/MethodHandle.java
Normal file
@ -0,0 +1,3 @@
|
||||
package java.lang.invoke;
|
||||
public abstract class MethodHandle {
|
||||
}
|
5
classpath/java/lang/invoke/MethodHandles.java
Normal file
5
classpath/java/lang/invoke/MethodHandles.java
Normal file
@ -0,0 +1,5 @@
|
||||
package java.lang.invoke;
|
||||
public class MethodHandles {
|
||||
public static class Lookup {
|
||||
}
|
||||
}
|
3
classpath/java/lang/invoke/MethodType.java
Normal file
3
classpath/java/lang/invoke/MethodType.java
Normal file
@ -0,0 +1,3 @@
|
||||
package java.lang.invoke;
|
||||
public final class MethodType implements java.io.Serializable {
|
||||
}
|
43
invoke.sh
Normal file
43
invoke.sh
Normal file
@ -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
|
6
makefile
6
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 $(@)
|
||||
|
@ -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 \
|
||||
|
@ -146,6 +146,7 @@ enum OpCode {
|
||||
imul = 0x68,
|
||||
ineg = 0x74,
|
||||
instanceof = 0xc1,
|
||||
invokedynamic = 0xba,
|
||||
invokeinterface = 0xb9,
|
||||
invokespecial = 0xb7,
|
||||
invokestatic = 0xb8,
|
||||
|
@ -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
|
||||
|
@ -34,6 +34,7 @@ FIELD(virtualThunks)
|
||||
|
||||
THUNK_FIELD(default_);
|
||||
THUNK_FIELD(defaultVirtual);
|
||||
THUNK_FIELD(defaultDynamic);
|
||||
THUNK_FIELD(native);
|
||||
THUNK_FIELD(aioob);
|
||||
THUNK_FIELD(stackOverflow);
|
||||
|
@ -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,
|
||||
|
325
src/compile.cpp
325
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<ir::Value*> 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<MyThread*>(t->peer), o);
|
||||
if (t->child)
|
||||
updateDynamicTable(static_cast<MyThread*>(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<unsigned>(index) >= oldCapacity) {
|
||||
unsigned newCapacity = oldCapacity ? 2 * oldCapacity : 4096;
|
||||
|
||||
void** newTable = static_cast<void**>(
|
||||
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<MyThread*>(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<void*>(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<GcInvocation>(
|
||||
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<const char*>(context->method->spec()->body().begin()));
|
||||
|
||||
// for debugging:
|
||||
if (false
|
||||
if (true
|
||||
and ::strcmp(reinterpret_cast<const char*>(
|
||||
context->method->class_()->name()->body().begin()),
|
||||
"java/lang/System") == 0
|
||||
"InvokeDynamic") == 0
|
||||
and ::strcmp(reinterpret_cast<const char*>(
|
||||
context->method->name()->body().begin()),
|
||||
"<clinit>") == 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<uint8_t>(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<MyThread*>(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<MyProcessor*>(t->m->processor)->dynamicIndex;
|
||||
}
|
||||
|
||||
void**& dynamicTable(MyThread* t)
|
||||
{
|
||||
return static_cast<MyProcessor*>(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<uintptr_t>(processor(t)->thunks.defaultVirtual.start);
|
||||
}
|
||||
|
||||
uintptr_t defaultDynamicThunk(MyThread* t)
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(processor(t)->thunks.defaultDynamic.start);
|
||||
}
|
||||
|
||||
uintptr_t nativeThunk(MyThread* t)
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
7
test/InvokeDynamic.java
Normal file
7
test/InvokeDynamic.java
Normal file
@ -0,0 +1,7 @@
|
||||
public class InvokeDynamic {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Runnable r = () -> System.out.println("success");
|
||||
r.run();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user