diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index 43cc6e3860..210130412f 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -1,12 +1,14 @@ package java.io; public class PrintStream extends OutputStream { - private static final byte[] newline - = System.getProperty("line.separator").getBytes(); - private final OutputStream out; private final boolean autoFlush; + private static class Static { + private static final byte[] newline + = System.getProperty("line.separator").getBytes(); + } + public PrintStream(OutputStream out, boolean autoFlush) { this.out = out; this.autoFlush = autoFlush; @@ -33,14 +35,14 @@ public class PrintStream extends OutputStream { public synchronized void println(String s) { try { out.write(s.getBytes()); - out.write(newline); + out.write(Static.newline); if (autoFlush) flush(); } catch (IOException e) { } } public synchronized void println() { try { - out.write(newline); + out.write(Static.newline); if (autoFlush) flush(); } catch (IOException e) { } } diff --git a/src/compile.cpp b/src/compile.cpp index 98deab7191..13554db687 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -32,6 +32,30 @@ throwNew(Thread* t, object class_) unwind(t); } +void +throw_(Thread* t, object o) +{ + if (o) { + t->exception = makeNullPointerException(t); + } else { + t->exception = o; + } + unwind(t); +} + +object +makeBlankObjectArray(Thread* t, object class_, int32_t length) +{ + return makeObjectArray(t, class_, length, true); +} + +object +makeBlankArray(Thread* t, object (*constructor)(Thread*, uintptr_t, bool), + int32_t length) +{ + return constructor(t, length, true); +} + class Buffer { public: Buffer(System* s, unsigned minimumCapacity): @@ -402,6 +426,17 @@ class Assembler { code.append(v); } + void add(int32_t v, Register dst, unsigned offset) { + rex(); + unsigned i = (isByte(v) ? 0x83 : 0x81); + offsetInstruction(i, 0, 0x40, 0x80, rax, dst, offset); + if (isByte(v)) { + code.append(v); + } else { + code.append4(v); + } + } + void sub(Register src, Register dst) { rex(); code.append(0x29); @@ -470,9 +505,9 @@ class Assembler { code.append(0xe0 | reg); } - void je(Label& label) { + void conditional(Label& label, unsigned condition) { code.append(0x0f); - code.append(0x84); + code.append(condition); label.reference(); } @@ -486,32 +521,50 @@ class Assembler { code.append4(0); } + void je(Label& label) { + conditional(label, 0x84); + } + void je(unsigned javaIP) { conditional(javaIP, 0x84); } void jne(Label& label) { - code.append(0x0f); - code.append(0x85); - label.reference(); + conditional(label, 0x85); } void jne(unsigned javaIP) { conditional(javaIP, 0x85); } + void jg(Label& label) { + conditional(label, 0x8f); + } + void jg(unsigned javaIP) { conditional(javaIP, 0x8f); } + void jge(Label& label) { + conditional(label, 0x8d); + } + void jge(unsigned javaIP) { conditional(javaIP, 0x8d); } + void jl(Label& label) { + conditional(label, 0x8c); + } + void jl(unsigned javaIP) { conditional(javaIP, 0x8c); } + void jle(Label& label) { + conditional(label, 0x8e); + } + void jle(unsigned javaIP) { conditional(javaIP, 0x8e); } @@ -539,7 +592,8 @@ localOffset(int v, int parameterFootprint) { v *= BytesPerWord; if (v < parameterFootprint) { - return v + (BytesPerWord * 2) + FrameFootprint; + return (parameterFootprint - v - BytesPerWord) + (BytesPerWord * 2) + + FrameFootprint; } else { return -(v + BytesPerWord - parameterFootprint); } @@ -574,11 +628,9 @@ sseRegister(Thread* t, unsigned index) } unsigned -parameterOffset(Thread* t, object method, unsigned index) +parameterOffset(unsigned index) { - return FrameFootprint - + (((methodParameterFootprint(t, method) - index - 1) + 2) - * BytesPerWord); + return FrameFootprint + ((index + 2) * BytesPerWord); } class Compiler: public Assembler { @@ -635,7 +687,7 @@ class Compiler: public Assembler { void compileCall(uintptr_t function, uintptr_t arg1) { if (BytesPerWord == 4) { - pushAddress(arg1); + push(arg1); push(rbp, FrameThread); } else { mov(arg1, rsi); @@ -650,6 +702,42 @@ class Compiler: public Assembler { } } + void compileCall(uintptr_t function, Register arg1) { + if (BytesPerWord == 4) { + push(arg1); + push(rbp, FrameThread); + } else { + mov(arg1, rsi); + mov(rbp, FrameThread, rdi); + } + + mov(function, rax); + call(rax); + + if (BytesPerWord == 4) { + add(BytesPerWord * 2, rsp); + } + } + + void compileCall(uintptr_t function, uintptr_t arg1, Register arg2) { + if (BytesPerWord == 4) { + push(arg2); + push(arg1); + push(rbp, FrameThread); + } else { + mov(arg2, rdx); + mov(arg1, rsi); + mov(rbp, FrameThread, rdi); + } + + mov(function, rax); + call(rax); + + if (BytesPerWord == 4) { + add(BytesPerWord * 3, rsp); + } + } + void compileCall(uintptr_t function, Register arg1, Register arg2) { if (BytesPerWord == 4) { push(arg2); @@ -682,6 +770,12 @@ class Compiler: public Assembler { - reinterpret_cast(t); void* function = resolveNativeMethod(t, method); + if (UNLIKELY(function == 0)) { + object message = makeString + (t, "%s", &byteArrayBody(t, methodCode(t, method), 0)); + t->exception = makeUnsatisfiedLinkError(t, message); + return; + } push(rbp); mov(rsp, rbp); @@ -696,17 +790,24 @@ class Compiler: public Assembler { } else { index = 1; } + + unsigned parameterCodes[methodParameterCount(t, method)]; + MethodSpecIterator it + (t, reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0))); - MethodSpecIterator it(t, reinterpret_cast - (&byteArrayBody(t, methodSpec(t, method), 0))); + for (unsigned i = 0; it.hasNext(); ++i) { + parameterCodes[i] = fieldCode(t, *it.next()); + } unsigned stackFootprint; + unsigned parameterCodeIndex = methodParameterCount(t, method); if (BytesPerWord == 4) { - while (it.hasNext()) { - unsigned offset = parameterOffset(t, method, index); + while (parameterCodeIndex) { + unsigned offset = parameterOffset(index); - switch (fieldCode(t, *it.next())) { + switch (parameterCodes[--parameterCodeIndex]) { case BooleanField: case ByteField: case ShortField: @@ -741,7 +842,8 @@ class Compiler: public Assembler { sub(BytesPerWord, rax); push(rax); // push pointer to class pointer } else { - unsigned offset = parameterOffset(t, method, 0); + unsigned offset = parameterOffset + (methodParameterFootprint(t, method) - 1); mov(rbp, rax); add(offset, rax); push(rax); // push pointer to this pointer @@ -760,10 +862,10 @@ class Compiler: public Assembler { stackFootprint = 0; - while (it.hasNext()) { - unsigned offset = parameterOffset(t, method, index); + while (parameterCodeIndex) { + unsigned offset = parameterOffset(index); - switch (fieldCode(t, *it.next())) { + switch (parameterCodes[--parameterCodeIndex]) { case BooleanField: case ByteField: case ShortField: @@ -817,7 +919,8 @@ class Compiler: public Assembler { mov(rbp, rsi); sub(BytesPerWord, rsi); // push pointer to class pointer } else { - unsigned offset = parameterOffset(t, method, 0); + unsigned offset = parameterOffset + (methodParameterFootprint(t, method) - 1); mov(rbp, rsi); add(offset, rsi); // push pointer to this pointer } @@ -897,6 +1000,31 @@ class Compiler: public Assembler { push(rbp, localOffset(3, parameterFootprint)); break; + case anewarray: { + uint16_t index = codeReadInt16(t, code, ip); + + object class_ = resolveClass(t, codePool(t, code), index - 1); + if (UNLIKELY(t->exception)) return; + + Label nonnegative(this); + + pop(rax); + cmp(0, rax); + jle(nonnegative); + + compileCall + (reinterpret_cast(throwNew), + reinterpret_cast + (arrayBody(t, t->m->types, + Machine::NegativeArraySizeExceptionType))); + + nonnegative.mark(); + compileCall(reinterpret_cast(makeBlankObjectArray), + reinterpret_cast(class_), + rax); + push(rax); + } break; + case areturn: case ireturn: case freturn: @@ -936,6 +1064,11 @@ class Compiler: public Assembler { pop(rbp, localOffset(3, parameterFootprint)); break; + case athrow: + pop(rax); + compileCall(reinterpret_cast(throw_), rax); + break; + case bipush: { push(static_cast(codeBody(t, code, ip++))); } break; @@ -948,7 +1081,7 @@ class Compiler: public Assembler { Label next(this); - pop(rax); + mov(rsp, 0, rax); cmp(0, rax); je(next); @@ -970,7 +1103,7 @@ class Compiler: public Assembler { } break; case dup: - push(rsp, BytesPerWord); + push(rsp, 0); break; case getfield: { @@ -1031,7 +1164,7 @@ class Compiler: public Assembler { object table = classStaticTable(t, fieldClass(t, field)); mov(reinterpret_cast(table), rax); - add(fieldOffset(t, field), rax); + add((fieldOffset(t, field) * BytesPerWord) + ArrayBody, rax); switch (fieldCode(t, field)) { case ByteField: @@ -1082,6 +1215,16 @@ class Compiler: public Assembler { } } break; + case goto_: { + int16_t offset = codeReadInt16(t, code, ip); + jmp((ip - 3) + offset); + } break; + + case goto_w: { + int32_t offset = codeReadInt32(t, code, ip); + jmp((ip - 5) + offset); + } break; + case iadd: pop(rax); pop(rcx); @@ -1223,14 +1366,11 @@ class Compiler: public Assembler { jle((ip - 3) + offset); } break; - case goto_: { - int16_t offset = codeReadInt16(t, code, ip); - jmp((ip - 3) + offset); - } break; - - case goto_w: { - int32_t offset = codeReadInt32(t, code, ip); - jmp((ip - 5) + offset); + case iinc: { + uint8_t index = codeBody(t, code, ip++); + int8_t c = codeBody(t, code, ip++); + + add(c, rbp, localOffset(index, parameterFootprint)); } break; case instanceof: { @@ -1326,6 +1466,13 @@ class Compiler: public Assembler { pushReturnValue(t, methodReturnCode(t, target)); } break; + case isub: + pop(rax); + pop(rcx); + sub(rax, rcx); + push(rcx); + break; + case ldc: case ldc_w: { uint16_t index; @@ -1378,6 +1525,66 @@ class Compiler: public Assembler { push(rax); } break; + case newarray: { + uint8_t type = codeBody(t, code, ip++); + + Label nonnegative(this); + + pop(rax); + cmp(0, rax); + jge(nonnegative); + + compileCall + (reinterpret_cast(throwNew), + reinterpret_cast + (arrayBody(t, t->m->types, + Machine::NegativeArraySizeExceptionType))); + + nonnegative.mark(); + + object (*constructor)(Thread*, uintptr_t, bool); + switch (type) { + case T_BOOLEAN: + constructor = makeBooleanArray; + break; + + case T_CHAR: + constructor = makeCharArray; + break; + + case T_FLOAT: + constructor = makeFloatArray; + break; + + case T_DOUBLE: + constructor = makeDoubleArray; + break; + + case T_BYTE: + constructor = makeByteArray; + break; + + case T_SHORT: + constructor = makeShortArray; + break; + + case T_INT: + constructor = makeIntArray; + break; + + case T_LONG: + constructor = makeLongArray; + break; + + default: abort(t); + } + + compileCall(reinterpret_cast(makeBlankArray), + reinterpret_cast(constructor), + rax); + push(rax); + } break; + case pop_: { add(BytesPerWord, rsp); } break; @@ -1446,7 +1653,7 @@ class Compiler: public Assembler { object table = classStaticTable(t, fieldClass(t, field)); mov(reinterpret_cast(table), rax); - add(fieldOffset(t, field), rax); + add((fieldOffset(t, field) * BytesPerWord) + ArrayBody, rax); switch (fieldCode(t, field)) { case ByteField: @@ -1486,6 +1693,10 @@ class Compiler: public Assembler { ret(); break; + case sipush: { + push(static_cast(codeReadInt16(t, code, ip))); + } break; + default: abort(t); } @@ -1575,7 +1786,7 @@ compileMethod2(MyThread* t, object method) Compiler c(t->m->system); c.compile(t, method); - object compiled = makeCompiled(t, 0, c.code.length(), false); + object compiled = makeCompiled(t, c.code.length(), false); if (UNLIKELY(t->exception)) return; c.code.copyTo(&compiledBody(t, compiled, 0)); @@ -1635,7 +1846,7 @@ compileStub(Thread* t) Compiler c(t->m->system); c.compileStub(static_cast(t)); - object stub = makeCompiled(t, 0, c.code.length(), false); + object stub = makeCompiled(t, c.code.length(), false); c.code.copyTo(&compiledBody(t, stub, 0)); return stub; @@ -1811,10 +2022,14 @@ invoke(Thread* thread, object method, ArgumentList* arguments) unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); + void* frame = t->frame; + uint64_t result = vmInvoke (&compiledBody(t, methodCompiled(t, method), 0), arguments->array, arguments->position * BytesPerWord, returnType); + t->frame = frame; + object r; switch (returnCode) { case ByteField: diff --git a/src/interpret.cpp b/src/interpret.cpp index 44669719ae..9d2cba0661 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1760,16 +1760,7 @@ interpret(Thread* t) object class_ = methodClass(t, frameMethod(t, frame)); if (isSpecialMethod(t, method, class_)) { class_ = classSuper(t, class_); - - if (classVirtualTable(t, class_) == 0) { - PROTECT(t, method); - PROTECT(t, class_); - - resolveClass(t, className(t, class_)); - if (UNLIKELY(exception)) goto throw_; - - if (UNLIKELY(classInit(t, class_, 3))) goto invoke; - } + if (UNLIKELY(classInit(t, class_, 3))) goto invoke; code = findMethod(t, method, class_); } else { @@ -1804,16 +1795,7 @@ interpret(Thread* t) unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { object class_ = objectClass(t, peekObject(t, sp - parameterFootprint)); - - if (classVirtualTable(t, class_) == 0) { - PROTECT(t, method); - PROTECT(t, class_); - - resolveClass(t, className(t, class_)); - if (UNLIKELY(exception)) goto throw_; - - if (UNLIKELY(classInit(t, class_, 3))) goto invoke; - } + if (UNLIKELY(classInit(t, class_, 3))) goto invoke; code = findMethod(t, method, class_); goto invoke; @@ -2494,10 +2476,7 @@ interpret(Thread* t) } goto loop; case sipush: { - uint8_t byte1 = codeBody(t, code, ip++); - uint8_t byte2 = codeBody(t, code, ip++); - - pushInt(t, static_cast((byte1 << 8) | byte2)); + pushInt(t, static_cast(codeReadInt16(t, code, ip))); } goto loop; case swap: { @@ -2766,11 +2745,6 @@ invoke(Thread* t, object method) if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { method = findInterfaceMethod(t, method, class_); } else { - if (classVirtualTable(t, class_) == 0) { - resolveClass(t, className(t, class_)); - if (UNLIKELY(t->exception)) return 0; - } - method = findMethod(t, method, class_); } } diff --git a/src/machine.cpp b/src/machine.cpp index b1a84b6752..57db550f29 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1451,8 +1451,6 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): m->bootstrapClassMap = makeHashMap(this, 0, 0); -#include "type-java-initializations.cpp" - object loaderMap = makeHashMap(this, 0, 0); set(t, systemClassLoaderMap(t, m->loader), loaderMap); @@ -1462,6 +1460,17 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): m->jniInterfaceTable = makeVector(this, 0, 0, false); m->localThread->set(this); + +#include "type-java-initializations.cpp" + + enter(t, Thread::ActiveState); + + resolveClass + (t, className(t, arrayBody(t, m->types, Machine::ClassType))); + resolveClass + (t, className(t, arrayBody(t, m->types, Machine::IntArrayType))); + resolveClass + (t, className(t, arrayBody(t, m->types, Machine::ByteArrayType))); } else { parent->child = this; } @@ -1472,6 +1481,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): this->javaThread = makeThread (this, reinterpret_cast(this), 0, 0, 0, 0, m->loader); } + + enter(this, Thread::IdleState); } void diff --git a/src/machine.h b/src/machine.h index 1bf0900852..1be9e59ab1 100644 --- a/src/machine.h +++ b/src/machine.h @@ -56,6 +56,7 @@ const unsigned WeakReferenceFlag = 1 << 1; const unsigned NeedInitFlag = 1 << 2; const unsigned InitFlag = 1 << 3; const unsigned PrimitiveFlag = 1 << 4; +const unsigned BootstrapFlag = 1 << 5; // method flags: const unsigned ClassInitFlag = 1 << 0; diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 3adff315ce..1b5682206d 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -40,6 +40,12 @@ equal(const char* a, const char* b) return strcmp(a, b) == 0; } +inline bool +startsWith(const char* a, const char* b) +{ + return strncmp(a, b, strlen(a)) == 0; +} + class Object { public: typedef enum { @@ -1354,6 +1360,22 @@ writeConstructors(Output* out, Object* declarations) } } + if (typeJavaName(o) + and not equal("class", typeName(o)) + and startsWith("java/", typeJavaName(o))) + { + out->write(" object class__ "); + out->write("= arrayBody(t, t->m->types, Machine::"); + out->write(capitalize(typeName(o))); + out->write("Type);\n"); + + out->write(" if (classVmFlags(t, class__) & BootstrapFlag) {\n"); + out->write(" classVmFlags(t, class__) &= ~BootstrapFlag;\n"); + out->write(" resolveClass(t, className(t, class__));\n"); + out->write(" assert(t, t->exception == 0);\n"); + out->write(" }\n"); + } + out->write(" object o = allocate(t, "); writeOffset(out, typeOffset(o), true); out->write(");\n"); @@ -1522,7 +1544,18 @@ writeInitialization(Output* out, Object* type) } out->write(" object class_ = makeClass"); - out->write("(t, 0, 0, 0, "); + out->write("(t, 0, "); + + if (typeJavaName(type) + and not equal("class", typeName(type)) + and startsWith("java/", typeJavaName(type))) + { + out->write("BootstrapFlag"); + } else { + out->write("0"); + } + + out->write(", 0, "); out->write(typeFixedSize(type)); out->write(", "); out->write(typeArrayElementSize(type)); diff --git a/src/types.def b/src/types.def index ab6dec5a8b..f1ec9cf494 100644 --- a/src/types.def +++ b/src/types.def @@ -53,7 +53,6 @@ (object compiled)) (type compiled - (nogc object method) (array uint8_t body)) (type nativeMethodData