mirror of
https://github.com/corda/corda.git
synced 2024-12-28 00:38:55 +00:00
more JNI work
This commit is contained in:
parent
f0bc4dbe76
commit
2057e72956
34
makefile
34
makefile
@ -4,6 +4,14 @@ bld = build
|
||||
src = src
|
||||
classpath = classpath
|
||||
|
||||
arch = $(shell uname -m)
|
||||
ifeq ($(arch),i586)
|
||||
arch = i386
|
||||
endif
|
||||
ifeq ($(arch),i686)
|
||||
arch = i386
|
||||
endif
|
||||
|
||||
cxx = g++
|
||||
cc = gcc
|
||||
vg = nice valgrind --leak-check=full --num-callers=32 --db-attach=yes \
|
||||
@ -27,6 +35,7 @@ test-cflags = -DDEBUG_MEMORY
|
||||
stress-cflags = -DDEBUG_MEMORY -DDEBUG_MEMORY_MAJOR
|
||||
|
||||
cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(bld)/%.o,$(x)))
|
||||
assembly-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(bld)/%.o,$(x)))
|
||||
|
||||
stdcpp-sources = $(src)/stdc++.cpp
|
||||
stdcpp-objects = $(call cpp-objects,$(stdcpp-sources),$(src))
|
||||
@ -58,7 +67,21 @@ interpreter-sources = \
|
||||
$(src)/vm.cpp \
|
||||
$(src)/heap.cpp \
|
||||
$(src)/main.cpp
|
||||
interpreter-objects = $(call cpp-objects,$(interpreter-sources),$(src))
|
||||
|
||||
ifeq ($(arch),i386)
|
||||
interpreter-assembly-sources = $(src)/cdecl.S
|
||||
endif
|
||||
ifeq ($(arch),x86_64)
|
||||
interpreter-assembly-sources = $(src)/amd64.S
|
||||
endif
|
||||
|
||||
interpreter-cpp-objects = \
|
||||
$(call cpp-objects,$(interpreter-sources),$(src))
|
||||
interpreter-assembly-objects = \
|
||||
$(call assembly-objects,$(interpreter-assembly-sources),$(src))
|
||||
interpreter-objects = \
|
||||
$(interpreter-cpp-objects) \
|
||||
$(interpreter-assembly-objects)
|
||||
interpreter-cflags = $(slow) $(cflags)
|
||||
|
||||
generator-headers = \
|
||||
@ -138,7 +161,7 @@ stress-all: $(stress-executable)
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "removing $(bld)"
|
||||
rm -r $(bld)
|
||||
rm -rf $(bld)
|
||||
|
||||
gen-arg = $(shell echo $(1) | sed -e 's:$(bld)/type-\(.*\)\.cpp:\1:')
|
||||
$(generated-code): %.cpp: $(src)/types.def $(generator-executable)
|
||||
@ -159,7 +182,12 @@ $(stdcpp-objects): $(bld)/%.o: $(src)/%.cpp
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(stdcpp-cflags) -c $(<) -o $(@)
|
||||
|
||||
$(interpreter-objects): $(bld)/%.o: $(src)/%.cpp $(interpreter-depends)
|
||||
$(interpreter-cpp-objects): $(bld)/%.o: $(src)/%.cpp $(interpreter-depends)
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(interpreter-cflags) -c $(<) -o $(@)
|
||||
|
||||
$(interpreter-assembly-objects): $(bld)/%.o: $(src)/%.S
|
||||
@echo "compiling $(@)"
|
||||
@mkdir -p $(dir $(@))
|
||||
$(cxx) $(interpreter-cflags) -c $(<) -o $(@)
|
||||
|
107
src/amd64.S
Normal file
107
src/amd64.S
Normal file
@ -0,0 +1,107 @@
|
||||
#include "types.h"
|
||||
|
||||
.text
|
||||
.globl amd64Call
|
||||
.type amd64Call, @function
|
||||
|
||||
amd64Call:
|
||||
pushq %rbp
|
||||
|
||||
// %rdi aka 0(%rbp): function
|
||||
// %rsi aka 8(%rbp): stack
|
||||
// %rdx aka 16(%rbp): stackSize
|
||||
// %rcx aka 24(%rbp): gprTable
|
||||
// %r8 aka 32(%rbp): sseTable
|
||||
// %r9 aka 40(%rbp): returnType
|
||||
|
||||
// save our argument registers so we can clobber them
|
||||
pushq %r9
|
||||
pushq %r8
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
|
||||
movq %rsp,%rbp
|
||||
|
||||
// reserve space for arguments passed via memory
|
||||
subq %rdx,%rsp
|
||||
|
||||
// copy memory arguments into place
|
||||
movq $0,%rcx
|
||||
jmp test
|
||||
|
||||
loop:
|
||||
movq %rcx,%rax
|
||||
movq %rcx,%rdx
|
||||
addq %rsp,%rdx
|
||||
addq 8(%rbp),%rax
|
||||
movq (%rax),%rax
|
||||
movq %rax,(%rdx)
|
||||
addq $8,%rcx
|
||||
|
||||
test:
|
||||
cmpq 16(%rbp),%rcx
|
||||
jb loop
|
||||
|
||||
// do we need to load the general-purpose registers?
|
||||
cmpq $0,24(%rbp)
|
||||
je sse
|
||||
|
||||
// yes, we do
|
||||
movq 24(%rbp),%rax
|
||||
movq 0(%rax),%rdi
|
||||
movq 8(%rax),%rsi
|
||||
movq 16(%rax),%rcx
|
||||
movq 24(%rax),%rdx
|
||||
movq 32(%rax),%r8
|
||||
movq 40(%rax),%r9
|
||||
|
||||
sse:
|
||||
// do we need to load the SSE registers?
|
||||
cmpq $0,32(%rbp)
|
||||
je call
|
||||
|
||||
// yes, we do
|
||||
movq 32(%rbp),%rax
|
||||
movq 0(%rax),%xmm0
|
||||
movq 8(%rax),%xmm1
|
||||
movq 16(%rax),%xmm2
|
||||
movq 24(%rax),%xmm3
|
||||
movq 32(%rax),%xmm4
|
||||
movq 40(%rax),%xmm5
|
||||
movq 48(%rax),%xmm6
|
||||
movq 64(%rax),%xmm7
|
||||
|
||||
call:
|
||||
call *0(%rbp)
|
||||
|
||||
// clear space reserved for memory arguments
|
||||
movq 16(%rbp),%rcx
|
||||
addq %rcx,%rsp
|
||||
|
||||
// handle return value based on expected type
|
||||
movq 40(%rbp),%rcx
|
||||
|
||||
void:
|
||||
cmpq $VOID_TYPE,%rcx
|
||||
jne float
|
||||
jmp exit
|
||||
|
||||
float:
|
||||
cmpq $FLOAT_TYPE,%rcx
|
||||
je copy
|
||||
cmpq $DOUBLE_TYPE,%rcx
|
||||
jne exit
|
||||
|
||||
copy:
|
||||
movq %xmm0,%rax
|
||||
|
||||
exit:
|
||||
movq %rbp,%rsp
|
||||
|
||||
// pop our argument registers
|
||||
addq $48,%rsp
|
||||
|
||||
popq %rbp
|
||||
ret
|
78
src/cdecl.S
Normal file
78
src/cdecl.S
Normal file
@ -0,0 +1,78 @@
|
||||
#include "types.h"
|
||||
|
||||
.text
|
||||
.globl cdeclCall
|
||||
.type cdeclCall, @function
|
||||
|
||||
cdeclCall:
|
||||
pushl %ebp
|
||||
movl %esp,%ebp
|
||||
|
||||
// 8(%ebp): function
|
||||
// 12(%ebp): stack
|
||||
// 16(%ebp): stackSize
|
||||
// 20(%ebp): returnType
|
||||
|
||||
// reserve space for arguments
|
||||
movl 16(%ebp),%ecx
|
||||
subl %ecx,%esp
|
||||
|
||||
// copy arguments into place
|
||||
movl $0,%ecx
|
||||
jmp test
|
||||
|
||||
loop:
|
||||
movl %ecx,%eax
|
||||
movl %ecx,%edx
|
||||
addl %esp,%edx
|
||||
addl 12(%ebp),%eax
|
||||
movl (%eax),%eax
|
||||
movl %eax,(%edx)
|
||||
addl $4,%ecx
|
||||
|
||||
test:
|
||||
cmpl 16(%ebp),%ecx
|
||||
jb loop
|
||||
|
||||
// call function
|
||||
call *8(%ebp)
|
||||
|
||||
// clear space reserved for arguments
|
||||
movl 16(%ebp),%ecx
|
||||
addl %ecx,%esp
|
||||
|
||||
// handle return value based on expected type
|
||||
movl 20(%ebp),%ecx
|
||||
|
||||
void:
|
||||
cmpl $VOID_TYPE,%ecx
|
||||
jne int64
|
||||
jmp exit
|
||||
|
||||
int64:
|
||||
cmpl $INT64_TYPE,%ecx
|
||||
jne float
|
||||
jmp exit
|
||||
|
||||
float:
|
||||
cmpl $FLOAT_TYPE,%ecx
|
||||
jne double
|
||||
fstps 8(%ebp)
|
||||
movl 8(%ebp),%eax
|
||||
jmp int32
|
||||
|
||||
double:
|
||||
cmpl $DOUBLE_TYPE,%ecx
|
||||
jne int32
|
||||
fstpl 8(%ebp)
|
||||
movl 8(%ebp),%eax
|
||||
movl 12(%ebp),%edx
|
||||
jmp exit
|
||||
|
||||
int32:
|
||||
movl $0,%edx
|
||||
|
||||
exit:
|
||||
movl %ebp,%esp
|
||||
popl %ebp
|
||||
ret
|
@ -6,6 +6,7 @@
|
||||
#include "stdarg.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "types.h"
|
||||
|
||||
#define NO_RETURN __attribute__((noreturn))
|
||||
|
||||
|
80
src/main.cpp
80
src/main.cpp
@ -11,6 +11,77 @@
|
||||
|
||||
using namespace vm;
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
extern "C" uint64_t
|
||||
cdeclCall(void* function, void* stack, unsigned stackSize,
|
||||
unsigned returnType);
|
||||
|
||||
namespace {
|
||||
|
||||
inline uint64_t
|
||||
dynamicCall(void* function, uint32_t* arguments, uint8_t*,
|
||||
unsigned, unsigned argumentsSize, unsigned returnType)
|
||||
{
|
||||
return cdeclCall(function, arguments, argumentsSize, returnType);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#elif defined __x86_64__
|
||||
|
||||
extern "C" uint64_t
|
||||
amd64Call(void* function, void* stack, unsigned stackSize,
|
||||
void* gprTable, void* sseTable, unsigned returnType);
|
||||
|
||||
namespace {
|
||||
|
||||
uint64_t
|
||||
dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
|
||||
unsigned argumentCount, unsigned, unsigned returnType)
|
||||
{
|
||||
const unsigned GprCount = 6;
|
||||
uint64_t gprTable[GprCount];
|
||||
unsigned gprIndex = 0;
|
||||
|
||||
const unsigned SseCount = 8;
|
||||
uint64_t sseTable[SseCount];
|
||||
unsigned sseIndex = 0;
|
||||
|
||||
uint64_t stack[argumentCount];
|
||||
unsigned stackIndex = 0;
|
||||
|
||||
for (unsigned i = 0; i < argumentCount; ++i) {
|
||||
switch (argumentTypes[i]) {
|
||||
case FLOAT_TYPE:
|
||||
case DOUBLE_TYPE: {
|
||||
if (sseIndex < SseCount) {
|
||||
sseTable[sseIndex++] = arguments[i];
|
||||
} else {
|
||||
stack[stackIndex++] = arguments[i];
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
if (gprIndex < GprCount) {
|
||||
gprTable[gprIndex++] = arguments[i];
|
||||
} else {
|
||||
stack[stackIndex++] = arguments[i];
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
return amd64Call(function, stack, stackIndex * 8, (gprIndex ? gprTable : 0),
|
||||
(sseIndex ? sseTable : 0), returnType);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
# error unsupported platform
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
const bool Verbose = false;
|
||||
@ -115,13 +186,10 @@ class System: public vm::System {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint64_t call(void* ,//function,
|
||||
unsigned ,//argumentCount,
|
||||
uint32_t* ,//argumentTable,
|
||||
uint8_t* ,//argumentSizeTable,
|
||||
unsigned )//returnSize)
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
unsigned count, unsigned size, unsigned returnType)
|
||||
{
|
||||
::abort();
|
||||
return dynamicCall(function, arguments, types, count, size, returnType);
|
||||
}
|
||||
|
||||
virtual Status load(vm::System::Library** lib,
|
||||
|
@ -42,9 +42,9 @@ class System {
|
||||
virtual void free(const void*) = 0;
|
||||
virtual Status start(Thread*) = 0;
|
||||
virtual Status make(Monitor**) = 0;
|
||||
virtual uint64_t call(void* function, unsigned argumentCount,
|
||||
uint32_t* argumentTable, uint8_t* argumentSizeTable,
|
||||
unsigned returnSize) = 0;
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
unsigned count, unsigned size,
|
||||
unsigned returnType) = 0;
|
||||
virtual Status load(Library**, const char* name, Library* next) = 0;
|
||||
virtual void abort() = 0;
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
(uint16_t argumentTableSize)
|
||||
(uint8_t returnCode)
|
||||
(uint8_t builtin)
|
||||
(array uint8_t parameterCodes))
|
||||
(array uint8_t parameterTypes))
|
||||
|
||||
(type pointer
|
||||
(void* value))
|
||||
|
13
src/types.h
Normal file
13
src/types.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#define VOID_TYPE 0
|
||||
#define INT8_TYPE 1
|
||||
#define INT16_TYPE 2
|
||||
#define INT32_TYPE 3
|
||||
#define INT64_TYPE 4
|
||||
#define FLOAT_TYPE 5
|
||||
#define DOUBLE_TYPE 6
|
||||
#define POINTER_TYPE 7
|
||||
|
||||
#endif//TYPES_H
|
142
src/vm.cpp
142
src/vm.cpp
@ -17,7 +17,8 @@ using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
static const bool Debug = true;
|
||||
static const bool Verbose = false;
|
||||
static const bool Debug = false;
|
||||
|
||||
class Thread;
|
||||
|
||||
@ -827,7 +828,7 @@ makeRuntimeException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeClassCastException(t, message, trace, 0);
|
||||
return makeRuntimeException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
object
|
||||
@ -935,6 +936,33 @@ fieldCode(Thread* t, unsigned javaCode)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
fieldType(Thread* t, unsigned code)
|
||||
{
|
||||
switch (code) {
|
||||
case VoidField:
|
||||
return VOID_TYPE;
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
return INT8_TYPE;
|
||||
case CharField:
|
||||
case ShortField:
|
||||
return INT16_TYPE;
|
||||
case DoubleField:
|
||||
return DOUBLE_TYPE;
|
||||
case FloatField:
|
||||
return FLOAT_TYPE;
|
||||
case IntField:
|
||||
return INT32_TYPE;
|
||||
case LongField:
|
||||
return INT64_TYPE;
|
||||
case ObjectField:
|
||||
return POINTER_TYPE;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
primitiveValue(Thread* t, unsigned code, object o)
|
||||
{
|
||||
@ -1828,15 +1856,19 @@ resolveClass(Thread* t, object spec)
|
||||
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
||||
|
||||
if (data) {
|
||||
fprintf(stderr, "parsing %s\n", &byteArrayBody
|
||||
(t, spec, 0));
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "parsing %s\n", &byteArrayBody
|
||||
(t, spec, 0));
|
||||
}
|
||||
|
||||
// parse class file
|
||||
class_ = parseClass(t, data->start(), data->length());
|
||||
data->dispose();
|
||||
|
||||
fprintf(stderr, "done parsing %s\n", &byteArrayBody
|
||||
(t, className(t, class_), 0));
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "done parsing %s\n", &byteArrayBody
|
||||
(t, className(t, class_), 0));
|
||||
}
|
||||
|
||||
PROTECT(t, class_);
|
||||
|
||||
@ -1929,15 +1961,17 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
|
||||
0, // argument table size
|
||||
0, // return code,
|
||||
builtin,
|
||||
methodParameterCount(t, method),
|
||||
methodParameterCount(t, method) + 1,
|
||||
false);
|
||||
|
||||
unsigned argumentTableSize = BytesPerWord / 4;
|
||||
unsigned argumentTableSize = BytesPerWord;
|
||||
unsigned index = 0;
|
||||
|
||||
nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE;
|
||||
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
nativeMethodDataParameterCodes(t, data, index++) = ObjectField;
|
||||
argumentTableSize += BytesPerWord / 4;
|
||||
nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE;
|
||||
argumentTableSize += BytesPerWord;
|
||||
}
|
||||
|
||||
const char* s = reinterpret_cast<const char*>
|
||||
@ -1945,22 +1979,22 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
unsigned code = fieldCode(t, *s);
|
||||
nativeMethodDataParameterCodes(t, data, index++) = code;
|
||||
nativeMethodDataParameterTypes(t, data, index++) = fieldType(t, code);
|
||||
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
argumentTableSize += BytesPerWord / 4;
|
||||
argumentTableSize += BytesPerWord;
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
argumentTableSize += BytesPerWord / 4;
|
||||
argumentTableSize += BytesPerWord;
|
||||
while (*s == '[') ++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
argumentTableSize += divide(primitiveSize(t, code), 4);
|
||||
argumentTableSize += pad(primitiveSize(t, code));
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
@ -2020,44 +2054,50 @@ invokeNative(Thread* t, object method)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned parameterCount = methodParameterCount(t, method);
|
||||
unsigned count = methodParameterCount(t, method);
|
||||
|
||||
uint32_t args[nativeMethodDataArgumentTableSize(t, data)];
|
||||
uint8_t sizes[parameterCount + 1];
|
||||
unsigned size = nativeMethodDataArgumentTableSize(t, data);
|
||||
uintptr_t args[size / BytesPerWord];
|
||||
unsigned offset = 0;
|
||||
|
||||
sizes[0] = BytesPerWord;
|
||||
memcpy(args + offset, &t, BytesPerWord);
|
||||
offset += BytesPerWord / 4;
|
||||
args[offset++] = reinterpret_cast<uintptr_t>(t);
|
||||
|
||||
for (unsigned i = 0; i < parameterCount; ++i) {
|
||||
unsigned code = nativeMethodDataParameterCodes(t, data, i);
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
unsigned type = nativeMethodDataParameterTypes(t, data, i);
|
||||
unsigned position = (t->sp - count) + i;
|
||||
object o = t->stack[position];
|
||||
|
||||
if (code == ObjectField) {
|
||||
sizes[i + 1] = BytesPerWord;
|
||||
unsigned position = (t->sp - parameterCount) + i;
|
||||
if (t->stack[position]) {
|
||||
memcpy(args + offset, t->stack + position, BytesPerWord);
|
||||
} else {
|
||||
memset(args + offset, 0, BytesPerWord);
|
||||
}
|
||||
offset += BytesPerWord / 4;
|
||||
} else {
|
||||
sizes[i + 1] = primitiveSize(t, code);
|
||||
uint64_t v = primitiveValue(t, code, t->stack[t->sp + i]);
|
||||
if (sizes[i + 1] == 8) {
|
||||
memcpy(args + offset, &v, 8);
|
||||
offset += 2;
|
||||
} else {
|
||||
args[offset++] = v;
|
||||
}
|
||||
switch (type) {
|
||||
case INT8_TYPE:
|
||||
args[offset++] = cast<uint8_t>(o, BytesPerWord);
|
||||
break;
|
||||
|
||||
case INT16_TYPE:
|
||||
args[offset++] = cast<uint16_t>(o, BytesPerWord);
|
||||
break;
|
||||
|
||||
case INT32_TYPE:
|
||||
case FLOAT_TYPE:
|
||||
args[offset++] = cast<uint32_t>(o, BytesPerWord);
|
||||
break;
|
||||
|
||||
case INT64_TYPE:
|
||||
case DOUBLE_TYPE: {
|
||||
uint64_t v = cast<uint64_t>(o, BytesPerWord);
|
||||
memcpy(args + offset, &v, 8);
|
||||
offset += (8 / BytesPerWord);
|
||||
} break;
|
||||
|
||||
case POINTER_TYPE:
|
||||
args[offset++] = reinterpret_cast<uintptr_t>(t->stack + position);
|
||||
break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned returnCode = nativeMethodDataReturnCode(t, data);
|
||||
unsigned returnSize
|
||||
= (returnCode == ObjectField ? 4 : primitiveSize(t, returnCode));
|
||||
|
||||
unsigned returnType = fieldType(t, returnCode);
|
||||
void* function = nativeMethodDataFunction(t, data);
|
||||
|
||||
bool builtin = nativeMethodDataBuiltin(t, data);
|
||||
@ -2065,11 +2105,13 @@ invokeNative(Thread* t, object method)
|
||||
enter(t, Thread::IdleState);
|
||||
}
|
||||
|
||||
uint64_t rv = t->vm->system->call(function,
|
||||
parameterCount,
|
||||
args,
|
||||
sizes,
|
||||
returnSize);
|
||||
uint64_t rv = t->vm->system->call
|
||||
(function,
|
||||
args,
|
||||
&nativeMethodDataParameterTypes(t, data, 0),
|
||||
count + 1,
|
||||
size,
|
||||
returnType);
|
||||
|
||||
if (not builtin) {
|
||||
enter(t, Thread::ActiveState);
|
||||
@ -3656,6 +3698,8 @@ run(Thread* t)
|
||||
if (nativeMethodDataReturnCode(t, methodCode(t, code)) != VoidField) {
|
||||
push(t, r);
|
||||
}
|
||||
|
||||
code = methodCode(t, frameMethod(t, frame));
|
||||
} else {
|
||||
if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + base
|
||||
> Thread::StackSizeInWords))
|
||||
@ -3734,7 +3778,7 @@ run(Thread* t)
|
||||
}
|
||||
|
||||
for (; p; p = traceNext(t, p)) {
|
||||
fprintf(stderr, " at %s:%s\n",
|
||||
fprintf(stderr, " at %s.%s\n",
|
||||
&byteArrayBody
|
||||
(t, className(t, methodClass(t, traceMethod(t, p))), 0),
|
||||
&byteArrayBody
|
||||
|
Loading…
Reference in New Issue
Block a user