From d9aac52b3d8d456473181713ccf6cccc72416fc9 Mon Sep 17 00:00:00 2001 From: jet Date: Mon, 12 Jul 2010 14:18:36 -0600 Subject: [PATCH 001/274] First version; interpreted mode works and JIT mode compiles. --- src/arm.S | 2 +- src/arm.cpp | 773 ++++++++++++++++++++++++++++++++-------------- src/arm.h | 2 +- src/compile-arm.S | 110 +++++++ 4 files changed, 650 insertions(+), 237 deletions(-) create mode 100644 src/compile-arm.S diff --git a/src/arm.S b/src/arm.S index f3dd2b146f..9df1b14ac3 100644 --- a/src/arm.S +++ b/src/arm.S @@ -53,4 +53,4 @@ vmJump: mov sp, r2 mov r4, r3 ldmia sp, {r0,r1} - mov pc, lr + bx lr diff --git a/src/arm.cpp b/src/arm.cpp index 66af8a37d3..387c4ee688 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -14,6 +14,7 @@ #define CAST1(x) reinterpret_cast(x) #define CAST2(x) reinterpret_cast(x) #define CAST3(x) reinterpret_cast(x) +#define CAST_BRANCH(x) reinterpret_cast(x) using namespace vm; @@ -111,7 +112,7 @@ inline int stmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 0, Rn, rl inline int stmdb(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 0, 0, Rn, rlist); } inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); } inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); } -inline int SETCOND(int ins, int cond) { return ins&0x0fffffff | cond<<28; } +inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); } inline int SETS(int ins) { return ins | 1<<20; } // PSEUDO-INSTRUCTIONS inline int nop() { return mov(0, 0); } @@ -122,6 +123,14 @@ inline int lsri(int Rd, int Rm, int imm) { return mov(Rd, Rm, LSR, imm); } inline int asr(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ASR); } inline int asri(int Rd, int Rm, int imm) { return mov(Rd, Rm, ASR, imm); } inline int ror(int Rd, int Rm, int Rs) { return movsh(Rd, Rm, Rs, ROR); } +inline int beq(int offset) { return SETCOND(b(offset), EQ); } +inline int bne(int offset) { return SETCOND(b(offset), NE); } +inline int bls(int offset) { return SETCOND(b(offset), LS); } +inline int bhi(int offset) { return SETCOND(b(offset), HI); } +inline int blt(int offset) { return SETCOND(b(offset), LT); } +inline int bgt(int offset) { return SETCOND(b(offset), GT); } +inline int ble(int offset) { return SETCOND(b(offset), LE); } +inline int bge(int offset) { return SETCOND(b(offset), GE); } } const uint64_t MASK_LO32 = 0xffffffff; @@ -134,17 +143,27 @@ inline unsigned hi16(int64_t i) { return lo16(i>>16); } inline unsigned lo8(int64_t i) { return (unsigned)(i&MASK_LO8); } inline unsigned hi8(int64_t i) { return lo8(i>>8); } +inline int ha16(int32_t i) { + return ((i >> 16) + ((i & 0x8000) ? 1 : 0)) & 0xffff; +} +inline int unha16(int32_t high, int32_t low) { + return ((high - ((low & 0x8000) ? 1 : 0)) << 16) | low; +} + inline bool isInt8(intptr_t v) { return v == static_cast(v); } inline bool isInt16(intptr_t v) { return v == static_cast(v); } -inline bool isInt24(intptr_t v) { return v == v & 0xffffff; } +inline bool isInt24(intptr_t v) { return v == (v & 0xffffff); } inline bool isInt32(intptr_t v) { return v == static_cast(v); } inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } -const unsigned FrameFooterSize = 0; +const unsigned FrameFooterSize = 2; +const unsigned FrameHeaderSize = 0; + const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int StackRegister = 13; +const int BaseRegister = 11; const int ThreadRegister = 12; class MyBlock: public Assembler::Block { @@ -167,13 +186,14 @@ class MyBlock: public Assembler::Block { }; class Task; +class ConstantPoolEntry; class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock) + lastBlock(firstBlock), constantPool(0), constantPoolCount(0) { } System* s; @@ -184,6 +204,8 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; + ConstantPoolEntry* constantPool; + unsigned constantPoolCount; }; class Task { @@ -206,6 +228,10 @@ typedef void (*TernaryOperationType) (Context*, unsigned, Assembler::Operand*, Assembler::Operand*, Assembler::Operand*); +typedef void (*BranchOperationType) +(Context*, TernaryOperation, unsigned, Assembler::Operand*, + Assembler::Operand*, Assembler::Operand*); + class ArchitectureContext { public: ArchitectureContext(System* s): s(s) { } @@ -217,7 +243,9 @@ class ArchitectureContext { BinaryOperationType binaryOperations [BinaryOperationCount * OperandTypeCount * OperandTypeCount]; TernaryOperationType ternaryOperations - [TernaryOperationCount * OperandTypeCount]; + [NonBranchTernaryOperationCount * OperandTypeCount]; + BranchOperationType branchOperations + [BranchOperationCount * OperandTypeCount * OperandTypeCount]; }; inline void NO_RETURN @@ -356,13 +384,14 @@ appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, } inline unsigned -index(UnaryOperation operation, OperandType operand) +index(ArchitectureContext*, UnaryOperation operation, OperandType operand) { return operation + (UnaryOperationCount * operand); } inline unsigned -index(BinaryOperation operation, +index(ArchitectureContext*, + BinaryOperation operation, OperandType operand1, OperandType operand2) { @@ -371,13 +400,34 @@ index(BinaryOperation operation, + (BinaryOperationCount * OperandTypeCount * operand2); } -inline unsigned -index(TernaryOperation operation, - OperandType operand1) +bool +isBranch(TernaryOperation op) { - return operation + (TernaryOperationCount * operand1); + return op > FloatMin; } +bool +isFloatBranch(TernaryOperation op) +{ + return op > JumpIfNotEqual; +} + +inline unsigned +index(ArchitectureContext* c UNUSED, + TernaryOperation operation, + OperandType operand1) +{ + assert(c, not isBranch(operation)); + + return operation + (NonBranchTernaryOperationCount * operand1); +} + +unsigned +branchIndex(ArchitectureContext* c UNUSED, OperandType operand1, + OperandType operand2) +{ + return operand1 + (OperandTypeCount * operand2); +} // BEGIN OPERATION COMPILERS @@ -387,10 +437,9 @@ using namespace isa; inline void emit(Context* con, int code) { con->code.append4(code); } inline int newTemp(Context* con) { return con->client->acquireTemporary(); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } -inline int64_t getValue(Assembler::Constant c) { return c->value->value(); } +inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } - -void shiftLeftR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { int tmpHi = newTemp(con), tmpLo = newTemp(con); @@ -406,13 +455,13 @@ void shiftLeftR(Context* con, unsigned size, Assembler::Register a, Assembler::R emit(con, lsl(t->low, b->low, a->low)); } -void shiftLeftC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void shiftLeftC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsli(t->low, b->low, getValue(a))); } -void shiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { int tmpHi = newTemp(con), tmpLo = newTemp(con); @@ -422,7 +471,7 @@ void shiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler:: emit(con, orr(t->low, t->low, tmpLo)); emit(con, SETS(addi(tmpHi, a->low, -32))); emit(con, asr(tmpLo, b->high, tmpHi)); - emit(con, SETCOND(b(8), LE)); + emit(con, SETCOND(::b(8), LE)); emit(con, orri(t->low, tmpLo, 0)); emit(con, asr(t->high, b->high, a->low)); freeTemp(con, tmpHi); freeTemp(con, tmpLo); @@ -431,13 +480,13 @@ void shiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler:: } } -void shiftRightC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void shiftRightC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, asri(t->low, b->low, getValue(a))); } -void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) +void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { emit(con, lsr(t->low, b->low, a->low)); if (size == 8) { @@ -453,14 +502,14 @@ void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register a, Ass } } -void unsignedShiftRightC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) +void unsignedShiftRightC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsri(t->low, b->low, getValue(a))); } void -updateImmediate(System* s, void* dst, int64_t src, unsigned size) +updateImmediate(System* s, void* dst, int64_t src, unsigned size, bool) { switch (size) { case 4: { @@ -479,12 +528,13 @@ updateImmediate(System* s, void* dst, int64_t src, unsigned size) class ImmediateListener: public Promise::Listener { public: - ImmediateListener(System* s, void* dst, unsigned size, unsigned offset): - s(s), dst(dst), size(size), offset(offset) + ImmediateListener(System* s, void* dst, unsigned size, unsigned offset, + bool address): + s(s), dst(dst), size(size), offset(offset), address(address) { } virtual bool resolve(int64_t value, void** location) { - updateImmediate(s, dst, value, size); + updateImmediate(s, dst, value, size, address); if (location) *location = static_cast(dst) + offset; return false; } @@ -493,26 +543,28 @@ class ImmediateListener: public Promise::Listener { void* dst; unsigned size; unsigned offset; + bool address; }; class ImmediateTask: public Task { public: ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, - unsigned promiseOffset): + unsigned promiseOffset, bool address): Task(next), promise(promise), offset(offset), size(size), - promiseOffset(promiseOffset) + promiseOffset(promiseOffset), + address(address) { } virtual void run(Context* c) { if (promise->resolved()) { updateImmediate - (c->s, c->result + offset->value(), promise->value(), size); + (c->s, c->result + offset->value(), promise->value(), size, address); } else { new (promise->listen(sizeof(ImmediateListener))) ImmediateListener - (c->s, c->result + offset->value(), size, promiseOffset); + (c->s, c->result + offset->value(), size, promiseOffset, address); } } @@ -520,14 +572,48 @@ class ImmediateTask: public Task { Promise* offset; unsigned size; unsigned promiseOffset; + bool address; }; void appendImmediateTask(Context* c, Promise* promise, Promise* offset, - unsigned size, unsigned promiseOffset = 0) + unsigned size, unsigned promiseOffset, bool address) { c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset, size, promiseOffset); + (c->tasks, promise, offset, size, promiseOffset, address); +} + +class ConstantPoolEntry: public Promise { + public: + ConstantPoolEntry(Context* c, Promise* constant): + c(c), constant(constant), next(c->constantPool), address(0) + { + c->constantPool = this; + ++ c->constantPoolCount; + } + + virtual int64_t value() { + assert(c, resolved()); + + return reinterpret_cast(address); + } + + virtual bool resolved() { + return address != 0; + } + + Context* c; + Promise* constant; + ConstantPoolEntry* next; + void* address; + unsigned constantPoolCount; +}; + +ConstantPoolEntry* +appendConstantPoolEntry(Context* c, Promise* constant) +{ + return new (c->zone->allocate(sizeof(ConstantPoolEntry))) + ConstantPoolEntry(c, constant); } void @@ -619,7 +705,7 @@ moveCR2(Context* c, unsigned, Assembler::Constant* src, { if (dstSize <= 4) { if (src->value->resolved()) { - int32_t i = getValue(c); + int32_t i = getValue(src); emit(c, movi(dst->low, lo8(i))); if (!isInt8(i)) { emit(c, orri(dst->low, dst->low, hi8(i), 12)); @@ -632,7 +718,7 @@ moveCR2(Context* c, unsigned, Assembler::Constant* src, } } else { appendImmediateTask - (c, src->value, offset(c), BytesPerWord, promiseOffset); + (c, src->value, offset(c), BytesPerWord, promiseOffset, false); emit(c, movi(dst->low, 0)); emit(c, orri(dst->low, dst->low, 0, 12)); emit(c, orri(dst->low, dst->low, 0, 8)); @@ -650,16 +736,16 @@ moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, moveCR2(c, srcSize, src, dstSize, dst, 0); } -void addR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - emit(con, SETS(addc(t->low, a->low, b->low))); + emit(con, SETS(adc(t->low, a->low, b->low))); emit(con, adc(t->high, a->high, b->high)); } else { emit(con, add(t->low, a->low, b->low)); } } -void addC(Context* con, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) { +void addC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); int32_t i = getValue(a); @@ -679,7 +765,7 @@ void addC(Context* con, unsigned size, Assembler::Constant a, Assembler::Registe } } -void subR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { emit(con, SETS(rsb(t->low, a->low, b->low))); emit(con, rsc(t->high, a->high, b->high)); @@ -688,7 +774,7 @@ void subR(Context* con, unsigned size, Assembler::Register a, Assembler::Registe } } -void subC(Context* c, unsigned size, Assembler::Constant a, Assembler::Register b, Assembler::Register t) { +void subC(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(c, size == BytesPerWord); ResolvedPromise promise(- a->value->value()); @@ -696,7 +782,7 @@ void subC(Context* c, unsigned size, Assembler::Constant a, Assembler::Register addC(c, size, &constant, b, t); } -void multiplyR(Context* con, unsigned size, Assembler::Register a, Assembler::Register b, Assembler::Register t) { +void multiplyR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { emit(con, mul(t->high, a->low, b->high)); emit(con, mla(t->high, a->high, b->low, t->high)); @@ -944,19 +1030,19 @@ andR(Context* c, unsigned size, Assembler::Register* a, } void -andC(Context* c, unsigned size, Assembler::Constant* a, +andC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* dst) { assert(con, size == BytesPerWord); int32_t i = getValue(a); if (i) { - emit(con, andi(t->low, b->low, lo8(i))); - emit(con, andi(t->low, b->low, hi8(i), 12)); - emit(con, andi(t->low, b->low, lo8(hi16(i)), 8)); - emit(con, andi(t->low, b->low, hi8(hi16(i)), 4)); + emit(con, andi(dst->low, b->low, lo8(i))); + emit(con, andi(dst->low, b->low, hi8(i), 12)); + emit(con, andi(dst->low, b->low, lo8(hi16(i)), 8)); + emit(con, andi(dst->low, b->low, hi8(hi16(i)), 4)); } else { - moveRR(con, size, b, size, t); + moveRR(con, size, b, size, dst); } } @@ -969,72 +1055,82 @@ orR(Context* c, unsigned size, Assembler::Register* a, } void -orC(Context* c, unsigned size, Assembler::Constant* a, +orC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* dst) { assert(con, size == BytesPerWord); int32_t i = getValue(a); if (i) { - emit(con, orri(t->low, b->low, lo8(i))); + emit(con, orri(dst->low, b->low, lo8(i))); if (!isInt8(i)) { - emit(con, orri(t->low, b->low, hi8(i), 12)); + emit(con, orri(dst->low, b->low, hi8(i), 12)); if (!isInt16(i)) { - emit(con, orri(t->low, b->low, lo8(hi16(i)), 8)); + emit(con, orri(dst->low, b->low, lo8(hi16(i)), 8)); if (!isInt24(i)) { - emit(con, orri(t->low, b->low, hi8(hi16(i)), 4)); + emit(con, orri(dst->low, b->low, hi8(hi16(i)), 4)); } } } } else { - moveRR(con, size, b, size, t); + moveRR(con, size, b, size, dst); } } void -xorR(Context* com, unsigned size, Assembler::Register* a, +xorR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) { - if (size == 8) emit(com, eor(dst->high, a->high, b->high)); - emit(com, eor(dst->low, a->low, b->low)); + if (size == 8) emit(con, eor(dst->high, a->high, b->high)); + emit(con, eor(dst->low, a->low, b->low)); } void -xorC(Context* com, unsigned size, Assembler::Constant* a, +xorC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* dst) { assert(con, size == BytesPerWord); int32_t i = getValue(a); if (i) { - emit(con, eori(t->low, b->low, lo8(i))); + emit(con, eori(dst->low, b->low, lo8(i))); if (!isInt8(i)) { - emit(con, eori(t->low, b->low, hi8(i), 12)); + emit(con, eori(dst->low, b->low, hi8(i), 12)); if (!isInt16(i)) { - emit(con, eori(t->low, b->low, lo8(hi16(i)), 8)); + emit(con, eori(dst->low, b->low, lo8(hi16(i)), 8)); if (!isInt24(i)) { - emit(con, eori(t->low, b->low, hi8(hi16(i)), 4)); + emit(con, eori(dst->low, b->low, hi8(hi16(i)), 4)); } } } } else { - moveRR(con, size, b, size, t); + moveRR(con, size, b, size, dst); } } void -moveAR(Context* c, unsigned srcSize, Assembler::Address* src, - unsigned dstSize, Assembler::Register* dst) +moveAR2(Context* c, unsigned srcSize, Assembler::Address* src, + unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) { assert(c, srcSize == 4 and dstSize == 4); Assembler::Constant constant(src->address); Assembler::Memory memory(dst->low, 0, -1, 0); + appendImmediateTask + (c, src->address, offset(c), BytesPerWord, promiseOffset, true); + moveCR(c, srcSize, &constant, dstSize, dst); moveMR(c, dstSize, &memory, dstSize, dst); } +void +moveAR(Context* c, unsigned srcSize, Assembler::Address* src, + unsigned dstSize, Assembler::Register* dst) +{ + moveAR2(c, srcSize, src, dstSize, dst, 0); +} + void compareRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, unsigned bSize UNUSED, Assembler::Register* b) @@ -1083,105 +1179,185 @@ compareRM(Context* c, unsigned aSize, Assembler::Register* a, c->client->releaseTemporary(tmp.low); } -void -longCompare(Context* c, Assembler::Operand* al, Assembler::Operand* ah, - Assembler::Operand* bl, Assembler::Operand* bh, - Assembler::Register* dst, BinaryOperationType compareSigned, - BinaryOperationType compareUnsigned) +int32_t +branch(Context* c, TernaryOperation op) { - ResolvedPromise negativePromise(-1); - Assembler::Constant negative(&negativePromise); + switch (op) { + case JumpIfEqual: + return beq(0); + + case JumpIfNotEqual: + return bne(0); + + case JumpIfLess: + return blt(0); + + case JumpIfGreater: + return bgt(0); + + case JumpIfLessOrEqual: + return ble(0); + + case JumpIfGreaterOrEqual: + return bge(0); + + default: + abort(c); + } +} - ResolvedPromise zeroPromise(0); - Assembler::Constant zero(&zeroPromise); +void +conditional(Context* c, int32_t branch, Assembler::Constant* target) +{ + appendOffsetTask(c, target->value, offset(c), true); + emit(c, branch); +} - ResolvedPromise positivePromise(1); - Assembler::Constant positive(&positivePromise); +void +branch(Context* c, TernaryOperation op, Assembler::Constant* target) +{ + conditional(c, branch(c, op), target); +} +void +branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, + Assembler::Operand* ah, Assembler::Operand* bl, + Assembler::Operand* bh, Assembler::Constant* target, + BinaryOperationType compareSigned, + BinaryOperationType compareUnsigned) +{ compareSigned(c, 4, ah, 4, bh); - unsigned less = c->code.length(); - emit(c, blt(0)); + unsigned next = 0; + + switch (op) { + case JumpIfEqual: + next = c->code.length(); + emit(c, bne(0)); - unsigned greater = c->code.length(); - emit(c, bgt(0)); + compareSigned(c, 4, al, 4, bl); + conditional(c, beq(0), target); + break; - compareUnsigned(c, 4, al, 4, bl); + case JumpIfNotEqual: + conditional(c, bne(0), target); - unsigned above = c->code.length(); - emit(c, bgt(0)); + compareSigned(c, 4, al, 4, bl); + conditional(c, bne(0), target); + break; - unsigned below = c->code.length(); - emit(c, blt(0)); + case JumpIfLess: + conditional(c, blt(0), target); - moveCR(c, 4, &zero, 4, dst); + next = c->code.length(); + emit(c, bgt(0)); - unsigned nextFirst = c->code.length(); - emit(c, b(0)); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, blt(0), target); + break; - updateOffset - (c->s, c->code.data + less, true, reinterpret_cast - (c->code.data + c->code.length())); + case JumpIfGreater: + conditional(c, bgt(0), target); - updateOffset - (c->s, c->code.data + below, true, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, blt(0)); - moveCR(c, 4, &negative, 4, dst); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, bgt(0), target); + break; - unsigned nextSecond = c->code.length(); - emit(c, b(0)); + case JumpIfLessOrEqual: + conditional(c, blt(0), target); - updateOffset - (c->s, c->code.data + greater, true, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, bgt(0)); - updateOffset - (c->s, c->code.data + above, true, reinterpret_cast - (c->code.data + c->code.length())); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, ble(0), target); + break; - moveCR(c, 4, &positive, 4, dst); + case JumpIfGreaterOrEqual: + conditional(c, bgt(0), target); - updateOffset - (c->s, c->code.data + nextFirst, false, reinterpret_cast - (c->code.data + c->code.length())); + next = c->code.length(); + emit(c, blt(0)); - updateOffset - (c->s, c->code.data + nextSecond, false, reinterpret_cast - (c->code.data + c->code.length())); + compareUnsigned(c, 4, al, 4, bl); + conditional(c, bge(0), target); + break; + + default: + abort(c); + } + + if (next) { + updateOffset + (c->s, c->code.data + next, true, reinterpret_cast + (c->code.data + c->code.length())); + } } void -longCompareR(Context* c, unsigned size UNUSED, Assembler::Register* a, - Assembler::Register* b, Assembler::Register* dst) +branchRR(Context* c, TernaryOperation op, unsigned size, + Assembler::Register* a, Assembler::Register* b, + Assembler::Constant* target) { - assert(c, size == 8); - - Assembler::Register ah(a->high); - Assembler::Register bh(b->high); - - longCompare(c, a, &ah, b, &bh, dst, CAST2(compareRR), - CAST2(compareUnsignedRR)); + if (size > BytesPerWord) { + Assembler::Register ah(a->high); + Assembler::Register bh(b->high); + + branchLong(c, op, a, &ah, b, &bh, target, CAST2(compareRR), + CAST2(compareRR)); + } else { + compareRR(c, size, a, size, b); + branch(c, op, target); + } } void -longCompareC(Context* c, unsigned size UNUSED, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) +branchCR(Context* c, TernaryOperation op, unsigned size, + Assembler::Constant* a, Assembler::Register* b, + Assembler::Constant* target) { - assert(c, size == 8); + if (size > BytesPerWord) { + int64_t v = a->value->value(); - int64_t v = a->value->value(); + ResolvedPromise low(v & ~static_cast(0)); + Assembler::Constant al(&low); - ResolvedPromise low(v & ~static_cast(0)); - Assembler::Constant al(&low); - - ResolvedPromise high((v >> 32) & ~static_cast(0)); - Assembler::Constant ah(&high); - - Assembler::Register bh(b->high); - - longCompare(c, &al, &ah, b, &bh, dst, CAST2(compareCR), - CAST2(compareUnsignedCR)); + ResolvedPromise high((v >> 32) & ~static_cast(0)); + Assembler::Constant ah(&high); + + Assembler::Register bh(b->high); + + branchLong(c, op, &al, &ah, b, &bh, target, CAST2(compareCR), + CAST2(compareCR)); + } else { + compareCR(c, size, a, size, b); + branch(c, op, target); + } +} + +void +branchRM(Context* c, TernaryOperation op, unsigned size, + Assembler::Register* a, Assembler::Memory* b, + Assembler::Constant* target) +{ + assert(c, size <= BytesPerWord); + + compareRM(c, size, a, size, b); + branch(c, op, target); +} + +void +branchCM(Context* c, TernaryOperation op, unsigned size, + Assembler::Constant* a, Assembler::Memory* b, + Assembler::Constant* target) +{ + assert(c, size <= BytesPerWord); + + compareCM(c, size, a, size, b); + branch(c, op, target); } ShiftMaskPromise* @@ -1257,6 +1433,18 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) callR(c, BytesPerWord, &tmp); } +void +alignedLongCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + Assembler::Register tmp(c->client->acquireTemporary()); + Assembler::Address address(appendConstantPoolEntry(c, target->value)); + moveAR2(c, BytesPerWord, &address, BytesPerWord, &tmp, 12); + callR(c, BytesPerWord, &tmp); + c->client->releaseTemporary(tmp.low); +} + void longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { @@ -1267,6 +1455,18 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) jumpR(c, BytesPerWord, &tmp); } +void +alignedLongJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) +{ + assert(c, size == BytesPerWord); + + Assembler::Register tmp(c->client->acquireTemporary()); + Assembler::Address address(appendConstantPoolEntry(c, target->value)); + moveAR2(c, BytesPerWord, &address, BytesPerWord, &tmp, 12); + jumpR(c, BytesPerWord, &tmp); + c->client->releaseTemporary(tmp.low); +} + void jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { @@ -1339,7 +1539,7 @@ return_(Context* c) } void -memoryBarrier(Context* c) {} +memoryBarrier(Context*) {} // END OPERATION COMPILERS @@ -1355,96 +1555,94 @@ populateTables(ArchitectureContext* c) UnaryOperationType* uo = c->unaryOperations; BinaryOperationType* bo = c->binaryOperations; TernaryOperationType* to = c->ternaryOperations; + BranchOperationType* bro = c->branchOperations; zo[Return] = return_; zo[LoadBarrier] = memoryBarrier; zo[StoreStoreBarrier] = memoryBarrier; zo[StoreLoadBarrier] = memoryBarrier; - uo[index(LongCall, C)] = CAST1(longCallC); + uo[index(c, LongCall, C)] = CAST1(longCallC); - uo[index(LongJump, C)] = CAST1(longJumpC); + uo[index(c, AlignedLongCall, C)] = CAST1(alignedLongCallC); - uo[index(Jump, R)] = CAST1(jumpR); - uo[index(Jump, C)] = CAST1(jumpC); + uo[index(c, LongJump, C)] = CAST1(longJumpC); - uo[index(AlignedJump, R)] = CAST1(jumpR); - uo[index(AlignedJump, C)] = CAST1(jumpC); + uo[index(c, AlignedLongJump, C)] = CAST1(alignedLongJumpC); - uo[index(JumpIfEqual, C)] = CAST1(jumpIfEqualC); - uo[index(JumpIfNotEqual, C)] = CAST1(jumpIfNotEqualC); - uo[index(JumpIfGreater, C)] = CAST1(jumpIfGreaterC); - uo[index(JumpIfGreaterOrEqual, C)] = CAST1(jumpIfGreaterOrEqualC); - uo[index(JumpIfLess, C)] = CAST1(jumpIfLessC); - uo[index(JumpIfLessOrEqual, C)] = CAST1(jumpIfLessOrEqualC); + uo[index(c, Jump, R)] = CAST1(jumpR); + uo[index(c, Jump, C)] = CAST1(jumpC); - uo[index(Call, C)] = CAST1(callC); - uo[index(Call, R)] = CAST1(callR); + uo[index(c, AlignedJump, R)] = CAST1(jumpR); + uo[index(c, AlignedJump, C)] = CAST1(jumpC); - uo[index(AlignedCall, C)] = CAST1(callC); - uo[index(AlignedCall, R)] = CAST1(callR); + uo[index(c, Call, C)] = CAST1(callC); + uo[index(c, Call, R)] = CAST1(callR); - bo[index(Move, R, R)] = CAST2(moveRR); - bo[index(Move, C, R)] = CAST2(moveCR); - bo[index(Move, C, M)] = CAST2(moveCM); - bo[index(Move, M, R)] = CAST2(moveMR); - bo[index(Move, R, M)] = CAST2(moveRM); - bo[index(Move, A, R)] = CAST2(moveAR); + uo[index(c, AlignedCall, C)] = CAST1(callC); + uo[index(c, AlignedCall, R)] = CAST1(callR); - bo[index(MoveZ, R, R)] = CAST2(moveZRR); - bo[index(MoveZ, M, R)] = CAST2(moveZMR); - bo[index(MoveZ, C, R)] = CAST2(moveCR); + bo[index(c, Move, R, R)] = CAST2(moveRR); + bo[index(c, Move, C, R)] = CAST2(moveCR); + bo[index(c, Move, C, M)] = CAST2(moveCM); + bo[index(c, Move, M, R)] = CAST2(moveMR); + bo[index(c, Move, R, M)] = CAST2(moveRM); + bo[index(c, Move, A, R)] = CAST2(moveAR); - bo[index(Compare, R, R)] = CAST2(compareRR); - bo[index(Compare, C, R)] = CAST2(compareCR); - bo[index(Compare, R, M)] = CAST2(compareRM); - bo[index(Compare, C, M)] = CAST2(compareCM); + bo[index(c, MoveZ, R, R)] = CAST2(moveZRR); + bo[index(c, MoveZ, M, R)] = CAST2(moveZMR); + bo[index(c, MoveZ, C, R)] = CAST2(moveCR); - bo[index(Negate, R, R)] = CAST2(negateRR); + bo[index(c, Negate, R, R)] = CAST2(negateRR); - to[index(Add, R)] = CAST3(addR); - to[index(Add, C)] = CAST3(addC); + to[index(c, Add, R)] = CAST3(addR); + to[index(c, Add, C)] = CAST3(addC); - to[index(Subtract, R)] = CAST3(subR); - to[index(Subtract, C)] = CAST3(subC); + to[index(c, Subtract, R)] = CAST3(subR); + to[index(c, Subtract, C)] = CAST3(subC); - to[index(Multiply, R)] = CAST3(multiplyR); + to[index(c, Multiply, R)] = CAST3(multiplyR); - to[index(Divide, R)] = CAST3(divideR); + to[index(c, ShiftLeft, R)] = CAST3(shiftLeftR); + to[index(c, ShiftLeft, C)] = CAST3(shiftLeftC); - to[index(Remainder, R)] = CAST3(remainderR); + to[index(c, ShiftRight, R)] = CAST3(shiftRightR); + to[index(c, ShiftRight, C)] = CAST3(shiftRightC); - to[index(ShiftLeft, R)] = CAST3(shiftLeftR); - to[index(ShiftLeft, C)] = CAST3(shiftLeftC); + to[index(c, UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); + to[index(c, UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); - to[index(ShiftRight, R)] = CAST3(shiftRightR); - to[index(ShiftRight, C)] = CAST3(shiftRightC); + to[index(c, And, C)] = CAST3(andC); + to[index(c, And, R)] = CAST3(andR); - to[index(UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); - to[index(UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); + to[index(c, Or, C)] = CAST3(orC); + to[index(c, Or, R)] = CAST3(orR); - to[index(And, C)] = CAST3(andC); - to[index(And, R)] = CAST3(andR); + to[index(c, Xor, C)] = CAST3(xorC); + to[index(c, Xor, R)] = CAST3(xorR); - to[index(Or, C)] = CAST3(orC); - to[index(Or, R)] = CAST3(orR); - - to[index(Xor, C)] = CAST3(xorC); - to[index(Xor, R)] = CAST3(xorR); - - to[index(LongCompare, R)] = CAST3(longCompareR); - to[index(LongCompare, C)] = CAST3(longCompareC); + bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); + bro[branchIndex(c, C, R)] = CAST_BRANCH(branchCR); + bro[branchIndex(c, C, M)] = CAST_BRANCH(branchCM); + bro[branchIndex(c, R, M)] = CAST_BRANCH(branchRM); } -// TODO class MyArchitecture: public Assembler::Architecture { public: MyArchitecture(System* system): c(system), referenceCount(0) { populateTables(&c); } - virtual unsigned registerCount() { - return 16; + virtual unsigned floatRegisterSize() { + return 0; + } + + virtual uint32_t generalRegisterMask() { + return 0xFFFFFFFF; + } + + virtual uint32_t floatRegisterMask() { + return 0; } virtual int stack() { @@ -1456,11 +1654,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual int returnLow() { - return 4; + return 0; } virtual int returnHigh() { - return (BytesPerWord == 4 ? 3 : NoRegister); + return 1; } virtual int virtualCallTarget() { @@ -1471,12 +1669,12 @@ class MyArchitecture: public Assembler::Architecture { return 3; } - virtual bool condensedAddressing() { + virtual bool bigEndian() { return false; } - virtual bool bigEndian() { - return false; + virtual uintptr_t maximumImmediateJump() { + return 0x7FFFFF; } virtual bool reserved(int register_) { @@ -1508,7 +1706,7 @@ class MyArchitecture: public Assembler::Architecture { return index + 0; } - + virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } @@ -1522,12 +1720,14 @@ class MyArchitecture: public Assembler::Architecture { } virtual void updateCall(UnaryOperation op UNUSED, - bool assertAlignment UNUSED, void* returnAddress, + void* returnAddress, void* newTarget) { switch (op) { case Call: - case Jump: { + case Jump: + case AlignedCall: + case AlignedJump: { updateOffset(c.s, static_cast(returnAddress) - 4, false, reinterpret_cast(newTarget)); } break; @@ -1535,7 +1735,15 @@ class MyArchitecture: public Assembler::Architecture { case LongCall: case LongJump: { updateImmediate(c.s, static_cast(returnAddress) - 12, - reinterpret_cast(newTarget), BytesPerWord); + reinterpret_cast(newTarget), BytesPerWord, + false); + } break; + + case AlignedLongCall: + case AlignedLongJump: { + uint32_t* p = static_cast(returnAddress) - 4; + *reinterpret_cast(unha16(p[0] & 0xFFFF, p[1] & 0xFFFF)) + = newTarget; } break; default: abort(&c); @@ -1546,13 +1754,8 @@ class MyArchitecture: public Assembler::Architecture { return 4; } - virtual uintptr_t getConstant(const void* src) { - const int32_t* p = static_cast(src); - return (p[0] << 16) | (p[1] & 0xFFFF); - } - virtual void setConstant(void* dst, uintptr_t constant) { - updateImmediate(c.s, dst, constant, BytesPerWord); + updateImmediate(c.s, dst, constant, BytesPerWord, false); } virtual unsigned alignFrameSize(unsigned sizeInWords) { @@ -1565,11 +1768,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameHeaderSize() { - return 0; + return FrameHeaderSize; } virtual unsigned frameReturnAddressSize() { - return 0; + return 1; } virtual unsigned frameFooterSize() { @@ -1577,7 +1780,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int returnAddressOffset() { - return 8 / BytesPerWord; + return 1; } virtual int framePointerOffset() { @@ -1590,6 +1793,22 @@ class MyArchitecture: public Assembler::Architecture { *stack = *static_cast(*stack); } + virtual BinaryOperation hasBinaryIntrinsic(Thread*, object) { + return NoBinaryOperation; + } + + virtual TernaryOperation hasTernaryIntrinsic(Thread*, object) { + return NoTernaryOperation; + } + + virtual bool alwaysCondensed(BinaryOperation) { + return false; + } + + virtual bool alwaysCondensed(TernaryOperation) { + return false; + } + virtual void plan (UnaryOperation, unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, @@ -1600,28 +1819,46 @@ class MyArchitecture: public Assembler::Architecture { *thunk = false; } - virtual void plan + virtual void planSource (BinaryOperation op, unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, - unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, - bool* thunk) + unsigned, bool* thunk) { *aTypeMask = ~0; *aRegisterMask = ~static_cast(0); - *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); - *bRegisterMask = ~static_cast(0); - *thunk = false; switch (op) { - case Compare: - *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); - *bTypeMask = (1 << RegisterOperand); - break; - case Negate: *aTypeMask = (1 << RegisterOperand); + break; + + case Absolute: + case FloatAbsolute: + case FloatSquareRoot: + case FloatNegate: + case Float2Float: + case Float2Int: + case Int2Float: + *thunk = true; + break; + + default: + break; + } + } + + virtual void planDestination + (BinaryOperation op, + unsigned, uint8_t, uint64_t, + unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask) + { + *bTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand); + *bRegisterMask = ~static_cast(0); + + switch (op) { + case Negate: *bTypeMask = (1 << RegisterOperand); break; @@ -1630,12 +1867,30 @@ class MyArchitecture: public Assembler::Architecture { } } - virtual void plan + virtual void planMove + (unsigned, uint8_t* srcTypeMask, uint64_t* srcRegisterMask, + uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask, + uint8_t dstTypeMask, uint64_t) + { + *srcTypeMask = ~0; + *srcRegisterMask = ~static_cast(0); + + *tmpTypeMask = 0; + *tmpRegisterMask = 0; + + if (dstTypeMask & (1 << MemoryOperand)) { + // can't move directly from memory or constant to memory + *srcTypeMask = 1 << RegisterOperand; + *tmpTypeMask = 1 << RegisterOperand; + *tmpRegisterMask = ~static_cast(0); + } + } + + virtual void planSource (TernaryOperation op, unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, - unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask, - bool* thunk) + unsigned, bool* thunk) { *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); *aRegisterMask = ~static_cast(0); @@ -1657,22 +1912,44 @@ class MyArchitecture: public Assembler::Architecture { *aTypeMask = *bTypeMask = (1 << RegisterOperand); break; - case LongCompare: - *bTypeMask = (1 << RegisterOperand); - break; - case Divide: case Remainder: - *bTypeMask = ~0; + case FloatAdd: + case FloatSubtract: + case FloatMultiply: + case FloatDivide: + case FloatRemainder: + case JumpIfFloatEqual: + case JumpIfFloatNotEqual: + case JumpIfFloatLess: + case JumpIfFloatGreater: + case JumpIfFloatLessOrEqual: + case JumpIfFloatGreaterOrEqual: + case JumpIfFloatLessOrUnordered: + case JumpIfFloatGreaterOrUnordered: + case JumpIfFloatLessOrEqualOrUnordered: + case JumpIfFloatGreaterOrEqualOrUnordered: *thunk = true; break; default: break; } + } - *cTypeMask = *bTypeMask; - *cRegisterMask = *bRegisterMask; + virtual void planDestination + (TernaryOperation op, + unsigned, uint8_t, uint64_t, + unsigned, uint8_t, const uint64_t, + unsigned, uint8_t* cTypeMask, uint64_t* cRegisterMask) + { + if (isBranch(op)) { + *cTypeMask = (1 << ConstantOperand); + *cRegisterMask = 0; + } else { + *cTypeMask = (1 << RegisterOperand); + *cRegisterMask = ~static_cast(0); + } } virtual void acquire() { @@ -1874,30 +2151,40 @@ class MyAssembler: public Assembler { virtual void apply(UnaryOperation op, unsigned aSize, OperandType aType, Operand* aOperand) { - arch_->c.unaryOperations[index(op, aType)](&c, aSize, aOperand); + arch_->c.unaryOperations[index(&(arch_->c), op, aType)] + (&c, aSize, aOperand); } virtual void apply(BinaryOperation op, unsigned aSize, OperandType aType, Operand* aOperand, unsigned bSize, OperandType bType, Operand* bOperand) { - arch_->c.binaryOperations[index(op, aType, bType)] + arch_->c.binaryOperations[index(&(arch_->c), op, aType, bType)] (&c, aSize, aOperand, bSize, bOperand); } virtual void apply(TernaryOperation op, - unsigned, OperandType aType, Operand* aOperand, + unsigned aSize, OperandType aType, Operand* aOperand, unsigned bSize, OperandType bType UNUSED, Operand* bOperand, unsigned cSize UNUSED, OperandType cType UNUSED, Operand* cOperand) { - assert(&c, bSize == cSize); - assert(&c, bType == RegisterOperand); - assert(&c, cType == RegisterOperand); + if (isBranch(op)) { + assert(&c, aSize == bSize); + assert(&c, cSize == BytesPerWord); + assert(&c, cType == ConstantOperand); - arch_->c.ternaryOperations[index(op, aType)] - (&c, bSize, aOperand, bOperand, cOperand); + arch_->c.branchOperations[branchIndex(&(arch_->c), aType, bType)] + (&c, op, aSize, aOperand, bOperand, cOperand); + } else { + assert(&c, bSize == cSize); + assert(&c, bType == RegisterOperand); + assert(&c, cType == RegisterOperand); + + arch_->c.ternaryOperations[index(&(arch_->c), op, aType)] + (&c, bSize, aOperand, bOperand, cOperand); + } } virtual void writeTo(uint8_t* dst) { @@ -1907,9 +2194,21 @@ class MyAssembler: public Assembler { memcpy(dst + b->start, c.code.data + b->offset, b->size); } + unsigned index = c.code.length(); + assert(&c, index % BytesPerWord == 0); + for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { + e->address = dst + index; + index += BytesPerWord; + } + for (Task* t = c.tasks; t; t = t->next) { t->run(&c); } + + for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { + *static_cast(e->address) = e->constant->value(); +// fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); + } } virtual Promise* offset() { @@ -1932,6 +2231,10 @@ class MyAssembler: public Assembler { return c.code.length(); } + virtual unsigned scratchSize() { + return c.constantPoolCount * BytesPerWord; + } + virtual void dispose() { c.code.dispose(); } @@ -1945,7 +2248,7 @@ class MyAssembler: public Assembler { namespace vm { Assembler::Architecture* -makeArchitecture(System* system) +makeArchitecture(System* system, bool) { return new (allocate(system, sizeof(MyArchitecture))) MyArchitecture(system); } diff --git a/src/arm.h b/src/arm.h index b7b844685d..f510d3e960 100644 --- a/src/arm.h +++ b/src/arm.h @@ -27,7 +27,7 @@ namespace vm { inline void trap() { - asm("nop"); + asm("bkpt"); } inline void diff --git a/src/compile-arm.S b/src/compile-arm.S new file mode 100644 index 0000000000..5ddf7140f2 --- /dev/null +++ b/src/compile-arm.S @@ -0,0 +1,110 @@ +/* Copyright (c) 2010, 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. */ + +#ifdef AVIAN_CONTINUATIONS +# error "Continuations not yet supported on ARM port" +#endif + +#include "types.h" + +.text + +#define BYTES_PER_WORD 4 + +#define LOCAL(x) L##x + +#ifdef __APPLE__ +# define GLOBAL(x) _##x +#else +# define GLOBAL(x) x +#endif + +.globl GLOBAL(vmInvoke) +GLOBAL(vmInvoke): + /* + arguments + r0 : thread + r1 : function + r2 : arguments + r3 : argumentFootprint + [sp, #0] : frameSize (not used) + [sp, #4] : returnType + */ + + // save stack frame + mov ip, sp + + // save all non-volatile registers + stmfd sp!, {r4-r11, lr} + + // save return type + ldr r4, [ip, #4] + str r4, [sp, #-4]! + + // we're at the bottom of our local stack frame; save it + mov ip, sp + + // align stack, if necessary + eor r4, sp, r3 + tst r4, #4 + subne sp, sp, #4 + + // copy arguments into place + sub sp, r3 + mov r4, #0 + b LOCAL(vmInvoke_argumentTest) + +LOCAL(vmInvoke_argumentLoop): + ldr r5, [r2, r4] + str r5, [sp, r4] + add r4, r4, #BYTES_PER_WORD + +LOCAL(vmInvoke_argumentTest): + cmp r4, r3 + blt LOCAL(vmInvoke_argumentLoop) + + // save the beginning of our stack frame + str ip, [sp, #-8]! + + // we use ip (r12) to hold the thread pointer, by convention + mov ip, r0 + + // load and call function address + blx r1 + +LOCAL(vmInvoke_returnAddress): + // restore stack pointer + ldr sp, [sp] + + // restore return type + ldr ip, [sp] + + // restore callee-saved registers + ldmfd sp!, {r4-r11, lr} + +LOCAL(vmInvoke_void): + cmp ip, #VOID_TYPE + beq LOCAL(vmInvoke_return) + +LOCAL(vmInvoke_int64): + cmp ip, #INT64_TYPE + beq LOCAL(vmInvoke_return) + +LOCAL(vmInvoke_int32): + mov r1, #0 + +LOCAL(vmInvoke_return): + bx lr + +.globl GLOBAL(vmJumpAndInvoke) +GLOBAL(vmJumpAndInvoke): + // vmJumpAndInvoke should only be called when continuations are + // enabled + bkpt From 1daa93d3c487faa194c291ba1778ec53db9f2c27 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 03:05:18 +0200 Subject: [PATCH 002/274] add ability to append to files --- classpath/java-io.cpp | 4 ++-- classpath/java/io/FileOutputStream.java | 9 +++++++-- test/FileOutput.java | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 test/FileOutput.java diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 22880146ac..134045bdd2 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -593,11 +593,11 @@ Java_java_io_FileInputStream_close(JNIEnv* e, jclass, jint fd) } extern "C" JNIEXPORT jint JNICALL -Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path) +Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path, jboolean append) { string_t chars = getChars(e, path); if (chars) { - int fd = doOpen(e, chars, O_WRONLY | O_CREAT | O_TRUNC); + int fd = doOpen(e, chars, append ? (O_WRONLY | O_APPEND) : (O_WRONLY | O_CREAT | O_TRUNC)); releaseChars(e, path, chars); return fd; } else { diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index d61d44e136..5a485e04f3 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -22,14 +22,19 @@ public class FileOutputStream extends OutputStream { } public FileOutputStream(String path) throws IOException { - fd = open(path); + this(path, false); } + public FileOutputStream(String path, boolean append) throws IOException { + fd = open(path, append); + } + + public FileOutputStream(File file) throws IOException { this(file.getPath()); } - private static native int open(String path) throws IOException; + private static native int open(String path, boolean append) throws IOException; private static native void write(int fd, int c) throws IOException; diff --git a/test/FileOutput.java b/test/FileOutput.java new file mode 100644 index 0000000000..e097f18598 --- /dev/null +++ b/test/FileOutput.java @@ -0,0 +1,23 @@ +import java.io.FileOutputStream; +import java.io.IOException; + + +public class FileOutput { + + /** + * @param args + * @throws IOException + */ + public static void main(String[] args) throws IOException { + FileOutputStream f = new FileOutputStream("test.txt"); + f.write("Hello world!\n".getBytes()); + f.close(); + + FileOutputStream f2 = new FileOutputStream("test.txt", true); + f2.write("Hello world again!".getBytes()); + f2.close(); + + + } + +} From 4dc05844df51ed45e2210c4146e2f4a07c5022aa Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 03:13:09 +0200 Subject: [PATCH 003/274] add java.util.Properties.propertyNames() method --- classpath/java/util/Properties.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index a09ba77808..749869823b 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -48,6 +48,10 @@ public class Properties extends Hashtable { public Object setProperty(String key, String value) { return put(key, value); } + + public Enumeration propertyNames() { + return keys(); + } private static class Parser { private StringBuilder key = null; From 03b66375f4afdc49a50faae7fa7f2189658295b8 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 03:25:51 +0200 Subject: [PATCH 004/274] add Collections.enumeration(Collection c) --- classpath/java/util/Collections.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 00facfaa0e..acabd6811a 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -79,6 +79,10 @@ public class Collections { sb.append("}"); return sb.toString(); } + + public static Enumeration enumeration(Collection c) { + return new IteratorEnumeration (c.iterator()); + } static class IteratorEnumeration implements Enumeration { private final Iterator it; From a50fda1a5eb893ad4dc73a2c58fe57d072f007b4 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 03:31:16 +0200 Subject: [PATCH 005/274] add ClassLoader.getResources calls --- classpath/java/lang/ClassLoader.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 9cb5b0e664..3cc052ac48 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -13,6 +13,10 @@ package java.lang; import java.io.InputStream; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; public abstract class ClassLoader { private final ClassLoader parent; @@ -123,4 +127,24 @@ public abstract class ClassLoader { public static InputStream getSystemResourceAsStream(String path) { return getSystemClassLoader().getResourceAsStream(path); } + + public static Enumeration getSystemResources(String name) throws IOException { + return getSystemClassLoader().getResources(name); + } + + public Enumeration getResources(String name) + throws IOException { + Collection resources = collectResources(name); + return Collections.enumeration(resources); + } + + private Collection collectResources(String name) { + Collection urls = parent != null ? parent.collectResources(name) : new ArrayList(5); + URL url = findResource(name); + if (url != null) { + urls.add(url); + } + return urls; + } + } From 416942530792e5c9276d58be07e7079467efe6e4 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 03:39:58 +0200 Subject: [PATCH 006/274] add error classes --- classpath/java/lang/IllegalAccessError.java | 26 +++++++++++++++++++++ classpath/java/lang/InstantiationError.java | 26 +++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 classpath/java/lang/IllegalAccessError.java create mode 100644 classpath/java/lang/InstantiationError.java diff --git a/classpath/java/lang/IllegalAccessError.java b/classpath/java/lang/IllegalAccessError.java new file mode 100644 index 0000000000..4e0cf6e399 --- /dev/null +++ b/classpath/java/lang/IllegalAccessError.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2010, 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; + +/** + * TODO : current Avian runtime doesn't check, need to be implemented. + * + */ +public class IllegalAccessError extends IncompatibleClassChangeError { + + public IllegalAccessError(String message) { + super(message); + } + + public IllegalAccessError() { + } + +} diff --git a/classpath/java/lang/InstantiationError.java b/classpath/java/lang/InstantiationError.java new file mode 100644 index 0000000000..82cf51bc41 --- /dev/null +++ b/classpath/java/lang/InstantiationError.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2010, 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; + +/** + * TODO : current Avian runtime doesn't check, need to be implemented. + * + */ +public class InstantiationError extends IncompatibleClassChangeError { + + public InstantiationError(String message) { + super(message); + } + + public InstantiationError() { + } + +} From be1ba2ccf810e7f858982c73db9061ea1a37a5c9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Aug 2010 09:24:27 -0600 Subject: [PATCH 007/274] fix gnu build --- src/jnienv.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 1886301027..4404014ef9 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1952,9 +1952,15 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->FindClass = local::FindClass; envTable->ThrowNew = local::ThrowNew; envTable->ExceptionCheck = local::ExceptionCheck; +#ifdef AVIAN_GNU + envTable->NewDirectByteBuffer = vm::NewDirectByteBuffer; + envTable->GetDirectBufferAddress = vm::GetDirectBufferAddress; + envTable->GetDirectBufferCapacity = vm::GetDirectBufferCapacity; +#else envTable->NewDirectByteBuffer = local::NewDirectByteBuffer; envTable->GetDirectBufferAddress = local::GetDirectBufferAddress; envTable->GetDirectBufferCapacity = local::GetDirectBufferCapacity; +#endif envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; envTable->IsInstanceOf = local::IsInstanceOf; From 7eabe13921e9f927774b7ffa49f5d2dedd645147 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Aug 2010 09:30:39 -0600 Subject: [PATCH 008/274] verify file contents in FileOutput test --- test/FileOutput.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/FileOutput.java b/test/FileOutput.java index e097f18598..db4273f650 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -1,7 +1,8 @@ import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.File; import java.io.IOException; - public class FileOutput { /** @@ -9,6 +10,7 @@ public class FileOutput { * @throws IOException */ public static void main(String[] args) throws IOException { + try { FileOutputStream f = new FileOutputStream("test.txt"); f.write("Hello world!\n".getBytes()); f.close(); @@ -17,7 +19,22 @@ public class FileOutput { f2.write("Hello world again!".getBytes()); f2.close(); + FileInputStream in = new FileInputStream("test.txt"); + byte[] buffer = new byte[256]; + int c; + int offset = 0; + while ((c = in.read(buffer, offset, buffer.length - offset)) != -1) { + offset += c; + } + if (! "Hello world!\nHello world again!".equals + (new String(buffer, 0, offset))) + { + throw new RuntimeException(); + } + } finally { + new File("test.txt").delete(); + } } } From bcf7c0639c3369be1a113b70d5b58adab312eea6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 16 Aug 2010 09:37:44 -0600 Subject: [PATCH 009/274] clarify GNU Classpath build instructions in readme.txt --- readme.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 78bad0048a..7ccd3d5cd4 100644 --- a/readme.txt +++ b/readme.txt @@ -201,9 +201,18 @@ By default, Avian uses its own lightweight class library. However, that library only contains a relatively small subset of the classes and methods included in the JRE. If your application requires features beyond that subset, you may want to tell Avian to use GNU -Classpath instead. To do so, specify the directory where Classpath is +Classpath instead. In order for this to work, you must configure +Classpath with "--enable-static" and "--with-pic". For example: + + $ cd classpath-0.98 + $ ./configure --prefix=/usr/local/classpath-0.98 --disable-plugin \ + --enable-static --with-pic + $ make && make install + +Then, when building Avian, specify the directory where Classpath is installed, e.g.: + $ cd ../avian $ make clean $ make gnu=/usr/local/classpath-0.98 From 5c00cfac6fe349688042668a99901866aabb2def Mon Sep 17 00:00:00 2001 From: jet Date: Tue, 24 Aug 2010 17:59:01 -0600 Subject: [PATCH 010/274] Incomplete debugging of "Hello World!" on ARM. --- src/arm.cpp | 46 +++++++++++++++++++++++++--------------------- src/compile-arm.S | 5 ++++- src/compile.cpp | 2 +- src/compiler.cpp | 4 ++-- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 387c4ee688..b6968127dd 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -30,9 +30,9 @@ inline int DATA(int cond, int opcode, int S, int Rn, int Rd, int shift, int Sh, inline int DATAS(int cond, int opcode, int S, int Rn, int Rd, int Rs, int Sh, int Rm) { return cond<<28 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | Rs<<8 | Sh<<5 | 1<<4 | Rm; } inline int DATAI(int cond, int opcode, int S, int Rn, int Rd, int rot, int imm) -{ return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | imm; } +{ return cond<<28 | 1<<25 | opcode<<21 | S<<20 | Rn<<16 | Rd<<12 | rot<<8 | (imm&0xff); } inline int BRANCH(int cond, int L, int offset) -{ return cond<<28 | 5<<25 | L<<24 | offset; } +{ return cond<<28 | 5<<25 | L<<24 | (offset&0xffffff); } inline int BRANCHX(int cond, int L, int Rm) { return cond<<28 | 0x4bffc<<6 | L<<5 | 1<<4 | Rm; } inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) @@ -40,7 +40,7 @@ inline int MULTIPLY(int cond, int mul, int S, int Rd, int Rn, int Rs, int Rm) inline int XFER(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int shift, int Sh, int Rm) { return cond<<28 | 3<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | shift<<7 | Sh<<5 | Rm; } inline int XFERI(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, int offset) -{ return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offset; } +{ return cond<<28 | 2<<25 | P<<24 | U<<23 | B<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | (offset&0xfff); } inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, int H, int Rm) { return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) @@ -48,9 +48,11 @@ inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offs inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist) { return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; } inline int SWI(int cond, int imm) -{ return cond<<28 | 0x0f<<24 | imm; } +{ return cond<<28 | 0x0f<<24 | (imm&0xffffff); } inline int SWAP(int cond, int B, int Rn, int Rd, int Rm) { return cond<<28 | 1<<24 | B<<22 | Rn<<16 | Rd<<12 | 9<<4 | Rm; } +// FIELD CALCULATORS +inline int calcU(int imm) { return imm >= 0 ? 1 : 0; } // INSTRUCTIONS // The "cond" and "S" fields are set using the SETCOND() and SETS() functions inline int b(int offset) { return BRANCH(AL, 0, offset); } @@ -91,21 +93,21 @@ inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdLo, RdHi, Rs, Rm); } inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdLo, RdHi, Rs, Rm); } inline int ldr(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 0, 0, 1, Rn, Rd, 0, 0, Rm); } -inline int ldri(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 0, 0, 1, Rn, Rd, imm); } +inline int ldri(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 0, 0, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } -inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 1, Rn, Rd, imm); } +inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 1, Rn, Rd, abs(imm)); } inline int str(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 0, Rn, Rd, 0, 0, Rm); } -inline int stri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, 1, 0, W, 0, Rn, Rd, imm); } +inline int stri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 0, Rn, Rd, abs(imm)); } inline int strb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 0, Rn, Rd, 0, 0, Rm); } -inline int strbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, 1, 1, 0, 0, Rn, Rd, imm); } +inline int strbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 0, Rn, Rd, abs(imm)); } inline int ldrh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 0, 1, Rm); } -inline int ldrhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int ldrhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int strh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 0, Rn, Rd, 0, 1, Rm); } -inline int strhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 0, Rn, Rd, imm>>4 & 0xf, 0, 1, imm&0xf); } +inline int strhi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 0, Rn, Rd, abs(imm)>>4 & 0xf, 0, 1, abs(imm)&0xf); } inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 1, Rm); } -inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 1, imm&0xf); } +inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); } inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } -inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, 1, 0, 1, Rn, Rd, imm>>4 & 0xf, 1, 0, imm&0xf); } +inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); } inline int ldmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 1, Rn, rlist); } inline int ldmia(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 0, 1, Rn, rlist); } inline int stmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 0, Rn, rlist); } @@ -165,6 +167,7 @@ const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int StackRegister = 13; const int BaseRegister = 11; const int ThreadRegister = 12; +const int ProgramCounter = 15; class MyBlock: public Assembler::Block { public: @@ -317,8 +320,9 @@ bounded(int right, int left, int32_t v) void* updateOffset(System* s, uint8_t* instruction, bool conditional UNUSED, int64_t value) { - int32_t v = reinterpret_cast(value) - instruction; - + // ARM's PC is two words ahead, and branches drop the bottom 2 bits. + int32_t v = (reinterpret_cast(value) - (instruction + 8)) >> 2; + int32_t mask; expect(s, bounded(0, 8, v)); mask = 0xFFFFFF; @@ -455,7 +459,7 @@ void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler:: emit(con, lsl(t->low, b->low, a->low)); } -void shiftLeftC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) +void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsli(t->low, b->low, getValue(a))); @@ -480,7 +484,7 @@ void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler: } } -void shiftRightC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) +void shiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, asri(t->low, b->low, getValue(a))); @@ -502,7 +506,7 @@ void unsignedShiftRightR(Context* con, unsigned size, Assembler::Register* a, As } } -void unsignedShiftRightC(Context* con, unsigned, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) +void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { assert(con, size == BytesPerWord); emit(con, lsri(t->low, b->low, getValue(a))); @@ -1450,7 +1454,7 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - Assembler::Register tmp(0); + Assembler::Register tmp(5); // a non-arg reg that we don't mind clobbering moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); jumpR(c, BytesPerWord, &tmp); } @@ -1638,7 +1642,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual uint32_t generalRegisterMask() { - return 0xFFFFFFFF; + return 0xFFFF; } virtual uint32_t floatRegisterMask() { @@ -1674,14 +1678,14 @@ class MyArchitecture: public Assembler::Architecture { } virtual uintptr_t maximumImmediateJump() { - return 0x7FFFFF; + return 0x1FFFFFF; } virtual bool reserved(int register_) { switch (register_) { case StackRegister: case ThreadRegister: - case 15: + case ProgramCounter: return true; default: diff --git a/src/compile-arm.S b/src/compile-arm.S index 5ddf7140f2..ca70ca8fd2 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -79,10 +79,13 @@ LOCAL(vmInvoke_argumentTest): // load and call function address blx r1 -LOCAL(vmInvoke_returnAddress): +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): // restore stack pointer ldr sp, [sp] +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): // restore return type ldr ip, [sp] diff --git a/src/compile.cpp b/src/compile.cpp index b84d2ae6e8..fe193d00d7 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -40,7 +40,7 @@ namespace { namespace local { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; diff --git a/src/compiler.cpp b/src/compiler.cpp index 44217336a2..84860cea2a 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -19,8 +19,8 @@ namespace local { const bool DebugAppend = false; const bool DebugCompile = false; -const bool DebugResources = false; -const bool DebugFrame = false; +const bool DebugResources = true; +const bool DebugFrame = true; const bool DebugControl = false; const bool DebugReads = false; const bool DebugSites = false; From f740570ff671d39305238b81fab91f01726e31ed Mon Sep 17 00:00:00 2001 From: jet Date: Fri, 27 Aug 2010 18:52:33 -0600 Subject: [PATCH 011/274] Further debugging of ARM "Hello World!" JIT functionality. --- src/arm.S | 6 +- src/arm.cpp | 157 ++++++++++++++-------------------------------- src/compile-arm.S | 28 +++++++-- src/compiler.cpp | 4 +- 4 files changed, 74 insertions(+), 121 deletions(-) diff --git a/src/arm.S b/src/arm.S index 9df1b14ac3..fe068824b0 100644 --- a/src/arm.S +++ b/src/arm.S @@ -50,7 +50,9 @@ vmNativeCall: .globl vmJump vmJump: + mov lr, r0 + ldr r0, [sp] + ldr r1, [sp, #4] mov sp, r2 - mov r4, r3 - ldmia sp, {r0,r1} + mov r8, r3 bx lr diff --git a/src/arm.cpp b/src/arm.cpp index b6968127dd..564e3b9f23 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -68,10 +68,10 @@ inline int add(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, inline int adc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x5, 0, Rn, Rd, shift, Sh, Rm); } inline int sbc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x6, 0, Rn, Rd, shift, Sh, Rm); } inline int rsc(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x7, 0, Rn, Rd, shift, Sh, Rm); } -inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 0, Rn, 0, shift, Sh, Rm); } -inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 0, Rn, 0, shift, Sh, Rm); } -inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 0, Rn, 0, shift, Sh, Rm); } -inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 0, Rn, 0, shift, Sh, Rm); } +inline int tst(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x8, 1, Rn, 0, shift, Sh, Rm); } +inline int teq(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0x9, 1, Rn, 0, shift, Sh, Rm); } +inline int cmp(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xa, 1, Rn, 0, shift, Sh, Rm); } +inline int cmn(int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xb, 1, Rn, 0, shift, Sh, Rm); } inline int orr(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xc, 0, Rn, Rd, shift, Sh, Rm); } inline int mov(int Rd, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xd, 0, 0, Rd, shift, Sh, Rm); } inline int bic(int Rd, int Rn, int Rm, int Sh=0, int shift=0) { return DATA(AL, 0xe, 0, Rn, Rd, shift, Sh, Rm); } @@ -82,7 +82,7 @@ inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, R inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); } inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); } inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); } -inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0x0, 0, Rn, 0, rot, imm); } +inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } @@ -92,8 +92,8 @@ inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdLo, RdHi, Rs, Rm); } inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdLo, RdHi, Rs, Rm); } inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdLo, RdHi, Rs, Rm); } -inline int ldr(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 0, 0, 1, Rn, Rd, 0, 0, Rm); } -inline int ldri(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 0, 0, 1, Rn, Rd, abs(imm)); } +inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); } +inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } inline int ldrbi(int Rd, int Rn, int imm) { return XFERI(AL, 1, calcU(imm), 1, 0, 1, Rn, Rd, abs(imm)); } inline int str(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 0, Rn, Rd, 0, 0, Rm); } @@ -108,10 +108,9 @@ inline int ldrsh(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, inline int ldrshi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 1, abs(imm)&0xf); } inline int ldrsb(int Rd, int Rn, int Rm) { return XFER2(AL, 1, 1, 0, 1, Rn, Rd, 1, 0, Rm); } inline int ldrsbi(int Rd, int Rn, int imm) { return XFER2I(AL, 1, calcU(imm), 0, 1, Rn, Rd, abs(imm)>>4 & 0xf, 1, 0, abs(imm)&0xf); } -inline int ldmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 1, Rn, rlist); } -inline int ldmia(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 0, 1, Rn, rlist); } -inline int stmib(int Rn, int rlist) { return BLOCKXFER(AL, 1, 1, 0, 0, 0, Rn, rlist); } -inline int stmdb(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 0, 0, Rn, rlist); } +inline int pop(int Rd) { return XFERI(AL, 0, 1, 0, 0, 1, 13, Rd, 4); } +inline int ldmfd(int Rn, int rlist) { return BLOCKXFER(AL, 0, 1, 0, 1, 1, Rn, rlist); } +inline int stmfd(int Rn, int rlist) { return BLOCKXFER(AL, 1, 0, 0, 1, 0, Rn, rlist); } inline int swp(int Rd, int Rm, int Rn) { return SWAP(AL, 0, Rn, Rd, Rm); } inline int swpb(int Rd, int Rm, int Rn) { return SWAP(AL, 1, Rn, Rd, Rm); } inline int SETCOND(int ins, int cond) { return ((ins&0x0fffffff) | (cond<<28)); } @@ -158,15 +157,18 @@ inline bool isInt24(intptr_t v) { return v == (v & 0xffffff); } inline bool isInt32(intptr_t v) { return v == static_cast(v); } inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } +inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } + const unsigned FrameFooterSize = 2; const unsigned FrameHeaderSize = 0; const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; -const int StackRegister = 13; +const int ThreadRegister = 8; const int BaseRegister = 11; -const int ThreadRegister = 12; +const int StackRegister = 13; +const int LinkRegister = 14; const int ProgramCounter = 15; class MyBlock: public Assembler::Block { @@ -711,11 +713,11 @@ moveCR2(Context* c, unsigned, Assembler::Constant* src, if (src->value->resolved()) { int32_t i = getValue(src); emit(c, movi(dst->low, lo8(i))); - if (!isInt8(i)) { + if (!isOfWidth(i, 8)) { emit(c, orri(dst->low, dst->low, hi8(i), 12)); - if (!isInt16(i)) { + if (!isOfWidth(i, 16)) { emit(c, orri(dst->low, dst->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { + if (!isOfWidth(i, 24)) { emit(c, orri(dst->low, dst->low, hi8(hi16(i)), 4)); } } @@ -755,11 +757,11 @@ void addC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Regist int32_t i = getValue(a); if (i) { emit(con, addi(t->low, b->low, lo8(i))); - if (!isInt8(i)) { + if (!isOfWidth(i, 8)) { emit(con, addi(t->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { + if (!isOfWidth(i, 16)) { emit(con, addi(t->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { + if (!isOfWidth(i, 24)) { emit(con, addi(t->low, b->low, hi8(hi16(i)), 4)); } } @@ -918,12 +920,12 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src, assert(c, dstSize == BytesPerWord); if (dst->index == NoRegister) { - emit(c, stri(src->low, dst->base, dst->offset, 1)); + emit(c, stri(src->low, dst->base, dst->offset, dst->offset ? 1 : 0)); } else { assert(c, dst->offset == 0); assert(c, dst->scale == 1); - emit(c, str(src->low, dst->base, dst->index, 1)); + emit(c, str(src->low, dst->base, dst->index, dst->offset ? 1 : 0)); } } @@ -1041,12 +1043,12 @@ andC(Context* con, unsigned size, Assembler::Constant* a, int32_t i = getValue(a); if (i) { - emit(con, andi(dst->low, b->low, lo8(i))); - emit(con, andi(dst->low, b->low, hi8(i), 12)); - emit(con, andi(dst->low, b->low, lo8(hi16(i)), 8)); - emit(con, andi(dst->low, b->low, hi8(hi16(i)), 4)); + Assembler::Register tmp(con->client->acquireTemporary()); + moveCR(con, size, a, size, &tmp); + andR(con, size, &tmp, b, dst); + con->client->releaseTemporary(tmp.low); } else { - moveRR(con, size, b, size, dst); + emit(con, mov(dst->low, 0)); } } @@ -1067,11 +1069,11 @@ orC(Context* con, unsigned size, Assembler::Constant* a, int32_t i = getValue(a); if (i) { emit(con, orri(dst->low, b->low, lo8(i))); - if (!isInt8(i)) { + if (!isOfWidth(i, 8)) { emit(con, orri(dst->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { + if (!isOfWidth(i, 16)) { emit(con, orri(dst->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { + if (!isOfWidth(i, 24)) { emit(con, orri(dst->low, b->low, hi8(hi16(i)), 4)); } } @@ -1097,18 +1099,10 @@ xorC(Context* con, unsigned size, Assembler::Constant* a, int32_t i = getValue(a); if (i) { - emit(con, eori(dst->low, b->low, lo8(i))); - if (!isInt8(i)) { - emit(con, eori(dst->low, b->low, hi8(i), 12)); - if (!isInt16(i)) { - emit(con, eori(dst->low, b->low, lo8(hi16(i)), 8)); - if (!isInt24(i)) { - emit(con, eori(dst->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, dst); + Assembler::Register tmp(con->client->acquireTemporary()); + moveCR(con, size, a, size, &tmp); + xorR(con, size, &tmp, b, dst); + con->client->releaseTemporary(tmp.low); } } @@ -1432,7 +1426,7 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - Assembler::Register tmp(0); + Assembler::Register tmp(4); moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); callR(c, BytesPerWord, &tmp); } @@ -1454,7 +1448,7 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - Assembler::Register tmp(5); // a non-arg reg that we don't mind clobbering + Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); jumpR(c, BytesPerWord, &tmp); } @@ -1480,66 +1474,10 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) emit(c, b(0)); } -void -jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), EQ)); -} - -void -jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), NE)); -} - -void -jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), GT)); -} - -void -jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), GE)); -} - -void -jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), LS)); -} - -void -jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, SETCOND(b(0), LE)); -} - void return_(Context* c) { - emit(c, mov(15, 14)); + emit(c, bx(LinkRegister)); } void @@ -1768,7 +1706,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual void* frameIp(void* stack) { - return stack ? static_cast(stack)[2] : 0; + return stack ? static_cast(stack)[returnAddressOffset()] : 0; } virtual unsigned frameHeaderSize() { @@ -1776,7 +1714,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameReturnAddressSize() { - return 1; + return 0; } virtual unsigned frameFooterSize() { @@ -2033,10 +1971,9 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register returnAddress(0); - emit(&c, mov(returnAddress.low, 14)); + Register returnAddress(LinkRegister); - Memory returnAddressDst(StackRegister, 8); + Memory returnAddressDst(StackRegister, arch_->returnAddressOffset() * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); Register stack(StackRegister); @@ -2055,14 +1992,12 @@ class MyAssembler: public Assembler { virtual void popFrame() { Register stack(StackRegister); - Memory stackSrc(StackRegister, 0); + Memory stackSrc(StackRegister, arch_->framePointerOffset() * BytesPerWord); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); - Register returnAddress(0); - Memory returnAddressSrc(StackRegister, 8); + Register returnAddress(LinkRegister); + Memory returnAddressSrc(StackRegister, arch_->returnAddressOffset() * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); - - emit(&c, mov(14, returnAddress.low)); } virtual void popFrameForTailCall(unsigned footprint, @@ -2076,7 +2011,7 @@ class MyAssembler: public Assembler { Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); - emit(&c, mov(14, tmp.low)); + emit(&c, mov(LinkRegister, tmp.low)); Memory stackSrc(StackRegister, footprint * BytesPerWord); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); diff --git a/src/compile-arm.S b/src/compile-arm.S index ca70ca8fd2..3ac3310030 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -25,7 +25,14 @@ #else # define GLOBAL(x) x #endif - + +#define THREAD_STACK 2144 +#define THREAD_CONTINUATION 2148 +#define THREAD_EXCEPTION 44 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 +#define THREAD_EXCEPTION_OFFSET 2156 +#define THREAD_EXCEPTION_HANDLER 2160 + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): /* @@ -70,24 +77,33 @@ LOCAL(vmInvoke_argumentTest): cmp r4, r3 blt LOCAL(vmInvoke_argumentLoop) - // save the beginning of our stack frame + // save frame str ip, [sp, #-8]! - // we use ip (r12) to hold the thread pointer, by convention - mov ip, r0 + // we use r8 to hold the thread pointer, by convention + mov r8, r0 +.global GLOBAL(beforecall) +GLOBAL(beforecall): // load and call function address blx r1 +.global GLOBAL(aftercall) +GLOBAL(aftercall): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): - // restore stack pointer + + // restore frame ldr sp, [sp] .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): + + mov ip, #0 + str ip, [r8, #THREAD_STACK] + // restore return type - ldr ip, [sp] + ldr ip, [sp], #4 // restore callee-saved registers ldmfd sp!, {r4-r11, lr} diff --git a/src/compiler.cpp b/src/compiler.cpp index 84860cea2a..44217336a2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -19,8 +19,8 @@ namespace local { const bool DebugAppend = false; const bool DebugCompile = false; -const bool DebugResources = true; -const bool DebugFrame = true; +const bool DebugResources = false; +const bool DebugFrame = false; const bool DebugControl = false; const bool DebugReads = false; const bool DebugSites = false; From 56b59cef5c5c0d19bc988fb1d0d234bcc929b2ff Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 30 Aug 2010 16:16:02 +0100 Subject: [PATCH 012/274] use r6 instead of r0 in popFrameAndUpdateStackAndReturn This avoids clobbering the return value. --- src/arm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arm.cpp b/src/arm.cpp index 564e3b9f23..266f95ed97 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -2066,7 +2066,7 @@ class MyAssembler: public Assembler { { popFrame(); - Register tmp1(0); + Register tmp1(6); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); From b6a839950f2ff6a6a4352f4a16fda05352a8182f Mon Sep 17 00:00:00 2001 From: jet Date: Mon, 30 Aug 2010 16:13:10 -0600 Subject: [PATCH 013/274] Nine tests (including float and integer calculations) are now passing. --- src/arm.cpp | 107 +++++----------------------------------------------- 1 file changed, 10 insertions(+), 97 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 266f95ed97..95e07bc9b6 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -157,6 +157,7 @@ inline bool isInt24(intptr_t v) { return v == (v & 0xffffff); } inline bool isInt32(intptr_t v) { return v == static_cast(v); } inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } +inline bool isOfWidth(long long i, int size) { return static_cast(i) >> size == 0; } inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } const unsigned FrameFooterSize = 2; @@ -751,26 +752,6 @@ void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Regist } } -void addC(Context* con, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - emit(con, addi(t->low, b->low, lo8(i))); - if (!isOfWidth(i, 8)) { - emit(con, addi(t->low, b->low, hi8(i), 12)); - if (!isOfWidth(i, 16)) { - emit(con, addi(t->low, b->low, lo8(hi16(i)), 8)); - if (!isOfWidth(i, 24)) { - emit(con, addi(t->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, t); - } -} - void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { emit(con, SETS(rsb(t->low, a->low, b->low))); @@ -780,14 +761,6 @@ void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Regist } } -void subC(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) { - assert(c, size == BytesPerWord); - - ResolvedPromise promise(- a->value->value()); - Assembler::Constant constant(&promise); - addC(c, size, &constant, b, t); -} - void multiplyR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { emit(con, mul(t->high, a->low, b->high)); @@ -835,8 +808,10 @@ normalize(Context* c, int offset, int index, unsigned scale, ResolvedPromise offsetPromise(offset); Assembler::Constant offsetConstant(&offsetPromise); - addC(c, BytesPerWord, &offsetConstant, - &untranslatedIndex, &normalizedIndex); + Assembler::Register tmp(c->client->acquireTemporary()); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + addR(c, BytesPerWord, &tmp, &untranslatedIndex, &normalizedIndex); + c->client->releaseTemporary(tmp.low); } return normalizedIndex.low; @@ -1035,23 +1010,6 @@ andR(Context* c, unsigned size, Assembler::Register* a, emit(c, and_(dst->low, a->low, b->low)); } -void -andC(Context* con, unsigned size, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) -{ - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - Assembler::Register tmp(con->client->acquireTemporary()); - moveCR(con, size, a, size, &tmp); - andR(con, size, &tmp, b, dst); - con->client->releaseTemporary(tmp.low); - } else { - emit(con, mov(dst->low, 0)); - } -} - void orR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) @@ -1060,29 +1018,6 @@ orR(Context* c, unsigned size, Assembler::Register* a, emit(c, orr(dst->low, a->low, b->low)); } -void -orC(Context* con, unsigned size, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) -{ - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - emit(con, orri(dst->low, b->low, lo8(i))); - if (!isOfWidth(i, 8)) { - emit(con, orri(dst->low, b->low, hi8(i), 12)); - if (!isOfWidth(i, 16)) { - emit(con, orri(dst->low, b->low, lo8(hi16(i)), 8)); - if (!isOfWidth(i, 24)) { - emit(con, orri(dst->low, b->low, hi8(hi16(i)), 4)); - } - } - } - } else { - moveRR(con, size, b, size, dst); - } -} - void xorR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) @@ -1091,21 +1026,6 @@ xorR(Context* con, unsigned size, Assembler::Register* a, emit(con, eor(dst->low, a->low, b->low)); } -void -xorC(Context* con, unsigned size, Assembler::Constant* a, - Assembler::Register* b, Assembler::Register* dst) -{ - assert(con, size == BytesPerWord); - - int32_t i = getValue(a); - if (i) { - Assembler::Register tmp(con->client->acquireTemporary()); - moveCR(con, size, a, size, &tmp); - xorR(con, size, &tmp, b, dst); - con->client->releaseTemporary(tmp.low); - } -} - void moveAR2(Context* c, unsigned srcSize, Assembler::Address* src, unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) @@ -1143,7 +1063,7 @@ compareCR(Context* c, unsigned aSize, Assembler::Constant* a, { assert(c, aSize == 4 and bSize == 4); - if (a->value->resolved() and isInt16(a->value->value())) { + if (a->value->resolved() and isOfWidth(a->value->value(), 8)) { emit(c, cmpi(b->low, a->value->value())); } else { Assembler::Register tmp(c->client->acquireTemporary()); @@ -1538,10 +1458,8 @@ populateTables(ArchitectureContext* c) bo[index(c, Negate, R, R)] = CAST2(negateRR); to[index(c, Add, R)] = CAST3(addR); - to[index(c, Add, C)] = CAST3(addC); to[index(c, Subtract, R)] = CAST3(subR); - to[index(c, Subtract, C)] = CAST3(subC); to[index(c, Multiply, R)] = CAST3(multiplyR); @@ -1554,13 +1472,10 @@ populateTables(ArchitectureContext* c) to[index(c, UnsignedShiftRight, R)] = CAST3(unsignedShiftRightR); to[index(c, UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); - to[index(c, And, C)] = CAST3(andC); to[index(c, And, R)] = CAST3(andR); - to[index(c, Or, C)] = CAST3(orC); to[index(c, Or, R)] = CAST3(orR); - to[index(c, Xor, C)] = CAST3(xorC); to[index(c, Xor, R)] = CAST3(xorR); bro[branchIndex(c, R, R)] = CAST_BRANCH(branchRR); @@ -1830,7 +1745,7 @@ class MyArchitecture: public Assembler::Architecture { virtual void planSource (TernaryOperation op, - unsigned aSize, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned aSize UNUSED, uint8_t* aTypeMask, uint64_t* aRegisterMask, unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, unsigned, bool* thunk) { @@ -1845,11 +1760,9 @@ class MyArchitecture: public Assembler::Architecture { switch (op) { case Add: case Subtract: - if (aSize == 8) { - *aTypeMask = *bTypeMask = (1 << RegisterOperand); - } - break; - + case And: + case Or: + case Xor: case Multiply: *aTypeMask = *bTypeMask = (1 << RegisterOperand); break; From a4914daae4c4f547342841c635ba77d773ae0f46 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 30 Aug 2010 16:55:48 -0600 Subject: [PATCH 014/274] remove unused functions from powerpc.cpp --- src/powerpc.cpp | 56 ------------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index a983f7039f..fbbfb64e38 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1677,62 +1677,6 @@ jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) emit(c, b(0)); } -void -jumpIfEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, beq(0)); -} - -void -jumpIfNotEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bne(0)); -} - -void -jumpIfGreaterC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bgt(0)); -} - -void -jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, bge(0)); -} - -void -jumpIfLessC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, blt(0)); -} - -void -jumpIfLessOrEqualC(Context* c, unsigned size UNUSED, - Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - appendOffsetTask(c, target->value, offset(c), true); - emit(c, ble(0)); -} - void return_(Context* c) { From b26dd4abf1e25127e5bd1542ccba5482145f6ccb Mon Sep 17 00:00:00 2001 From: jet Date: Tue, 31 Aug 2010 18:35:55 -0600 Subject: [PATCH 015/274] All but 6 tests are now passing in JIT mode on ARM. --- src/arm.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 95e07bc9b6..43885f57ab 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -132,6 +132,8 @@ inline int blt(int offset) { return SETCOND(b(offset), LT); } inline int bgt(int offset) { return SETCOND(b(offset), GT); } inline int ble(int offset) { return SETCOND(b(offset), LE); } inline int bge(int offset) { return SETCOND(b(offset), GE); } +inline int blo(int offset) { return SETCOND(b(offset), CC); } +inline int bhs(int offset) { return SETCOND(b(offset), CS); } } const uint64_t MASK_LO32 = 0xffffffff; @@ -699,7 +701,7 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, switch (srcSize) { case 2: emit(c, lsli(dst->low, src->low, 16)); - emit(c, lsri(dst->low, src->low, 16)); + emit(c, lsri(dst->low, dst->low, 16)); break; default: abort(c); @@ -745,7 +747,7 @@ moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - emit(con, SETS(adc(t->low, a->low, b->low))); + emit(con, SETS(add(t->low, a->low, b->low))); emit(con, adc(t->high, a->high, b->high)); } else { emit(con, add(t->low, a->low, b->low)); @@ -1171,7 +1173,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, emit(c, bgt(0)); compareUnsigned(c, 4, al, 4, bl); - conditional(c, blt(0), target); + conditional(c, blo(0), target); break; case JumpIfGreater: @@ -1181,7 +1183,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, emit(c, blt(0)); compareUnsigned(c, 4, al, 4, bl); - conditional(c, bgt(0), target); + conditional(c, bhi(0), target); break; case JumpIfLessOrEqual: @@ -1191,7 +1193,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, emit(c, bgt(0)); compareUnsigned(c, 4, al, 4, bl); - conditional(c, ble(0), target); + conditional(c, bls(0), target); break; case JumpIfGreaterOrEqual: @@ -1201,7 +1203,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, emit(c, blt(0)); compareUnsigned(c, 4, al, 4, bl); - conditional(c, bge(0), target); + conditional(c, bhs(0), target); break; default: @@ -1745,8 +1747,8 @@ class MyArchitecture: public Assembler::Architecture { virtual void planSource (TernaryOperation op, - unsigned aSize UNUSED, uint8_t* aTypeMask, uint64_t* aRegisterMask, - unsigned, uint8_t* bTypeMask, uint64_t* bRegisterMask, + unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, + unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask, unsigned, bool* thunk) { *aTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand); @@ -1758,6 +1760,12 @@ class MyArchitecture: public Assembler::Architecture { *thunk = false; switch (op) { + case ShiftLeft: + case ShiftRight: + case UnsignedShiftRight: + if (bSize == 8) *aTypeMask = *bTypeMask = (1 << RegisterOperand); + break; + case Add: case Subtract: case And: From 4273ff834c1d0f69aa85dd900652f3f43f2e4848 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Sep 2010 10:10:11 -0600 Subject: [PATCH 016/274] remove uncessary parentheses from Enum.java --- classpath/java/lang/Enum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index 3e7fb49282..b1920ac31d 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -34,7 +34,7 @@ public abstract class Enum> implements Comparable { try { Method method = enumType.getMethod("values"); - Enum values[] = (Enum[]) (method.invoke(null)); + Enum values[] = (Enum[]) method.invoke(null); for (Enum value: values) { if (name.equals(value.name)) { return (T) value; From 17c1a552d5fa3c3014e3c845bf9461cc6c2ffe15 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Sep 2010 10:13:52 -0600 Subject: [PATCH 017/274] break each Class, Field, and Method into separate classes In order to facilitate making the VM compatible with multiple class libraries, it's useful to separate the VM-specific representation of these classes from the library implementations. This commit introduces VMClass, VMField, and VMMethod for that purpose. --- classpath/avian/ClassAddendum.java | 1 + classpath/avian/SystemClassLoader.java | 78 +++-- classpath/avian/VMClass.java | 30 ++ classpath/avian/VMField.java | 22 ++ classpath/avian/VMMethod.java | 26 ++ classpath/java/lang/Class.java | 319 +++++++++---------- classpath/java/lang/ClassLoader.java | 5 +- classpath/java/lang/Object.java | 6 +- classpath/java/lang/reflect/Constructor.java | 4 +- classpath/java/lang/reflect/Field.java | 116 +++---- classpath/java/lang/reflect/Method.java | 97 +++--- classpath/java/lang/reflect/Proxy.java | 34 +- classpath/java/util/ResourceBundle.java | 7 +- classpath/java/util/logging/Logger.java | 6 +- src/builtin.cpp | 28 +- src/compile.cpp | 15 +- src/interpret.cpp | 6 +- src/jnienv.cpp | 57 ++-- src/machine.cpp | 2 +- src/machine.h | 23 ++ src/types.def | 13 +- 21 files changed, 547 insertions(+), 348 deletions(-) create mode 100644 classpath/avian/VMClass.java create mode 100644 classpath/avian/VMField.java create mode 100644 classpath/avian/VMMethod.java diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index 6958a7a3ca..c20079df6b 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -11,5 +11,6 @@ package avian; public class ClassAddendum extends Addendum { + public volatile Class class_; public Object[] signers; } diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 2257a9b66e..4ad1e3130a 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -13,6 +13,7 @@ package avian; import static avian.Stream.read1; import static avian.Stream.read2; +import java.lang.reflect.Modifier; import java.lang.reflect.Method; import java.lang.reflect.Field; import java.net.URL; @@ -24,16 +25,26 @@ import java.io.IOException; public class SystemClassLoader extends ClassLoader { private static final int LinkFlag = 1 << 8; - public static native Class defineClass + public static native VMClass defineVMClass (ClassLoader loader, byte[] b, int offset, int length); - protected native Class findClass(String name) throws ClassNotFoundException; + private static native VMClass findVMClass(String name) + throws ClassNotFoundException; - protected native Class reallyFindLoadedClass(String name); + protected Class findClass(String name) throws ClassNotFoundException { + return getClass(findVMClass(name)); + } - private native boolean resourceExists(String name); + private static native VMClass findLoadedVMClass(String name); - private static native Class resolveClass(ClassLoader loader, byte[] spec) + protected Class reallyFindLoadedClass(String name){ + VMClass c = findLoadedVMClass(name); + return c == null ? null : getClass(c); + } + + private static native boolean resourceExists(String name); + + private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) throws ClassNotFoundException; protected URL findResource(String name) { @@ -45,14 +56,14 @@ public class SystemClassLoader extends ClassLoader { return null; } - private static Class loadClass(ClassLoader loader, - byte[] nameBytes, int offset, int length) + private static VMClass loadVMClass(ClassLoader loader, + byte[] nameBytes, int offset, int length) { byte[] spec = new byte[length + 1]; System.arraycopy(nameBytes, offset, spec, 0, length); try { - Class c = resolveClass(loader, spec); + VMClass c = resolveVMClass(loader, spec); if (c == null) { throw new NoClassDefFoundError(); } @@ -110,14 +121,14 @@ public class SystemClassLoader extends ClassLoader { byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); return Enum.valueOf - (loadClass(loader, typeName, 1, typeName.length - 3), + (getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)), new String(name, 0, name.length - 1, false)); } case 'c':{ byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - return loadClass(loader, name, 1, name.length - 3); + return getClass(loadVMClass(loader, name, 1, name.length - 3)); } case '@': @@ -142,7 +153,8 @@ public class SystemClassLoader extends ClassLoader { { byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); Object[] annotation = new Object[(read2(in) + 1) * 2]; - annotation[1] = loadClass(loader, typeName, 1, typeName.length - 3); + annotation[1] = getClass + (loadVMClass(loader, typeName, 1, typeName.length - 3)); for (int i = 2; i < annotation.length; i += 2) { byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); @@ -214,7 +226,7 @@ public class SystemClassLoader extends ClassLoader { return start + 1; } - loadClass(loader, spec, start, end - start); + loadVMClass(loader, spec, start, end - start); return result; } @@ -223,7 +235,35 @@ public class SystemClassLoader extends ClassLoader { private static native void releaseClassLock(); - public static void link(Class c, ClassLoader loader) { + public static Class getClass(VMClass vmClass) { + if (vmClass.addendum == null) { + SystemClassLoader.acquireClassLock(); + try { + if (vmClass.addendum == null) { + vmClass.addendum = new ClassAddendum(); + } + } finally { + SystemClassLoader.releaseClassLock(); + } + } + + if (vmClass.addendum.class_ == null) { + SystemClassLoader.acquireClassLock(); + try { + if (vmClass.addendum.class_ == null) { + vmClass.addendum.class_ = new Class(vmClass); + } + } finally { + SystemClassLoader.releaseClassLock(); + } + } + + return vmClass.addendum.class_; + } + + public static native VMClass getVMClass(Object o); + + public static void link(VMClass c, ClassLoader loader) { acquireClassLock(); try { if ((c.vmFlags & LinkFlag) == 0) { @@ -234,15 +274,15 @@ public class SystemClassLoader extends ClassLoader { parseAnnotationTable(loader, c.addendum); if (c.interfaceTable != null) { - int stride = (c.isInterface() ? 1 : 2); + int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2); for (int i = 0; i < c.interfaceTable.length; i += stride) { - link((Class) c.interfaceTable[i], loader); + link((VMClass) c.interfaceTable[i], loader); } } if (c.methodTable != null) { for (int i = 0; i < c.methodTable.length; ++i) { - Method m = c.methodTable[i]; + VMMethod m = c.methodTable[i]; for (int j = 1; j < m.spec.length;) { j = resolveSpec(loader, m.spec, j); @@ -254,7 +294,7 @@ public class SystemClassLoader extends ClassLoader { if (c.fieldTable != null) { for (int i = 0; i < c.fieldTable.length; ++i) { - Field f = c.fieldTable[i]; + VMField f = c.fieldTable[i]; resolveSpec(loader, f.spec, 0); @@ -269,7 +309,7 @@ public class SystemClassLoader extends ClassLoader { } } - public static void link(Class c) { - link(c, c.getClassLoader()); + public static void link(VMClass c) { + link(c, c.loader); } } diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java new file mode 100644 index 0000000000..da9a64f832 --- /dev/null +++ b/classpath/avian/VMClass.java @@ -0,0 +1,30 @@ +/* Copyright (c) 2008-2010, 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 avian; + +public class VMClass { + public short flags; + public short vmFlags; + public short fixedSize; + public byte arrayElementSize; + public byte arrayDimensions; + public int[] objectMask; + public byte[] name; + public byte[] sourceFile; + public VMClass super_; + public Object[] interfaceTable; + public VMMethod[] virtualTable; + public VMField[] fieldTable; + public VMMethod[] methodTable; + public volatile avian.ClassAddendum addendum; + public Object staticTable; + public ClassLoader loader; +} diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java new file mode 100644 index 0000000000..96c2959f73 --- /dev/null +++ b/classpath/avian/VMField.java @@ -0,0 +1,22 @@ +/* Copyright (c) 2008-2010, 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 avian; + +public class VMField { + public byte vmFlags; + public byte code; + public short flags; + public short offset; + public byte[] name; + public byte[] spec; + public avian.Addendum addendum; + public VMClass class_; +} diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java new file mode 100644 index 0000000000..374b424d84 --- /dev/null +++ b/classpath/avian/VMMethod.java @@ -0,0 +1,26 @@ +/* Copyright (c) 2008-2010, 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 avian; + +public class VMMethod { + public byte vmFlags; + public byte returnCode; + public byte parameterCount; + public byte parameterFootprint; + public short flags; + public short offset; + public int nativeID; + public byte[] name; + public byte[] spec; + public avian.Addendum addendum; + public VMClass class_; + public Object code; +} diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index de7d3b0fc8..4b053d89ca 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -10,7 +10,10 @@ package java.lang; +import avian.VMClass; +import avian.ClassAddendum; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -38,24 +41,13 @@ public final class Class { private static final int PrimitiveFlag = 1 << 5; - private short flags; - public short vmFlags; - private short fixedSize; - private byte arrayElementSize; - private byte arrayDimensions; - private int[] objectMask; - private byte[] name; - private byte[] sourceFile; - public Class super_; - public Object[] interfaceTable; - public Method[] virtualTable; - public Field[] fieldTable; - public Method[] methodTable; - public avian.ClassAddendum addendum; - private Object staticTable; - private ClassLoader loader; + public final VMClass vmClass; - private Class() { } + public Class(VMClass vmClass) { + this.vmClass = vmClass; + } + + public static native VMClass vmClass(Object o); public String toString() { return getName(); @@ -73,26 +65,30 @@ public final class Class } public String getName() { - if (name == null) { - if ((vmFlags & PrimitiveFlag) != 0) { - if (this == primitiveClass('V')) { - name = "void\0".getBytes(); - } else if (this == primitiveClass('Z')) { - name = "boolean\0".getBytes(); - } else if (this == primitiveClass('B')) { - name = "byte\0".getBytes(); - } else if (this == primitiveClass('C')) { - name = "char\0".getBytes(); - } else if (this == primitiveClass('S')) { - name = "short\0".getBytes(); - } else if (this == primitiveClass('I')) { - name = "int\0".getBytes(); - } else if (this == primitiveClass('F')) { - name = "float\0".getBytes(); - } else if (this == primitiveClass('J')) { - name = "long\0".getBytes(); - } else if (this == primitiveClass('D')) { - name = "double\0".getBytes(); + return getName(vmClass); + } + + public static String getName(VMClass c) { + if (c.name == null) { + if ((c.vmFlags & PrimitiveFlag) != 0) { + if (c == primitiveClass('V')) { + c.name = "void\0".getBytes(); + } else if (c == primitiveClass('Z')) { + c.name = "boolean\0".getBytes(); + } else if (c == primitiveClass('B')) { + c.name = "byte\0".getBytes(); + } else if (c == primitiveClass('C')) { + c.name = "char\0".getBytes(); + } else if (c == primitiveClass('S')) { + c.name = "short\0".getBytes(); + } else if (c == primitiveClass('I')) { + c.name = "int\0".getBytes(); + } else if (c == primitiveClass('F')) { + c.name = "float\0".getBytes(); + } else if (c == primitiveClass('J')) { + c.name = "long\0".getBytes(); + } else if (c == primitiveClass('D')) { + c.name = "double\0".getBytes(); } else { throw new AssertionError(); } @@ -102,11 +98,12 @@ public final class Class } return new String - (replace('/', '.', name, 0, name.length - 1), 0, name.length - 1, false); + (replace('/', '.', c.name, 0, c.name.length - 1), 0, c.name.length - 1, + false); } public String getCanonicalName() { - if ((vmFlags & PrimitiveFlag) != 0) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getCanonicalName() + "[]"; @@ -116,7 +113,7 @@ public final class Class } public String getSimpleName() { - if ((vmFlags & PrimitiveFlag) != 0) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0) { return getName(); } else if (isArray()) { return getComponentType().getSimpleName() + "[]"; @@ -131,10 +128,6 @@ public final class Class } } - public Object staticTable() { - return staticTable; - } - public T newInstance() throws IllegalAccessException, InstantiationException { @@ -148,8 +141,7 @@ public final class Class } public static Class forName(String name) throws ClassNotFoundException { - return forName - (name, true, Method.getCaller().getDeclaringClass().getClassLoader()); + return forName(name, true, Method.getCaller().class_.loader); } public static Class forName(String name, boolean initialize, @@ -157,19 +149,19 @@ public final class Class throws ClassNotFoundException { if (loader == null) { - loader = Class.class.loader; + loader = Class.class.vmClass.loader; } Class c = loader.loadClass(name); - avian.SystemClassLoader.link(c, loader); + SystemClassLoader.link(c.vmClass, loader); if (initialize) { - c.initialize(); + initialize(c.vmClass); } return c; } - private static native Class primitiveClass(char name); + private static native VMClass primitiveClass(char name); - private native void initialize(); + private static native void initialize(VMClass vmClass); public static Class forCanonicalName(String name) { return forCanonicalName(null, name); @@ -183,7 +175,7 @@ public final class Class return forName(name.substring(1, name.length() - 1), true, loader); } else { if (name.length() == 1) { - return primitiveClass(name.charAt(0)); + return SystemClassLoader.getClass(primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } @@ -197,39 +189,43 @@ public final class Class if (isArray()) { String n = getName(); if ("[Z".equals(n)) { - return primitiveClass('Z'); + return SystemClassLoader.getClass(primitiveClass('Z')); } else if ("[B".equals(n)) { - return primitiveClass('B'); + return SystemClassLoader.getClass(primitiveClass('B')); } else if ("[S".equals(n)) { - return primitiveClass('S'); + return SystemClassLoader.getClass(primitiveClass('S')); } else if ("[C".equals(n)) { - return primitiveClass('C'); + return SystemClassLoader.getClass(primitiveClass('C')); } else if ("[I".equals(n)) { - return primitiveClass('I'); + return SystemClassLoader.getClass(primitiveClass('I')); } else if ("[F".equals(n)) { - return primitiveClass('F'); + return SystemClassLoader.getClass(primitiveClass('F')); } else if ("[J".equals(n)) { - return primitiveClass('J'); + return SystemClassLoader.getClass(primitiveClass('J')); } else if ("[D".equals(n)) { - return primitiveClass('D'); + return SystemClassLoader.getClass(primitiveClass('D')); } - if (staticTable == null) throw new AssertionError(name); - return (Class) staticTable; + if (vmClass.staticTable == null) throw new AssertionError(); + return SystemClassLoader.getClass((VMClass) vmClass.staticTable); } else { return null; } } - public native boolean isAssignableFrom(Class c); + public static native boolean isAssignableFrom(VMClass a, VMClass b); - private Field findField(String name) { - if (fieldTable != null) { - avian.SystemClassLoader.link(this); + public boolean isAssignableFrom(Class c) { + return isAssignableFrom(vmClass, c.vmClass); + } - for (int i = 0; i < fieldTable.length; ++i) { - if (fieldTable[i].getName().equals(name)) { - return fieldTable[i]; + private static Field findField(VMClass vmClass, String name) { + if (vmClass.fieldTable != null) { + SystemClassLoader.link(vmClass); + + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (Field.getName(vmClass.fieldTable[i]).equals(name)) { + return new Field(vmClass.fieldTable[i]); } } } @@ -237,7 +233,7 @@ public final class Class } public Field getDeclaredField(String name) throws NoSuchFieldException { - Field f = findField(name); + Field f = findField(vmClass, name); if (f == null) { throw new NoSuchFieldException(name); } else { @@ -246,8 +242,8 @@ public final class Class } public Field getField(String name) throws NoSuchFieldException { - for (Class c = this; c != null; c = c.super_) { - Field f = c.findField(name); + for (VMClass c = vmClass; c != null; c = c.super_) { + Field f = findField(c, name); if (f != null) { return f; } @@ -268,19 +264,22 @@ public final class Class } } - private Method findMethod(String name, Class[] parameterTypes) { - if (methodTable != null) { - avian.SystemClassLoader.link(this); + private static Method findMethod(VMClass vmClass, String name, + Class[] parameterTypes) + { + if (vmClass.methodTable != null) { + SystemClassLoader.link(vmClass); if (parameterTypes == null) { parameterTypes = new Class[0]; } - for (int i = 0; i < methodTable.length; ++i) { - if (methodTable[i].getName().equals(name) - && match(parameterTypes, methodTable[i].getParameterTypes())) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (Method.getName(vmClass.methodTable[i]).equals(name) + && match(parameterTypes, + Method.getParameterTypes(vmClass.methodTable[i]))) { - return methodTable[i]; + return new Method(vmClass.methodTable[i]); } } } @@ -293,7 +292,7 @@ public final class Class if (name.startsWith("<")) { throw new NoSuchMethodException(name); } - Method m = findMethod(name, parameterTypes); + Method m = findMethod(vmClass, name, parameterTypes); if (m == null) { throw new NoSuchMethodException(name); } else { @@ -307,8 +306,8 @@ public final class Class if (name.startsWith("<")) { throw new NoSuchMethodException(name); } - for (Class c = this; c != null; c = c.super_) { - Method m = c.findMethod(name, parameterTypes); + for (VMClass c = vmClass; c != null; c = c.super_) { + Method m = findMethod(c, name, parameterTypes); if (m != null) { return m; } @@ -319,7 +318,7 @@ public final class Class public Constructor getConstructor(Class ... parameterTypes) throws NoSuchMethodException { - Method m = findMethod("", parameterTypes); + Method m = findMethod(vmClass, "", parameterTypes); if (m == null) { throw new NoSuchMethodException(); } else { @@ -348,11 +347,12 @@ public final class Class private int countConstructors(boolean publicOnly) { int count = 0; - if (methodTable != null) { - for (int i = 0; i < methodTable.length; ++i) { + if (vmClass.methodTable != null) { + for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((! publicOnly) - || ((methodTable[i].getModifiers() & Modifier.PUBLIC)) != 0) - && methodTable[i].getName().equals("")) + || ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) + != 0) + && Method.getName(vmClass.methodTable[i]).equals("")) { ++ count; } @@ -363,13 +363,13 @@ public final class Class public Constructor[] getDeclaredConstructors() { Constructor[] array = new Constructor[countConstructors(false)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + SystemClassLoader.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (methodTable[i].getName().equals("")) { - array[index++] = new Constructor(methodTable[i]); + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (Method.getName(vmClass.methodTable[i]).equals("")) { + array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } @@ -379,15 +379,15 @@ public final class Class public Constructor[] getConstructors() { Constructor[] array = new Constructor[countConstructors(true)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + SystemClassLoader.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (((methodTable[i].getModifiers() & Modifier.PUBLIC) != 0) - && methodTable[i].getName().equals("")) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) + && Method.getName(vmClass.methodTable[i]).equals("")) { - array[index++] = new Constructor(methodTable[i]); + array[index++] = new Constructor(new Method(vmClass.methodTable[i])); } } } @@ -396,9 +396,11 @@ public final class Class } public Field[] getDeclaredFields() { - if (fieldTable != null) { - Field[] array = new Field[fieldTable.length]; - System.arraycopy(fieldTable, 0, array, 0, fieldTable.length); + if (vmClass.fieldTable != null) { + Field[] array = new Field[vmClass.fieldTable.length]; + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + array[i] = new Field(vmClass.fieldTable[i]); + } return array; } else { return new Field[0]; @@ -407,9 +409,9 @@ public final class Class private int countPublicFields() { int count = 0; - if (fieldTable != null) { - for (int i = 0; i < fieldTable.length; ++i) { - if (((fieldTable[i].getModifiers() & Modifier.PUBLIC)) != 0) { + if (vmClass.fieldTable != null) { + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { ++ count; } } @@ -419,13 +421,13 @@ public final class Class public Field[] getFields() { Field[] array = new Field[countPublicFields()]; - if (fieldTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.fieldTable != null) { + SystemClassLoader.link(vmClass); int ai = 0; - for (int i = 0; i < fieldTable.length; ++i) { - if (((fieldTable[i].getModifiers() & Modifier.PUBLIC)) != 0) { - array[ai++] = fieldTable[i]; + for (int i = 0; i < vmClass.fieldTable.length; ++i) { + if (((vmClass.fieldTable[i].flags & Modifier.PUBLIC)) != 0) { + array[ai++] = new Field(vmClass.fieldTable[i]); } } } @@ -434,11 +436,12 @@ public final class Class private int countMethods(boolean publicOnly) { int count = 0; - if (methodTable != null) { - for (int i = 0; i < methodTable.length; ++i) { + if (vmClass.methodTable != null) { + for (int i = 0; i < vmClass.methodTable.length; ++i) { if (((! publicOnly) - || ((methodTable[i].getModifiers() & Modifier.PUBLIC)) != 0) - && (! methodTable[i].getName().startsWith("<"))) + || ((vmClass.methodTable[i].flags & Modifier.PUBLIC)) + != 0) + && (! Method.getName(vmClass.methodTable[i]).startsWith("<"))) { ++ count; } @@ -449,13 +452,13 @@ public final class Class public Method[] getDeclaredMethods() { Method[] array = new Method[countMethods(false)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + SystemClassLoader.link(vmClass); int ai = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (! methodTable[i].getName().startsWith("<")) { - array[ai++] = methodTable[i]; + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (! Method.getName(vmClass.methodTable[i]).startsWith("<")) { + array[ai++] = new Method(vmClass.methodTable[i]); } } } @@ -465,15 +468,15 @@ public final class Class public Method[] getMethods() { Method[] array = new Method[countMethods(true)]; - if (methodTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.methodTable != null) { + SystemClassLoader.link(vmClass); int index = 0; - for (int i = 0; i < methodTable.length; ++i) { - if (((methodTable[i].getModifiers() & Modifier.PUBLIC) != 0) - && (! methodTable[i].getName().startsWith("<"))) + for (int i = 0; i < vmClass.methodTable.length; ++i) { + if (((vmClass.methodTable[i].flags & Modifier.PUBLIC) != 0) + && (! Method.getName(vmClass.methodTable[i]).startsWith("<"))) { - array[index++] = methodTable[i]; + array[index++] = new Method(vmClass.methodTable[i]); } } } @@ -482,13 +485,14 @@ public final class Class } public Class[] getInterfaces() { - if (interfaceTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.interfaceTable != null) { + SystemClassLoader.link(vmClass); int stride = (isInterface() ? 1 : 2); - Class[] array = new Class[interfaceTable.length / stride]; + Class[] array = new Class[vmClass.interfaceTable.length / stride]; for (int i = 0; i < array.length; ++i) { - array[i] = (Class) interfaceTable[i * stride]; + array[i] = SystemClassLoader.getClass + ((VMClass) vmClass.interfaceTable[i * stride]); } return array; } else { @@ -509,36 +513,41 @@ public final class Class } public ClassLoader getClassLoader() { - return loader; + return vmClass.loader; } public int getModifiers() { - return flags; + return vmClass.flags; } public boolean isInterface() { - return (flags & Modifier.INTERFACE) != 0; + return (vmClass.flags & Modifier.INTERFACE) != 0; } public Class getSuperclass() { - return super_; + return SystemClassLoader.getClass(vmClass.super_); } public boolean isArray() { - return arrayDimensions != 0; + return vmClass.arrayDimensions != 0; + } + + public static boolean isInstance(VMClass c, Object o) { + return o != null && isAssignableFrom(c, SystemClassLoader.getVMClass(o)); } public boolean isInstance(Object o) { - return o != null && isAssignableFrom(o.getClass()); + return isInstance(vmClass, o); } public boolean isPrimitive() { - return (vmFlags & PrimitiveFlag) != 0; + return (vmClass.vmFlags & PrimitiveFlag) != 0; } public URL getResource(String path) { if (! path.startsWith("/")) { - String name = new String(this.name, 0, this.name.length - 1, false); + String name = new String + (vmClass.name, 0, vmClass.name.length - 1, false); int index = name.lastIndexOf('/'); if (index >= 0) { path = name.substring(0, index) + "/" + path; @@ -573,11 +582,11 @@ public final class Class } public Object[] getSigners() { - return addendum == null ? null : addendum.signers; + return vmClass.addendum.signers; } public Package getPackage() { - if ((vmFlags & PrimitiveFlag) != 0 || isArray()) { + if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) { return null; } else { String name = getCanonicalName(); @@ -597,25 +606,25 @@ public final class Class return getAnnotation(class_) != null; } - private Annotation getAnnotation(Object[] a) { + private static Annotation getAnnotation(VMClass c, Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (loader, new Class[] { (Class) a[1] }, + (c.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { - avian.SystemClassLoader.link(c, c.loader); + SystemClassLoader.link(c, c.loader); Object[] table = (Object[]) c.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { - return (T) c.getAnnotation(a); + return (T) getAnnotation(c, a); } } } @@ -624,13 +633,13 @@ public final class Class } public Annotation[] getDeclaredAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - avian.SystemClassLoader.link(this); + if (vmClass.addendum.annotationTable != null) { + SystemClassLoader.link(vmClass); - Object[] table = (Object[]) addendum.annotationTable; + Object[] table = (Object[]) vmClass.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { - array[i] = getAnnotation((Object[]) table[i]); + array[i] = getAnnotation(vmClass, (Object[]) table[i]); } return array; } else { @@ -640,7 +649,7 @@ public final class Class private int countAnnotations() { int count = 0; - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { count += ((Object[]) c.addendum.annotationTable).length; } @@ -651,11 +660,11 @@ public final class Class public Annotation[] getAnnotations() { Annotation[] array = new Annotation[countMethods(true)]; int i = 0; - for (Class c = this; c != null; c = c.super_) { + for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { Object[] table = (Object[]) c.addendum.annotationTable; for (int j = 0; j < table.length; ++j) { - array[i++] = getAnnotation((Object[]) table[j]); + array[i++] = getAnnotation(vmClass, (Object[]) table[j]); } } } @@ -692,14 +701,4 @@ public final class Class p.add(new AllPermission()); return new ProtectionDomain(null, p); } - - // for GNU Classpath compatibility: - void setSigners(Object[] signers) { - if (signers != null && signers.length > 0) { - if (addendum == null) { - addendum = new avian.ClassAddendum(); - } - addendum.signers = signers; - } - } } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 3cc052ac48..c63d971440 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -46,7 +46,8 @@ public abstract class ClassLoader { throw new IndexOutOfBoundsException(); } - return avian.SystemClassLoader.defineClass(this, b, offset, length); + return avian.SystemClassLoader.getClass + (avian.SystemClassLoader.defineVMClass(this, b, offset, length)); } protected Class findClass(String name) throws ClassNotFoundException { @@ -87,7 +88,7 @@ public abstract class ClassLoader { } protected void resolveClass(Class c) { - avian.SystemClassLoader.link(c, this); + avian.SystemClassLoader.link(c.vmClass, this); } private ClassLoader getParent() { diff --git a/classpath/java/lang/Object.java b/classpath/java/lang/Object.java index bfd2da9eea..24e6d2dd4b 100644 --- a/classpath/java/lang/Object.java +++ b/classpath/java/lang/Object.java @@ -27,7 +27,11 @@ public class Object { protected void finalize() throws Throwable { } - public native final Class getClass(); + public final Class getClass() { + return avian.SystemClassLoader.getClass(getVMClass(this)); + } + + private static native avian.VMClass getVMClass(Object o); public native int hashCode(); diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index ac42178373..324797fe9a 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -78,13 +78,13 @@ public class Constructor extends AccessibleObject return method.getGenericParameterTypes(); } - private static native T make(Class c); + private static native Object make(avian.VMClass c); public T newInstance(Object ... arguments) throws InvocationTargetException, InstantiationException, IllegalAccessException { - T v = make(method.getDeclaringClass()); + T v = (T) make(method.getDeclaringClass().vmClass); method.invoke(v, arguments); return v; } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 0d015b8254..504b85d402 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -10,7 +10,9 @@ package java.lang.reflect; +import avian.VMField; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; import java.lang.annotation.Annotation; @@ -26,81 +28,90 @@ public class Field extends AccessibleObject { private static final int BooleanField = 8; private static final int ObjectField = 9; - private byte vmFlags; - private byte code; - private short flags; - private short offset; - private byte[] name; - public byte[] spec; - public avian.Addendum addendum; - private Class class_; + private final VMField vmField; + private boolean accessible = true; - private Field() { } + public Field(VMField vmField) { + this.vmField = vmField; + } public boolean isAccessible() { - return (vmFlags & Accessible) != 0; + return accessible; } public void setAccessible(boolean v) { - if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; + accessible = v; } public Class getDeclaringClass() { - return class_; + return SystemClassLoader.getClass(vmField.class_); } public int getModifiers() { - return flags; + return vmField.flags; } public String getName() { - return new String(name, 0, name.length - 1, false); + return getName(vmField); + } + + public static String getName(VMField vmField) { + return new String(vmField.name, 0, vmField.name.length - 1, false); } public Class getType() { - return Class.forCanonicalName(class_.getClassLoader(), - new String(spec, 0, spec.length - 1, false)); + return Class.forCanonicalName + (vmField.class_.loader, + new String(vmField.spec, 0, vmField.spec.length - 1, false)); } public Object get(Object instance) throws IllegalAccessException { Object target; - if ((flags & Modifier.STATIC) != 0) { - target = class_.staticTable(); - } else if (class_.isInstance(instance)) { + if ((vmField.flags & Modifier.STATIC) != 0) { + target = vmField.class_.staticTable; + } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } - switch (code) { + switch (vmField.code) { case ByteField: - return Byte.valueOf((byte) getPrimitive(target, code, offset)); + return Byte.valueOf + ((byte) getPrimitive(target, vmField.code, vmField.offset)); case BooleanField: - return Boolean.valueOf(getPrimitive(target, code, offset) != 0); + return Boolean.valueOf + (getPrimitive(target, vmField.code, vmField.offset) != 0); case CharField: - return Character.valueOf((char) getPrimitive(target, code, offset)); + return Character.valueOf + ((char) getPrimitive(target, vmField.code, vmField.offset)); case ShortField: - return Short.valueOf((short) getPrimitive(target, code, offset)); + return Short.valueOf + ((short) getPrimitive(target, vmField.code, vmField.offset)); case IntField: - return Integer.valueOf((int) getPrimitive(target, code, offset)); + return Integer.valueOf + ((int) getPrimitive(target, vmField.code, vmField.offset)); case LongField: - return Long.valueOf((int) getPrimitive(target, code, offset)); + return Long.valueOf + ((int) getPrimitive(target, vmField.code, vmField.offset)); case FloatField: return Float.valueOf - (Float.intBitsToFloat((int) getPrimitive(target, code, offset))); + (Float.intBitsToFloat + ((int) getPrimitive(target, vmField.code, vmField.offset))); case DoubleField: return Double.valueOf - (Double.longBitsToDouble(getPrimitive(target, code, offset))); + (Double.longBitsToDouble + (getPrimitive(target, vmField.code, vmField.offset))); case ObjectField: - return getObject(target, offset); + return getObject(target, vmField.offset); default: throw new Error(); @@ -143,56 +154,58 @@ public class Field extends AccessibleObject { throws IllegalAccessException { Object target; - if ((flags & Modifier.STATIC) != 0) { - target = class_.staticTable(); - } else if (class_.isInstance(instance)) { + if ((vmField.flags & Modifier.STATIC) != 0) { + target = vmField.class_.staticTable; + } else if (Class.isInstance(vmField.class_, instance)) { target = instance; } else { throw new IllegalArgumentException(); } - switch (code) { + switch (vmField.code) { case ByteField: - setPrimitive(target, code, offset, (Byte) value); + setPrimitive(target, vmField.code, vmField.offset, (Byte) value); break; case BooleanField: - setPrimitive(target, code, offset, ((Boolean) value) ? 1 : 0); + setPrimitive + (target, vmField.code, vmField.offset, ((Boolean) value) ? 1 : 0); break; case CharField: - setPrimitive(target, code, offset, (Character) value); + setPrimitive(target, vmField.code, vmField.offset, (Character) value); break; case ShortField: - setPrimitive(target, code, offset, (Short) value); + setPrimitive(target, vmField.code, vmField.offset, (Short) value); break; case IntField: - setPrimitive(target, code, offset, (Integer) value); + setPrimitive(target, vmField.code, vmField.offset, (Integer) value); break; case LongField: - setPrimitive(target, code, offset, (Long) value); + setPrimitive(target, vmField.code, vmField.offset, (Long) value); break; case FloatField: - setPrimitive(target, code, offset, + setPrimitive(target, vmField.code, vmField.offset, Float.floatToRawIntBits((Float) value)); break; case DoubleField: - setPrimitive(target, code, offset, + setPrimitive(target, vmField.code, vmField.offset, Double.doubleToRawLongBits((Double) value)); break; case ObjectField: if (value == null || getType().isInstance(value)) { - setObject(target, offset, value); + setObject(target, vmField.offset, value); } else { throw new IllegalArgumentException - ("needed " + getType() + ", got " + value.getClass().getName() + - " when setting " + class_.getName() + "." + getName()); + ("needed " + getType() + ", got " + + Class.getName(Class.vmClass(target)) + + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; @@ -204,15 +217,15 @@ public class Field extends AccessibleObject { private Annotation getAnnotation(Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (class_.getClassLoader(), new Class[] { (Class) a[1] }, + (vmField.class_.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmField.addendum.annotationTable != null) { + Object[] table = (Object[]) vmField.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -224,8 +237,8 @@ public class Field extends AccessibleObject { } public Annotation[] getAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmField.addendum.annotationTable != null) { + Object[] table = (Object[]) vmField.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); @@ -255,9 +268,4 @@ public class Field extends AccessibleObject { private static native void setObject (Object instance, int offset, Object value); - - public static class Addendum { - public Object pool; - public Object annotationTable; - } } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 8a8e383cfb..2db5698eac 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -10,53 +10,54 @@ package java.lang.reflect; +import avian.VMMethod; import avian.AnnotationInvocationHandler; +import avian.SystemClassLoader; import java.lang.annotation.Annotation; public class Method extends AccessibleObject implements Member, GenericDeclaration { - private byte vmFlags; - private byte returnCode; - public byte parameterCount; - public byte parameterFootprint; - private short flags; - private short offset; - private int nativeID; - private byte[] name; - public byte[] spec; - public avian.Addendum addendum; - private Class class_; - private Object code; - private long compiled; + private final VMMethod vmMethod; + private boolean accessible; - private Method() { } + public Method(VMMethod vmMethod) { + this.vmMethod = vmMethod; + } public boolean isAccessible() { - return (vmFlags & Accessible) != 0; + return accessible; } public void setAccessible(boolean v) { - if (v) vmFlags |= Accessible; else vmFlags &= ~Accessible; + accessible = v; } - public static native Method getCaller(); + public static native VMMethod getCaller(); public Class getDeclaringClass() { - return class_; + return SystemClassLoader.getClass(vmMethod.class_); } public int getModifiers() { - return flags; + return vmMethod.flags; } public String getName() { - return new String(name, 0, name.length - 1, false); + return getName(vmMethod); } - String getSpec() { - return new String(spec, 0, spec.length - 1, false); + public static String getName(VMMethod vmMethod) { + return new String(vmMethod.name, 0, vmMethod.name.length - 1, false); + } + + private String getSpec() { + return getSpec(vmMethod); + } + + public static String getSpec(VMMethod vmMethod) { + return new String(vmMethod.spec, 0, vmMethod.spec.length - 1, false); } private static int next(char c, String s, int start) { @@ -67,12 +68,17 @@ public class Method extends AccessibleObject } public Class[] getParameterTypes() { - int count = parameterCount; + return getParameterTypes(vmMethod); + } + + public static Class[] getParameterTypes(VMMethod vmMethod) { + int count = vmMethod.parameterCount; Class[] types = new Class[count]; int index = 0; - String spec = new String(this.spec, 1, this.spec.length - 1, false); + String spec = new String + (vmMethod.spec, 1, vmMethod.spec.length - 1, false); try { for (int i = 0; i < spec.length(); ++i) { @@ -83,7 +89,7 @@ public class Method extends AccessibleObject int start = i + 1; i = next(';', spec, start); String name = spec.substring(start, i).replace('/', '.'); - types[index++] = Class.forName(name, true, class_.getClassLoader()); + types[index++] = Class.forName(name, true, vmMethod.class_.loader); } else if (c == '[') { int start = i; while (spec.charAt(i) == '[') ++i; @@ -92,16 +98,16 @@ public class Method extends AccessibleObject i = next(';', spec, i + 1); String name = spec.substring(start, i).replace('/', '.'); types[index++] = Class.forName - (name, true, class_.getClassLoader()); + (name, true, vmMethod.class_.loader); } else { String name = spec.substring(start, i + 1); types[index++] = Class.forCanonicalName - (class_.getClassLoader(), name); + (vmMethod.class_.loader, name); } } else { String name = spec.substring(i, i + 1); types[index++] = Class.forCanonicalName - (class_.getClassLoader(), name); + (vmMethod.class_.loader, name); } } } catch (ClassNotFoundException e) { @@ -114,38 +120,43 @@ public class Method extends AccessibleObject public Object invoke(Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException { - if ((flags & Modifier.STATIC) != 0 || class_.isInstance(instance)) { - if ((flags & Modifier.STATIC) != 0) { + if ((vmMethod.flags & Modifier.STATIC) != 0 + || Class.isInstance(vmMethod.class_, instance)) + { + if ((vmMethod.flags & Modifier.STATIC) != 0) { instance = null; } if (arguments == null) { - if (parameterCount > 0) { + if (vmMethod.parameterCount > 0) { throw new NullPointerException(); } arguments = new Object[0]; } - if (arguments.length == parameterCount) { - return invoke(this, instance, arguments); + if (arguments.length == vmMethod.parameterCount) { + return invoke(vmMethod, instance, arguments); } else { throw new ArrayIndexOutOfBoundsException(); } } else { +// System.out.println +// (getDeclaringClass() + "." + getName() + " flags: " + vmMethod.flags + " vm flags: " + vmMethod.vmFlags + " return code: " + vmMethod.returnCode); throw new IllegalArgumentException(); } } - private static native Object invoke(Method method, Object instance, + private static native Object invoke(VMMethod method, Object instance, Object ... arguments) throws InvocationTargetException, IllegalAccessException; public Class getReturnType() { - for (int i = 0; i < spec.length - 1; ++i) { - if (spec[i] == ')') { + for (int i = 0; i < vmMethod.spec.length - 1; ++i) { + if (vmMethod.spec[i] == ')') { return Class.forCanonicalName - (class_.getClassLoader(), - new String(spec, i + 1, spec.length - i - 2, false)); + (vmMethod.class_.loader, + new String + (vmMethod.spec, i + 1, vmMethod.spec.length - i - 2, false)); } } throw new RuntimeException(); @@ -154,15 +165,15 @@ public class Method extends AccessibleObject private Annotation getAnnotation(Object[] a) { if (a[0] == null) { a[0] = Proxy.newProxyInstance - (class_.getClassLoader(), new Class[] { (Class) a[1] }, + (vmMethod.class_.loader, new Class[] { (Class) a[1] }, new AnnotationInvocationHandler(a)); } return (Annotation) a[0]; } public T getAnnotation(Class class_) { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmMethod.addendum.annotationTable != null) { + Object[] table = (Object[]) vmMethod.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { Object[] a = (Object[]) table[i]; if (a[1] == class_) { @@ -174,8 +185,8 @@ public class Method extends AccessibleObject } public Annotation[] getAnnotations() { - if (addendum != null && addendum.annotationTable != null) { - Object[] table = (Object[]) addendum.annotationTable; + if (vmMethod.addendum.annotationTable != null) { + Object[] table = (Object[]) vmMethod.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; for (int i = 0; i < table.length; ++i) { array[i] = getAnnotation((Object[]) table[i]); diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index aca0351217..15119c8d30 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -45,12 +45,14 @@ public class Proxy { private static final int getfield = 0xb4; private static final int iload = 0x15; private static final int invokeinterface = 0xb9; + private static final int invokespecial = 0xb7; private static final int invokestatic = 0xb8; private static final int invokevirtual = 0xb6; private static final int ireturn = 0xac; private static final int ldc_w = 0x13; private static final int lload = 0x16; private static final int lreturn = 0xad; + private static final int new_ = 0xbb; private static final int pop = 0x57; private static final int putfield = 0xb5; private static final int return_ = 0xb1; @@ -172,15 +174,26 @@ public class Proxy { write1(out, aload_0); + write1(out, new_); + write2(out, poolAddClass(pool, "java/lang/reflect/Method") + 1); + write1(out, dup); write1(out, ldc_w); write2(out, poolAddClass(pool, className) + 1); write1(out, getfield); write2(out, poolAddFieldRef (pool, "java/lang/Class", - "methodTable", "[Ljava/lang/reflect/Method;") + 1); + "vmClass", "Lavian/VMClass;") + 1); + write1(out, getfield); + write2(out, poolAddFieldRef + (pool, "avian/VMClass", + "methodTable", "[Lavian/VMMethod;") + 1); write1(out, ldc_w); write2(out, poolAddInteger(pool, index) + 1); write1(out, aaload); + write1(out, invokespecial); + write2(out, poolAddMethodRef + (pool, "java/lang/reflect/Method", + "", "(Lavian/VMMethod;)V") + 1); write1(out, ldc_w); write2(out, poolAddInteger(pool, parameterCount) + 1); @@ -434,22 +447,22 @@ public class Proxy { interfaceIndexes[i] = poolAddClass(pool, interfaces[i].getName()); } - Map virtualMap = new HashMap(); + Map virtualMap = new HashMap(); for (Class c: interfaces) { - Method[] ivtable = c.virtualTable; + avian.VMMethod[] ivtable = c.vmClass.virtualTable; if (ivtable != null) { - for (Method m: ivtable) { - virtualMap.put(m.getName() + m.getSpec(), m); + for (avian.VMMethod m: ivtable) { + virtualMap.put(Method.getName(m) + Method.getSpec(m), m); } } } MethodData[] methodTable = new MethodData[virtualMap.size() + 1]; { int i = 0; - for (Method m: virtualMap.values()) { + for (avian.VMMethod m: virtualMap.values()) { methodTable[i] = new MethodData - (poolAddUtf8(pool, m.getName()), - poolAddUtf8(pool, m.getSpec()), + (poolAddUtf8(pool, Method.getName(m)), + poolAddUtf8(pool, Method.getSpec(m)), makeInvokeCode(pool, name, m.spec, m.parameterCount, m.parameterFootprint, i)); ++ i; @@ -501,8 +514,9 @@ public class Proxy { write2(out, 0); // attribute count byte[] classData = out.toByteArray(); - return avian.SystemClassLoader.defineClass - (loader, classData, 0, classData.length); + return avian.SystemClassLoader.getClass + (avian.SystemClassLoader.defineVMClass + (loader, classData, 0, classData.length)); } public static Object newProxyInstance(ClassLoader loader, diff --git a/classpath/java/util/ResourceBundle.java b/classpath/java/util/ResourceBundle.java index 97bde9b80c..4dc52443f6 100644 --- a/classpath/java/util/ResourceBundle.java +++ b/classpath/java/util/ResourceBundle.java @@ -94,13 +94,12 @@ public abstract class ResourceBundle { } public static ResourceBundle getBundle(String name, Locale locale) { - return getBundle(name, locale, - Method.getCaller().getDeclaringClass().getClassLoader()); + return getBundle(name, locale, Method.getCaller().class_.loader); } public static ResourceBundle getBundle(String name) { - return getBundle(name, Locale.getDefault(), - Method.getCaller().getDeclaringClass().getClassLoader()); + return getBundle + (name, Locale.getDefault(), Method.getCaller().class_.loader); } public Object getObject(String key) { diff --git a/classpath/java/util/logging/Logger.java b/classpath/java/util/logging/Logger.java index d06a7bb00a..ed2a8ce4d6 100644 --- a/classpath/java/util/logging/Logger.java +++ b/classpath/java/util/logging/Logger.java @@ -107,15 +107,15 @@ public class Logger { return logger.getLevel(); } - private void log(Level level, Method caller, String message, + private void log(Level level, avian.VMMethod caller, String message, Throwable exception) { if (level.intValue() < getEffectiveLevel().intValue()) { return; } LogRecord r = new LogRecord - (name, caller == null ? "" : caller.getName(), level, message, - exception); + (name, caller == null ? "" : Method.getName(caller), level, + message, exception); publish(r); } diff --git a/src/builtin.cpp b/src/builtin.cpp index d8ee84cc2c..13333a1fb6 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -97,12 +97,12 @@ Avian_java_lang_Object_toString } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_getClass +Avian_java_lang_Object_getVMClass (Thread* t, object, uintptr_t* arguments) { - object this_ = reinterpret_cast(arguments[0]); + object o = reinterpret_cast(arguments[0]); - return reinterpret_cast(objectClass(t, this_)); + return reinterpret_cast(objectClass(t, o)); } extern "C" JNIEXPORT void JNICALL @@ -183,7 +183,15 @@ Avian_avian_SystemClassLoader_releaseClassLock } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_defineClass +Avian_avian_SystemClassLoader_getVMClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (objectClass(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_SystemClassLoader_defineVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); @@ -214,25 +222,25 @@ Avian_avian_SystemClassLoader_defineClass } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_reallyFindLoadedClass +Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) { - object name = reinterpret_cast(arguments[1]); + object name = reinterpret_cast(arguments[0]); return search(t, name, findLoadedSystemClass, true); } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_findClass +Avian_avian_SystemClassLoader_findVMClass (Thread* t, object, uintptr_t* arguments) { - object name = reinterpret_cast(arguments[1]); + object name = reinterpret_cast(arguments[0]); return search(t, name, resolveSystemClass, true); } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_resolveClass +Avian_avian_SystemClassLoader_resolveVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); @@ -245,7 +253,7 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_resourceExists (Thread* t, object, uintptr_t* arguments) { - object name = reinterpret_cast(arguments[1]); + object name = reinterpret_cast(arguments[0]); if (LIKELY(name)) { RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); diff --git a/src/compile.cpp b/src/compile.cpp index e5d7a7df2d..a35fa98905 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4370,7 +4370,11 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; - frame->pushObject(frame->append(class_)); + frame->pushObject(frame->append(getJClass(t, class_))); + } else if (objectClass(t, v) + == arrayBody(t, t->m->types, Machine::ClassType)) + { + frame->pushObject(frame->append(getJClass(t, v))); } else { frame->pushObject(frame->append(v)); } @@ -6160,9 +6164,6 @@ invokeNativeSlow(MyThread* t, object method) { PROTECT(t, method); - object class_ = methodClass(t, method); - PROTECT(t, class_); - unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { ++ footprint; @@ -6181,9 +6182,13 @@ invokeNativeSlow(MyThread* t, object method) + t->arch->frameFooterSize() + t->arch->frameReturnAddressSize(); + object jclass = 0; + PROTECT(t, jclass); + if (methodFlags(t, method) & ACC_STATIC) { + jclass = getJClass(t, methodClass(t, method)); RUNTIME_ARRAY_BODY(args)[argOffset++] - = reinterpret_cast(&class_); + = reinterpret_cast(&jclass); } else { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(sp++); diff --git a/src/interpret.cpp b/src/interpret.cpp index e63613cb54..28754a0a3b 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -2224,7 +2224,11 @@ interpret(Thread* t) (t, frameMethod(t, frame), index - 1); if (UNLIKELY(exception)) goto throw_; - pushObject(t, class_); + pushObject(t, getJClass(t, class_)); + } else if (objectClass(t, v) + == arrayBody(t, t->m->types, Machine::ClassType)) + { + pushObject(t, getJClass(t, v)); } else { pushObject(t, v); } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 4404014ef9..a7b7b0cb6f 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -248,7 +248,9 @@ FindClass(Thread* t, const char* name) object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); - return makeLocalReference(t, resolveClass(t, t->m->loader, n)); + object c = resolveClass(t, t->m->loader, n); + + return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); } jint JNICALL @@ -270,7 +272,7 @@ ThrowNew(Thread* t, jclass c, const char* message) object trace = makeTrace(t); PROTECT(t, trace); - t->exception = make(t, *c); + t->exception = make(t, jclassVmClass(t, *c)); set(t, t->exception, ThrowableMessage, m); set(t, t->exception, ThrowableTrace, trace); @@ -316,7 +318,7 @@ GetObjectClass(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); - return makeLocalReference(t, objectClass(t, *o)); + return makeLocalReference(t, getJClass(t, objectClass(t, *o))); } jboolean JNICALL @@ -324,7 +326,7 @@ IsInstanceOf(Thread* t, jobject o, jclass c) { ENTER(t, Thread::ActiveState); - return instanceOf(t, *c, *o); + return instanceOf(t, jclassVmClass(t, *c), *o); } object @@ -334,7 +336,7 @@ findMethod(Thread* t, jclass c, const char* name, const char* spec) PROTECT(t, n); object s = makeByteArray(t, "%s", spec); - return vm::findMethod(t, *c, n, s); + return vm::findMethod(t, jclassVmClass(t, *c), n, s); } jint @@ -395,7 +397,7 @@ NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) { ENTER(t, Thread::ActiveState); - object o = make(t, *c); + object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); t->m->processor->invokeList(t, getMethod(t, m), o, true, a); @@ -875,7 +877,7 @@ GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { ENTER(t, Thread::ActiveState); - object field = resolveField(t, *c, name, spec); + object field = resolveField(t, jclassVmClass(t, *c), name, spec); if (UNLIKELY(t->exception)) return 0; return fieldOffset(t, field); @@ -886,7 +888,7 @@ GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { ENTER(t, Thread::ActiveState); - object field = resolveField(t, *c, name, spec); + object field = resolveField(t, jclassVmClass(t, *c), name, spec); if (UNLIKELY(t->exception)) return 0; return fieldOffset(t, field); @@ -1041,7 +1043,8 @@ GetStaticObjectField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return makeLocalReference(t, cast(classStaticTable(t, *c), field)); + return makeLocalReference + (t, cast(classStaticTable(t, jclassVmClass(t, *c)), field)); } jboolean JNICALL @@ -1049,7 +1052,7 @@ GetStaticBooleanField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jbyte JNICALL @@ -1057,7 +1060,7 @@ GetStaticByteField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jchar JNICALL @@ -1065,7 +1068,7 @@ GetStaticCharField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jshort JNICALL @@ -1073,7 +1076,7 @@ GetStaticShortField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jint JNICALL @@ -1081,7 +1084,7 @@ GetStaticIntField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jlong JNICALL @@ -1089,7 +1092,7 @@ GetStaticLongField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jfloat JNICALL @@ -1097,7 +1100,7 @@ GetStaticFloatField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } jdouble JNICALL @@ -1105,7 +1108,7 @@ GetStaticDoubleField(Thread* t, jclass c, jfieldID field) { ENTER(t, Thread::ActiveState); - return cast(classStaticTable(t, *c), field); + return cast(classStaticTable(t, jclassVmClass(t, *c)), field); } void JNICALL @@ -1121,7 +1124,7 @@ SetStaticBooleanField(Thread* t, jclass c, jfieldID field, jboolean v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1129,7 +1132,7 @@ SetStaticByteField(Thread* t, jclass c, jfieldID field, jbyte v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1137,7 +1140,7 @@ SetStaticCharField(Thread* t, jclass c, jfieldID field, jchar v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1145,7 +1148,7 @@ SetStaticShortField(Thread* t, jclass c, jfieldID field, jshort v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1153,7 +1156,7 @@ SetStaticIntField(Thread* t, jclass c, jfieldID field, jint v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1161,7 +1164,7 @@ SetStaticLongField(Thread* t, jclass c, jfieldID field, jlong v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1169,7 +1172,7 @@ SetStaticFloatField(Thread* t, jclass c, jfieldID field, jfloat v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } void JNICALL @@ -1177,7 +1180,7 @@ SetStaticDoubleField(Thread* t, jclass c, jfieldID field, jdouble v) { ENTER(t, Thread::ActiveState); - cast(classStaticTable(t, *c), field) = v; + cast(classStaticTable(t, jclassVmClass(t, *c)), field) = v; } jobject JNICALL @@ -1248,7 +1251,9 @@ NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) { ENTER(t, Thread::ActiveState); - object a = makeObjectArray(t, classLoader(t, *class_), *class_, length); + object a = makeObjectArray + (t, classLoader(t, jclassVmClass(t, *class_)), jclassVmClass(t, *class_), + length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); diff --git a/src/machine.cpp b/src/machine.cpp index 01b766de93..0b4ddcb461 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1627,7 +1627,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body, 0); + object addendum = makeClassAddendum(t, pool, body, 0, 0); set(t, class_, ClassAddendum, addendum); } else { diff --git a/src/machine.h b/src/machine.h index 4bdfccfc24..b406a455ca 100644 --- a/src/machine.h +++ b/src/machine.h @@ -3000,6 +3000,29 @@ resolveMethod(Thread* t, object method, unsigned index) (t, classLoader(t, methodClass(t, method)), method, index); } +inline object +getJClass(Thread* t, object c) +{ + if (classAddendum(t, c) == 0) { + ACQUIRE(t, t->m->classLock); + + object addendum = makeClassAddendum(t, 0, 0, 0, 0); + + set(t, c, ClassAddendum, addendum); + } + + object jclass = classAddendumClass(t, classAddendum(t, c)); + if (jclass == 0) { + ACQUIRE(t, t->m->classLock); + + jclass = makeJclass(t, c); + + set(t, classAddendum(t, c), ClassAddendumClass, jclass); + } + + return jclass; +} + void dumpHeap(Thread* t, FILE* out); diff --git a/src/types.def b/src/types.def index 184df800a0..143252e352 100644 --- a/src/types.def +++ b/src/types.def @@ -1,8 +1,10 @@ (type jobject java/lang/Object) -(type class java/lang/Class +(type class avian/VMClass (array void* vtable)) +(type jclass java/lang/Class) + (type singleton (array uintptr_t body)) @@ -11,13 +13,10 @@ (type systemClassLoader avian/SystemClassLoader) -(type accessibleObject java/lang/reflect/AccessibleObject) +(type field avian/VMField) -(type field java/lang/reflect/Field) - -(type method java/lang/reflect/Method) - -(type proxy java/lang/reflect/Proxy) +(type method avian/VMMethod + (intptr_t compiled)) (type addendum avian/Addendum) From a20d7e028b13788ce1abc9f7ed469115c665e19d Mon Sep 17 00:00:00 2001 From: jet Date: Thu, 2 Sep 2010 16:09:01 -0600 Subject: [PATCH 018/274] Longs.java test now progresses further before failure. --- src/arm.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 43885f57ab..5551042148 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -88,10 +88,10 @@ inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, ro inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); } -inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdLo, RdHi, Rs, Rm); } -inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdLo, RdHi, Rs, Rm); } -inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdLo, RdHi, Rs, Rm); } -inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdLo, RdHi, Rs, Rm); } +inline int umull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 4, 0, RdHi, RdLo, Rs, Rm); } +inline int umlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 5, 0, RdHi, RdLo, Rs, Rm); } +inline int smull(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 6, 0, RdHi, RdLo, Rs, Rm); } +inline int smlal(int RdLo, int RdHi, int Rm, int Rs) { return MULTIPLY(AL, 7, 0, RdHi, RdLo, Rs, Rm); } inline int ldr(int Rd, int Rn, int Rm, int W=0) { return XFER(AL, 1, 1, 0, W, 1, Rn, Rd, 0, 0, Rm); } inline int ldri(int Rd, int Rn, int imm, int W=0) { return XFERI(AL, 1, calcU(imm), 0, W, 1, Rn, Rd, abs(imm)); } inline int ldrb(int Rd, int Rn, int Rm) { return XFER(AL, 1, 1, 1, 0, 1, Rn, Rd, 0, 0, Rm); } @@ -479,8 +479,8 @@ void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler: emit(con, lsl(tmpLo, b->high, tmpHi)); emit(con, orr(t->low, t->low, tmpLo)); emit(con, SETS(addi(tmpHi, a->low, -32))); - emit(con, asr(tmpLo, b->high, tmpHi)); - emit(con, SETCOND(::b(8), LE)); + emit(con, SETS(asr(tmpLo, b->high, tmpHi))); + emit(con, ble(4)); emit(con, orri(t->low, tmpLo, 0)); emit(con, asr(t->high, b->high, a->low)); freeTemp(con, tmpHi); freeTemp(con, tmpLo); @@ -765,9 +765,20 @@ void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Regist void multiplyR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - emit(con, mul(t->high, a->low, b->high)); - emit(con, mla(t->high, a->high, b->low, t->high)); - emit(con, smlal(t->low, t->high, a->low, b->low)); + bool useTemporaries = b->low == t->low; + int tmpLow = useTemporaries ? con->client->acquireTemporary() : t->low; + int tmpHigh = useTemporaries ? con->client->acquireTemporary() : t->high; + + emit(con, umull(tmpLow, tmpHigh, a->low, b->low)); + emit(con, mla(tmpHigh, a->low, b->high, tmpHigh)); + emit(con, mla(tmpHigh, a->high, b->low, tmpHigh)); + + if (useTemporaries) { + emit(con, mov(t->low, tmpLow)); + emit(con, mov(t->high, tmpHigh)); + con->client->releaseTemporary(tmpLow); + con->client->releaseTemporary(tmpHigh); + } } else { emit(con, mul(t->low, a->low, b->low)); } From bd01784249bb5b0e4f500b560ea71727f841c9b9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Sep 2010 00:18:19 +0100 Subject: [PATCH 019/274] save return address in arm.cpp's MyAssembler::saveFrame This is necessary to allow safe stack unwinding (e.g. for exception handling and garbage collection) from native code. --- src/arm.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/arm.cpp b/src/arm.cpp index 5551042148..7bb209f16e 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1856,6 +1856,11 @@ class MyAssembler: public Assembler { } virtual void saveFrame(unsigned stackOffset, unsigned) { + Register returnAddress(LinkRegister); + Memory returnAddressDst + (StackRegister, arch_->returnAddressOffset() * BytesPerWord); + moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); + Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); From e7a48c0fa2832b1f45933a140742e9b0c282ec9b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 2 Sep 2010 17:28:20 -0600 Subject: [PATCH 020/274] save return address in powerpc.cpp's MyAssembler::saveFrame We've been getting away with not doing this so far since our Java calling convention matches the native calling convention concerning where the return address is saved, so when our thunk calls native code it gets saved for us automatically. However, there was still the danger that a thread would interrupt another thread after the stack pointer was saved to the thread field but before the native code was called and try to get a stack trace, at which point it would try to find the return address relative to that stack pointer and find garbage instead. This commit ensures that we save the return address before saving the stack pointer to avoid such a situation. --- src/powerpc.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index fbbfb64e38..eb1d5ef33b 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2142,6 +2142,12 @@ class MyAssembler: public Assembler { } virtual void saveFrame(unsigned stackOffset, unsigned) { + Register returnAddress(0); + emit(&c, mflr(returnAddress.low)); + + Memory returnAddressDst(StackRegister, 8); + moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); + Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); From dd0a696932ab7c6eb004235958efe42cccc9c0ea Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Sep 2010 18:32:22 +0100 Subject: [PATCH 021/274] handle logical AND with a constant in a single instruction where possible --- src/arm.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/arm.cpp b/src/arm.cpp index 7bb209f16e..2014c9fd40 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -82,6 +82,7 @@ inline int subi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x2, 0, R inline int rsbi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x3, 0, Rn, Rd, rot, imm); } inline int addi(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x4, 0, Rn, Rd, rot, imm); } inline int adci(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0x5, 0, Rn, Rd, rot, imm); } +inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, Rn, Rd, rot, imm); } inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } @@ -1023,6 +1024,54 @@ andR(Context* c, unsigned size, Assembler::Register* a, emit(c, and_(dst->low, a->low, b->low)); } +void +andC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + int64_t v = a->value->value(); + + if (size == 8) { + ResolvedPromise high((v >> 32) & 0xFFFFFFFF); + Assembler::Constant ah(&high); + + ResolvedPromise low(v & 0xFFFFFFFF); + Assembler::Constant al(&low); + + Assembler::Register bh(b->high); + Assembler::Register dh(dst->high); + + andC(c, 4, &al, b, dst); + andC(c, 4, &ah, &bh, &dh); + } else { + uint32_t v32 = static_cast(v); + if (v32 != 0xFFFFFFFF) { + if ((v32 & 0xFFFFFF00) == 0xFFFFFF00) { + emit(c, bici(dst->low, b->low, (~(v32 & 0xFF)) & 0xFF)); + } else if ((v32 & 0xFFFFFF00) == 0) { + emit(c, andi(dst->low, b->low, v32 & 0xFF)); + } else { + // todo: there are other cases we can handle in one + // instruction + + bool useTemporary = b->low == dst->low; + Assembler::Register tmp(dst->low); + if (useTemporary) { + tmp.low = c->client->acquireTemporary(); + } + + moveCR(c, 4, a, 4, &tmp); + andR(c, 4, b, &tmp, dst); + + if (useTemporary) { + c->client->releaseTemporary(tmp.low); + } + } + } else { + moveRR(c, size, b, size, dst); + } + } +} + void orR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) @@ -1486,6 +1535,7 @@ populateTables(ArchitectureContext* c) to[index(c, UnsignedShiftRight, C)] = CAST3(unsignedShiftRightC); to[index(c, And, R)] = CAST3(andR); + to[index(c, And, C)] = CAST3(andC); to[index(c, Or, R)] = CAST3(orR); @@ -1779,7 +1829,6 @@ class MyArchitecture: public Assembler::Architecture { case Add: case Subtract: - case And: case Or: case Xor: case Multiply: From a1f5456451ef2caf3990a5aa5257566a87634eae Mon Sep 17 00:00:00 2001 From: jet Date: Fri, 3 Sep 2010 12:52:11 -0600 Subject: [PATCH 022/274] All tests passing for ARM port in JIT mode. --- src/arm.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 2014c9fd40..6fca682e8f 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -86,6 +86,7 @@ inline int bici(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xe, 0, R inline int cmpi(int Rn, int imm, int rot=0) { return DATAI(AL, 0xa, 1, Rn, 0, rot, imm); } inline int orri(int Rd, int Rn, int imm, int rot=0) { return DATAI(AL, 0xc, 0, Rn, Rd, rot, imm); } inline int movi(int Rd, int imm, int rot=0) { return DATAI(AL, 0xd, 0, 0, Rd, rot, imm); } +inline int orrsh(int Rd, int Rn, int Rm, int Rs, int Sh) { return DATAS(AL, 0xc, 0, Rn, Rd, Rs, Sh, Rm); } inline int movsh(int Rd, int Rm, int Rs, int Sh) { return DATAS(AL, 0xd, 0, 0, Rd, Rs, Sh, Rm); } inline int mul(int Rd, int Rm, int Rs) { return MULTIPLY(AL, 0, 0, Rd, 0, Rs, Rm); } inline int mla(int Rd, int Rm, int Rs, int Rn) { return MULTIPLY(AL, 1, 0, Rd, Rn, Rs, Rm); } @@ -452,17 +453,18 @@ inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - int tmpHi = newTemp(con), tmpLo = newTemp(con); - emit(con, SETS(rsbi(tmpHi, a->low, 32))); - emit(con, lsl(t->high, b->high, a->low)); - emit(con, lsr(tmpLo, b->low, tmpHi)); - emit(con, orr(t->high, t->high, tmpLo)); - emit(con, addi(tmpHi, a->low, -32)); - emit(con, lsl(tmpLo, b->low, tmpHi)); - emit(con, orr(t->high, t->high, tmpLo)); - freeTemp(con, tmpHi); freeTemp(con, tmpLo); + int tmp1 = newTemp(con), tmp2 = newTemp(con); + emit(con, lsl(tmp1, b->high, a->low)); + emit(con, rsbi(tmp2, a->low, 32)); + emit(con, orrsh(tmp1, tmp1, b->low, tmp2, LSR)); + emit(con, SETS(subi(t->high, a->low, 32))); + emit(con, SETCOND(mov(t->high, tmp1), MI)); + emit(con, SETCOND(lsl(t->high, b->low, t->high), PL)); + emit(con, lsl(t->low, b->low, a->low)); + freeTemp(con, tmp1); freeTemp(con, tmp2); + } else { + emit(con, lsl(t->low, b->low, a->low)); } - emit(con, lsl(t->low, b->low, a->low)); } void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Assembler::Register* b, Assembler::Register* t) @@ -474,17 +476,15 @@ void shiftLeftC(Context* con, unsigned size UNUSED, Assembler::Constant* a, Asse void shiftRightR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { - int tmpHi = newTemp(con), tmpLo = newTemp(con); - emit(con, SETS(rsbi(tmpHi, a->low, 32))); - emit(con, lsr(t->low, b->low, a->low)); - emit(con, lsl(tmpLo, b->high, tmpHi)); - emit(con, orr(t->low, t->low, tmpLo)); - emit(con, SETS(addi(tmpHi, a->low, -32))); - emit(con, SETS(asr(tmpLo, b->high, tmpHi))); - emit(con, ble(4)); - emit(con, orri(t->low, tmpLo, 0)); + int tmp1 = newTemp(con), tmp2 = newTemp(con); + emit(con, lsr(tmp1, b->low, a->low)); + emit(con, rsbi(tmp2, a->low, 32)); + emit(con, orrsh(tmp1, tmp1, b->high, tmp2, LSL)); + emit(con, SETS(subi(t->low, a->low, 32))); + emit(con, SETCOND(mov(t->low, tmp1), MI)); + emit(con, SETCOND(asr(t->low, b->high, t->low), PL)); emit(con, asr(t->high, b->high, a->low)); - freeTemp(con, tmpHi); freeTemp(con, tmpLo); + freeTemp(con, tmp1); freeTemp(con, tmp2); } else { emit(con, asr(t->low, b->low, a->low)); } @@ -1076,7 +1076,7 @@ void orR(Context* c, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* dst) { - if (size == 8) orr(dst->high, a->high, b->high); + if (size == 8) emit(c, orr(dst->high, a->high, b->high)); emit(c, orr(dst->low, a->low, b->low)); } From a26eb1b2b9726e92dd4ec80c367b5d4ac8afeace Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Sun, 5 Sep 2010 09:07:18 -0600 Subject: [PATCH 023/274] Fix missing flush in PrintStream --- classpath/java/io/PrintStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index d4aa83eceb..520b676a29 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -31,6 +31,7 @@ public class PrintStream extends OutputStream { public synchronized void print(String s) { try { out.write(s.getBytes()); + if (autoFlush) flush(); } catch (IOException e) { } } From 250a77dc13d586fb7bae6a80a695ed6545898645 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 6 Sep 2010 11:16:27 -0600 Subject: [PATCH 024/274] handle empty strings properly in Pattern.split We were incorrectly returning an empty array when the input was empty, whereas we ought to return an array containing a single empty string. When the pattern to match was empty, we went into a loop to create an infinite list of empty strings, only to crash once we've run out of memory. This commit addresses both problems. --- classpath/java/util/regex/Pattern.java | 21 ++++++++++--- test/Strings.java | 43 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index a3ec90c676..2a48591592 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.java @@ -115,23 +115,34 @@ public class Pattern { List list = new LinkedList(); int index = 0; int trailing = 0; - while (index < input.length() && list.size() < limit) { - int i = indexOf(input, pattern, index); + int patternLength = pattern.length(); + while (index < input.length() && list.size() < limit - 1) { + int i; + if (patternLength == 0) { + if (list.size() == 0) { + i = 0; + } else { + i = index + 1; + } + } else { + i = indexOf(input, pattern, index); + } + if (i >= 0) { - if (i == index) { + if (patternLength != 0 && i == index) { ++ trailing; } else { trailing = 0; } list.add(input.subSequence(index, i)); - index = i + pattern.length(); + index = i + patternLength; } else { break; } } - if (strip && index == input.length()) { + if (strip && index > 0 && index == input.length()) { ++ trailing; } else { trailing = 0; diff --git a/test/Strings.java b/test/Strings.java index 9927ba2983..6b993bcb4f 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -3,6 +3,24 @@ public class Strings { if (! v) throw new RuntimeException(); } + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + private static boolean arraysEqual(Object[] a, Object[] b) { + if (a.length != b.length) { + return false; + } + + for (int i = 0; i < a.length; ++i) { + if (! equal(a[i], b[i])) { + return false; + } + } + + return true; + } + public static void main(String[] args) { expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, 116, 101, 46, 110, 97, 116, 46, 98, 117, @@ -13,6 +31,31 @@ public class Strings { expect(months.split("\u00ae").length == 3); expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); + expect(arraysEqual + ("xyz".split("", 0), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 1), new String[] { "xyz" })); + expect(arraysEqual + ("xyz".split("", 2), new String[] { "", "xyz" })); + expect(arraysEqual + ("xyz".split("", 3), new String[] { "", "x", "yz" })); + expect(arraysEqual + ("xyz".split("", 4), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })); + + expect(arraysEqual("".split("xyz", 0), new String[] { "" })); + expect(arraysEqual("".split("xyz", 1), new String[] { "" })); + expect(arraysEqual("".split("xyz", -1), new String[] { "" })); + + expect(arraysEqual("".split("", 0), new String[] { "" })); + expect(arraysEqual("".split("", 1), new String[] { "" })); + expect(arraysEqual("".split("", -1), new String[] { "" })); + expect("foo_foofoo__foo".replaceAll("_", "__") .equals("foo__foofoo____foo")); From cddea7187d1886a521abbec719691d4fda8135d8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Sep 2010 15:05:29 -0600 Subject: [PATCH 025/274] preliminary support for using OpenJDK's class library Whereas the GNU Classpath port used the strategy of patching Classpath with core classes from Avian so as to minimize changes to the VM, this port uses the opposite strategy: abstract and isolate classpath-specific features in the VM similar to how we abstract away platform-specific features in system.h. This allows us to use an unmodified copy of OpenJDK's class library, including its core classes and augmented by a few VM-specific classes in the "avian" package. --- classpath/avian/Addendum.java | 2 +- classpath/avian/Classes.java | 268 +++ classpath/avian/FieldAddendum.java | 13 + classpath/avian/MethodAddendum.java | 15 + classpath/avian/SystemClassLoader.java | 276 +-- classpath/avian/VMField.java | 2 +- classpath/avian/VMMethod.java | 2 +- classpath/avian/resource/Handler.java | 4 + classpath/java-lang.cpp | 1 - classpath/java/lang/Class.java | 60 +- classpath/java/lang/OutOfMemoryError.java | 2 +- classpath/java/lang/StackTraceElement.java | 2 +- classpath/java/lang/ref/ReferenceQueue.java | 10 +- classpath/java/lang/reflect/Field.java | 2 +- makefile | 203 +- openjdk.ld | 288 +++ src/builtin.cpp | 767 +------ src/classpath-avian.cpp | 601 ++++++ src/classpath-common.h | 271 +++ src/classpath-openjdk.cpp | 2096 +++++++++++++++++++ src/common.h | 10 + src/compile-x86.S | 2 +- src/compile.cpp | 110 +- src/continuations-x86.S | 8 +- src/interpret.cpp | 190 +- src/jnienv.cpp | 159 +- src/machine.cpp | 261 ++- src/machine.h | 289 ++- src/posix.cpp | 2 +- src/process.cpp | 7 +- src/process.h | 2 +- src/processor.h | 4 + src/system.h | 2 +- src/type-generator.cpp | 69 +- src/types.def | 49 +- test/test.sh | 6 +- 36 files changed, 4452 insertions(+), 1603 deletions(-) create mode 100644 classpath/avian/Classes.java create mode 100644 classpath/avian/FieldAddendum.java create mode 100644 classpath/avian/MethodAddendum.java create mode 100644 openjdk.ld create mode 100644 src/classpath-avian.cpp create mode 100644 src/classpath-common.h create mode 100644 src/classpath-openjdk.cpp diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index 80f3df6f8e..433b81e3c3 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -12,5 +12,5 @@ package avian; public class Addendum { public Object pool; - public Object annotationTable; + public Object annotationTable; } diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java new file mode 100644 index 0000000000..f312690606 --- /dev/null +++ b/classpath/avian/Classes.java @@ -0,0 +1,268 @@ +/* Copyright (c) 2010, 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 avian; + +import static avian.Stream.read1; +import static avian.Stream.read2; + +import java.lang.reflect.Modifier; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class Classes { + private static final int LinkFlag = 1 << 8; + + public static native VMClass defineVMClass + (ClassLoader loader, byte[] b, int offset, int length); + + public static native VMClass vmClass(Object o); + + public static native VMClass primitiveClass(char name); + + public static native void initialize(VMClass vmClass); + + public static native boolean isAssignableFrom(VMClass a, VMClass b); + + public static native VMClass getVMClass(Object o); + + private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) + throws ClassNotFoundException; + + private static VMClass loadVMClass(ClassLoader loader, + byte[] nameBytes, int offset, int length) + { + byte[] spec = new byte[length + 1]; + System.arraycopy(nameBytes, offset, spec, 0, length); + + try { + VMClass c = resolveVMClass(loader, spec); + if (c == null) { + throw new NoClassDefFoundError(); + } + return c; + } catch (ClassNotFoundException e) { + NoClassDefFoundError error = new NoClassDefFoundError + (new String(nameBytes, offset, length, false)); + error.initCause(e); + throw error; + } + } + + private static Object parseAnnotationValue(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + switch (read1(in)) { + case 'Z': + return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0); + + case 'B': + return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1)); + + case 'C': + return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1)); + + case 'S': + return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1)); + + case 'I': + return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1)); + + case 'F': + return Float.valueOf + (Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1))); + + case 'J': { + return Long.valueOf(Singleton.getLong(pool, read2(in) - 1)); + } + + case 'D': { + return Double.valueOf + (Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1))); + } + + case 's': { + byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return new String(data, 0, data.length - 1, false); + } + + case 'e': { + byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return Enum.valueOf + (getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)), + new String(name, 0, name.length - 1, false)); + } + + case 'c':{ + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + + return getClass(loadVMClass(loader, name, 1, name.length - 3)); + } + + case '@': + return parseAnnotation(loader, pool, in); + + case '[': { + Object[] array = new Object[read2(in)]; + for (int i = 0; i < array.length; ++i) { + array[i] = parseAnnotationValue(loader, pool, in); + } + return array; + } + + default: throw new AssertionError(); + } + } + + private static Object[] parseAnnotation(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); + Object[] annotation = new Object[(read2(in) + 1) * 2]; + annotation[1] = getClass + (loadVMClass(loader, typeName, 1, typeName.length - 3)); + + for (int i = 2; i < annotation.length; i += 2) { + byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); + annotation[i] = new String(name, 0, name.length - 1, false); + annotation[i + 1] = parseAnnotationValue(loader, pool, in); + } + + return annotation; + } + + private static Object[] parseAnnotationTable(ClassLoader loader, + Object pool, + InputStream in) + throws IOException + { + Object[] table = new Object[read2(in)]; + for (int i = 0; i < table.length; ++i) { + table[i] = parseAnnotation(loader, pool, in); + } + return table; + } + + private static void parseAnnotationTable(ClassLoader loader, + Addendum addendum) + { + if (addendum != null && addendum.annotationTable instanceof byte[]) { + try { + addendum.annotationTable = parseAnnotationTable + (loader, addendum.pool, new ByteArrayInputStream + ((byte[]) addendum.annotationTable)); + } catch (IOException e) { + AssertionError error = new AssertionError(); + error.initCause(e); + throw error; + } + } + } + + private static int resolveSpec(ClassLoader loader, byte[] spec, int start) { + int result; + int end; + switch (spec[start]) { + case 'L': + ++ start; + end = start; + while (spec[end] != ';') ++ end; + result = end + 1; + break; + + case '[': + end = start + 1; + while (spec[end] == '[') ++ end; + switch (spec[end]) { + case 'L': + ++ end; + while (spec[end] != ';') ++ end; + ++ end; + break; + + default: + ++ end; + } + result = end; + break; + + default: + return start + 1; + } + + loadVMClass(loader, spec, start, end - start); + + return result; + } + + public static void link(VMClass c, ClassLoader loader) { + acquireClassLock(); + try { + if ((c.vmFlags & LinkFlag) == 0) { + if (c.super_ != null) { + link(c.super_, loader); + } + + parseAnnotationTable(loader, c.addendum); + + if (c.interfaceTable != null) { + int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2); + for (int i = 0; i < c.interfaceTable.length; i += stride) { + link((VMClass) c.interfaceTable[i], loader); + } + } + + if (c.methodTable != null) { + for (int i = 0; i < c.methodTable.length; ++i) { + VMMethod m = c.methodTable[i]; + + for (int j = 1; j < m.spec.length;) { + j = resolveSpec(loader, m.spec, j); + } + + parseAnnotationTable(loader, m.addendum); + } + } + + if (c.fieldTable != null) { + for (int i = 0; i < c.fieldTable.length; ++i) { + VMField f = c.fieldTable[i]; + + resolveSpec(loader, f.spec, 0); + + parseAnnotationTable(loader, f.addendum); + } + } + + c.vmFlags |= LinkFlag; + } + } finally { + releaseClassLock(); + } + } + + public static void link(VMClass c) { + link(c, c.loader); + } + + private static native void acquireClassLock(); + + private static native void releaseClassLock(); +} diff --git a/classpath/avian/FieldAddendum.java b/classpath/avian/FieldAddendum.java new file mode 100644 index 0000000000..5e97e8a95b --- /dev/null +++ b/classpath/avian/FieldAddendum.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2010, 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 avian; + +public class FieldAddendum extends Addendum { } diff --git a/classpath/avian/MethodAddendum.java b/classpath/avian/MethodAddendum.java new file mode 100644 index 0000000000..a2e40a5261 --- /dev/null +++ b/classpath/avian/MethodAddendum.java @@ -0,0 +1,15 @@ +/* Copyright (c) 2009-2010, 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 avian; + +public class MethodAddendum extends Addendum { + public Object exceptionTable; +} diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 4ad1e3130a..d93be28114 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -10,24 +10,10 @@ package avian; -import static avian.Stream.read1; -import static avian.Stream.read2; - -import java.lang.reflect.Modifier; -import java.lang.reflect.Method; -import java.lang.reflect.Field; import java.net.URL; import java.net.MalformedURLException; -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; public class SystemClassLoader extends ClassLoader { - private static final int LinkFlag = 1 << 8; - - public static native VMClass defineVMClass - (ClassLoader loader, byte[] b, int offset, int length); - private static native VMClass findVMClass(String name) throws ClassNotFoundException; @@ -35,6 +21,8 @@ public class SystemClassLoader extends ClassLoader { return getClass(findVMClass(name)); } + public static native Class getClass(VMClass vmClass); + private static native VMClass findLoadedVMClass(String name); protected Class reallyFindLoadedClass(String name){ @@ -44,9 +32,6 @@ public class SystemClassLoader extends ClassLoader { private static native boolean resourceExists(String name); - private static native VMClass resolveVMClass(ClassLoader loader, byte[] spec) - throws ClassNotFoundException; - protected URL findResource(String name) { if (resourceExists(name)) { try { @@ -55,261 +40,4 @@ public class SystemClassLoader extends ClassLoader { } return null; } - - private static VMClass loadVMClass(ClassLoader loader, - byte[] nameBytes, int offset, int length) - { - byte[] spec = new byte[length + 1]; - System.arraycopy(nameBytes, offset, spec, 0, length); - - try { - VMClass c = resolveVMClass(loader, spec); - if (c == null) { - throw new NoClassDefFoundError(); - } - return c; - } catch (ClassNotFoundException e) { - NoClassDefFoundError error = new NoClassDefFoundError - (new String(nameBytes, offset, length, false)); - error.initCause(e); - throw error; - } - } - - private static Object parseAnnotationValue(ClassLoader loader, - Object pool, - InputStream in) - throws IOException - { - switch (read1(in)) { - case 'Z': - return Boolean.valueOf(Singleton.getInt(pool, read2(in) - 1) != 0); - - case 'B': - return Byte.valueOf((byte) Singleton.getInt(pool, read2(in) - 1)); - - case 'C': - return Character.valueOf((char) Singleton.getInt(pool, read2(in) - 1)); - - case 'S': - return Short.valueOf((short) Singleton.getInt(pool, read2(in) - 1)); - - case 'I': - return Integer.valueOf(Singleton.getInt(pool, read2(in) - 1)); - - case 'F': - return Float.valueOf - (Float.intBitsToFloat(Singleton.getInt(pool, read2(in) - 1))); - - case 'J': { - return Long.valueOf(Singleton.getLong(pool, read2(in) - 1)); - } - - case 'D': { - return Double.valueOf - (Double.longBitsToDouble(Singleton.getLong(pool, read2(in) - 1))); - } - - case 's': { - byte[] data = (byte[]) Singleton.getObject(pool, read2(in) - 1); - - return new String(data, 0, data.length - 1, false); - } - - case 'e': { - byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); - byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - - return Enum.valueOf - (getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)), - new String(name, 0, name.length - 1, false)); - } - - case 'c':{ - byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - - return getClass(loadVMClass(loader, name, 1, name.length - 3)); - } - - case '@': - return parseAnnotation(loader, pool, in); - - case '[': { - Object[] array = new Object[read2(in)]; - for (int i = 0; i < array.length; ++i) { - array[i] = parseAnnotationValue(loader, pool, in); - } - return array; - } - - default: throw new AssertionError(); - } - } - - private static Object[] parseAnnotation(ClassLoader loader, - Object pool, - InputStream in) - throws IOException - { - byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); - Object[] annotation = new Object[(read2(in) + 1) * 2]; - annotation[1] = getClass - (loadVMClass(loader, typeName, 1, typeName.length - 3)); - - for (int i = 2; i < annotation.length; i += 2) { - byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - annotation[i] = new String(name, 0, name.length - 1, false); - annotation[i + 1] = parseAnnotationValue(loader, pool, in); - } - - return annotation; - } - - private static Object[] parseAnnotationTable(ClassLoader loader, - Object pool, - InputStream in) - throws IOException - { - Object[] table = new Object[read2(in)]; - for (int i = 0; i < table.length; ++i) { - table[i] = parseAnnotation(loader, pool, in); - } - return table; - } - - private static void parseAnnotationTable(ClassLoader loader, - Addendum addendum) - { - if (addendum != null && addendum.annotationTable instanceof byte[]) { - try { - addendum.annotationTable = parseAnnotationTable - (loader, addendum.pool, new ByteArrayInputStream - ((byte[]) addendum.annotationTable)); - } catch (IOException e) { - AssertionError error = new AssertionError(); - error.initCause(e); - throw error; - } - - addendum.pool = null; - } - } - - private static int resolveSpec(ClassLoader loader, byte[] spec, int start) { - int result; - int end; - switch (spec[start]) { - case 'L': - ++ start; - end = start; - while (spec[end] != ';') ++ end; - result = end + 1; - break; - - case '[': - end = start + 1; - while (spec[end] == '[') ++ end; - switch (spec[end]) { - case 'L': - ++ end; - while (spec[end] != ';') ++ end; - ++ end; - break; - - default: - ++ end; - } - result = end; - break; - - default: - return start + 1; - } - - loadVMClass(loader, spec, start, end - start); - - return result; - } - - private static native void acquireClassLock(); - - private static native void releaseClassLock(); - - public static Class getClass(VMClass vmClass) { - if (vmClass.addendum == null) { - SystemClassLoader.acquireClassLock(); - try { - if (vmClass.addendum == null) { - vmClass.addendum = new ClassAddendum(); - } - } finally { - SystemClassLoader.releaseClassLock(); - } - } - - if (vmClass.addendum.class_ == null) { - SystemClassLoader.acquireClassLock(); - try { - if (vmClass.addendum.class_ == null) { - vmClass.addendum.class_ = new Class(vmClass); - } - } finally { - SystemClassLoader.releaseClassLock(); - } - } - - return vmClass.addendum.class_; - } - - public static native VMClass getVMClass(Object o); - - public static void link(VMClass c, ClassLoader loader) { - acquireClassLock(); - try { - if ((c.vmFlags & LinkFlag) == 0) { - if (c.super_ != null) { - link(c.super_, loader); - } - - parseAnnotationTable(loader, c.addendum); - - if (c.interfaceTable != null) { - int stride = ((c.flags & Modifier.INTERFACE) != 0 ? 1 : 2); - for (int i = 0; i < c.interfaceTable.length; i += stride) { - link((VMClass) c.interfaceTable[i], loader); - } - } - - if (c.methodTable != null) { - for (int i = 0; i < c.methodTable.length; ++i) { - VMMethod m = c.methodTable[i]; - - for (int j = 1; j < m.spec.length;) { - j = resolveSpec(loader, m.spec, j); - } - - parseAnnotationTable(loader, m.addendum); - } - } - - if (c.fieldTable != null) { - for (int i = 0; i < c.fieldTable.length; ++i) { - VMField f = c.fieldTable[i]; - - resolveSpec(loader, f.spec, 0); - - parseAnnotationTable(loader, f.addendum); - } - } - - c.vmFlags |= LinkFlag; - } - } finally { - releaseClassLock(); - } - } - - public static void link(VMClass c) { - link(c, c.loader); - } } diff --git a/classpath/avian/VMField.java b/classpath/avian/VMField.java index 96c2959f73..699a68e5f8 100644 --- a/classpath/avian/VMField.java +++ b/classpath/avian/VMField.java @@ -17,6 +17,6 @@ public class VMField { public short offset; public byte[] name; public byte[] spec; - public avian.Addendum addendum; + public FieldAddendum addendum; public VMClass class_; } diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java index 374b424d84..5a6754c034 100644 --- a/classpath/avian/VMMethod.java +++ b/classpath/avian/VMMethod.java @@ -20,7 +20,7 @@ public class VMMethod { public int nativeID; public byte[] name; public byte[] spec; - public avian.Addendum addendum; + public MethodAddendum addendum; public VMClass class_; public Object code; } diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/resource/Handler.java index a10e575a85..38d0312ff4 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/resource/Handler.java @@ -34,6 +34,10 @@ public class Handler extends URLStreamHandler { public InputStream getInputStream() throws IOException { return new ResourceInputStream(url.getFile()); } + + public void connect() { + // ignore + } } private static class ResourceInputStream extends InputStream { diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 8303e3e4e1..720b364729 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -11,7 +11,6 @@ #include "math.h" #include "stdlib.h" #include "time.h" -#include "time.h" #include "string.h" #include "stdio.h" #include "jni.h" diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 4b053d89ca..6d234f3765 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -47,8 +47,6 @@ public final class Class this.vmClass = vmClass; } - public static native VMClass vmClass(Object o); - public String toString() { return getName(); } @@ -71,23 +69,23 @@ public final class Class public static String getName(VMClass c) { if (c.name == null) { if ((c.vmFlags & PrimitiveFlag) != 0) { - if (c == primitiveClass('V')) { + if (c == SystemClassLoader.primitiveClass('V')) { c.name = "void\0".getBytes(); - } else if (c == primitiveClass('Z')) { + } else if (c == SystemClassLoader.primitiveClass('Z')) { c.name = "boolean\0".getBytes(); - } else if (c == primitiveClass('B')) { + } else if (c == SystemClassLoader.primitiveClass('B')) { c.name = "byte\0".getBytes(); - } else if (c == primitiveClass('C')) { + } else if (c == SystemClassLoader.primitiveClass('C')) { c.name = "char\0".getBytes(); - } else if (c == primitiveClass('S')) { + } else if (c == SystemClassLoader.primitiveClass('S')) { c.name = "short\0".getBytes(); - } else if (c == primitiveClass('I')) { + } else if (c == SystemClassLoader.primitiveClass('I')) { c.name = "int\0".getBytes(); - } else if (c == primitiveClass('F')) { + } else if (c == SystemClassLoader.primitiveClass('F')) { c.name = "float\0".getBytes(); - } else if (c == primitiveClass('J')) { + } else if (c == SystemClassLoader.primitiveClass('J')) { c.name = "long\0".getBytes(); - } else if (c == primitiveClass('D')) { + } else if (c == SystemClassLoader.primitiveClass('D')) { c.name = "double\0".getBytes(); } else { throw new AssertionError(); @@ -154,15 +152,11 @@ public final class Class Class c = loader.loadClass(name); SystemClassLoader.link(c.vmClass, loader); if (initialize) { - initialize(c.vmClass); + SystemClassLoader.initialize(c.vmClass); } return c; } - private static native VMClass primitiveClass(char name); - - private static native void initialize(VMClass vmClass); - public static Class forCanonicalName(String name) { return forCanonicalName(null, name); } @@ -175,7 +169,8 @@ public final class Class return forName(name.substring(1, name.length() - 1), true, loader); } else { if (name.length() == 1) { - return SystemClassLoader.getClass(primitiveClass(name.charAt(0))); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } @@ -189,21 +184,29 @@ public final class Class if (isArray()) { String n = getName(); if ("[Z".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('Z')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('Z')); } else if ("[B".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('B')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('B')); } else if ("[S".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('S')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('S')); } else if ("[C".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('C')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('C')); } else if ("[I".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('I')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('I')); } else if ("[F".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('F')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('F')); } else if ("[J".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('J')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('J')); } else if ("[D".equals(n)) { - return SystemClassLoader.getClass(primitiveClass('D')); + return SystemClassLoader.getClass + (SystemClassLoader.primitiveClass('D')); } if (vmClass.staticTable == null) throw new AssertionError(); @@ -213,10 +216,8 @@ public final class Class } } - public static native boolean isAssignableFrom(VMClass a, VMClass b); - public boolean isAssignableFrom(Class c) { - return isAssignableFrom(vmClass, c.vmClass); + return SystemClassLoader.isAssignableFrom(vmClass, c.vmClass); } private static Field findField(VMClass vmClass, String name) { @@ -533,7 +534,8 @@ public final class Class } public static boolean isInstance(VMClass c, Object o) { - return o != null && isAssignableFrom(c, SystemClassLoader.getVMClass(o)); + return o != null && SystemClassLoader.isAssignableFrom + (c, SystemClassLoader.getVMClass(o)); } public boolean isInstance(Object o) { diff --git a/classpath/java/lang/OutOfMemoryError.java b/classpath/java/lang/OutOfMemoryError.java index 50848a9ae4..29cae34d73 100644 --- a/classpath/java/lang/OutOfMemoryError.java +++ b/classpath/java/lang/OutOfMemoryError.java @@ -10,7 +10,7 @@ package java.lang; -public class OutOfMemoryError extends Error { +public class OutOfMemoryError extends VirtualMachineError { public OutOfMemoryError(String message) { super(message, null); } diff --git a/classpath/java/lang/StackTraceElement.java b/classpath/java/lang/StackTraceElement.java index db16585c73..9b933412e9 100644 --- a/classpath/java/lang/StackTraceElement.java +++ b/classpath/java/lang/StackTraceElement.java @@ -56,7 +56,7 @@ public class StackTraceElement { } public String getClassName() { - return class_.replace('/', '.'); + return class_; } public String getMethodName() { diff --git a/classpath/java/lang/ref/ReferenceQueue.java b/classpath/java/lang/ref/ReferenceQueue.java index 46eb1f26ce..068a5bfbc1 100644 --- a/classpath/java/lang/ref/ReferenceQueue.java +++ b/classpath/java/lang/ref/ReferenceQueue.java @@ -12,13 +12,12 @@ package java.lang.ref; public class ReferenceQueue { private Reference front; - private Reference rear; public Reference poll() { Reference r = front; if (front != null) { if (front == front.jNext) { - front = rear = null; + front = null; } else { front = front.jNext; } @@ -27,12 +26,11 @@ public class ReferenceQueue { } void add(Reference r) { - r.jNext = r; if (front == null) { - front = r; + r.jNext = r; } else { - rear.jNext = r; + r.jNext = front; } - rear = r; + front = r; } } diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 504b85d402..b8f9ac0cf3 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -204,7 +204,7 @@ public class Field extends AccessibleObject { } else { throw new IllegalArgumentException ("needed " + getType() + ", got " - + Class.getName(Class.vmClass(target)) + + + Class.getName(SystemClassLoader.vmClass(target)) + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; diff --git a/makefile b/makefile index f0dcab31a5..d388a28570 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -MAKEFLAGS = -s +#MAKEFLAGS = -s name = avian version = 0.3 @@ -39,11 +39,17 @@ endif ifeq ($(continuations),true) options := $(options)-continuations endif + +classpath = avian + +test-library-path = . +test-executable = $(executable) + ifdef gnu + classpath = gnu options := $(options)-gnu - gnu-sources = $(src)/gnu.cpp - gnu-jar = $(gnu)/share/classpath/glibj.zip - gnu-libraries = \ + classapth-jar = $(gnu)/share/classpath/glibj.zip + classpath-libraries = \ $(gnu)/lib/classpath/libjavaio.a \ $(gnu)/lib/classpath/libjavalang.a \ $(gnu)/lib/classpath/libjavalangreflect.a \ @@ -51,10 +57,20 @@ ifdef gnu $(gnu)/lib/classpath/libjavanet.a \ $(gnu)/lib/classpath/libjavanio.a \ $(gnu)/lib/classpath/libjavautil.a - gnu-object-dep = $(build)/gnu-object.dep - gnu-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU - gnu-lflags = -lgmp - gnu-objects = $(shell find $(build)/gnu-objects -name "*.o") + classpath-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU + classpath-lflags = -lgmp +endif +ifdef openjdk + classpath = openjdk + options := $(options)-openjdk + ifeq ($(arch),x86_64) + openjdk-lib-dir = $(openjdk)/jre/lib/amd64 + else + openjdk-lib-dir = $(openjdk)/jre/lib + endif + classpath-jar = $(openjdk)/jre/lib/rt.jar + test-library-path = $(openjdk-lib-dir):$(native-build) + test-executable = $(executable-dynamic) endif root := $(shell (cd .. && pwd)) @@ -63,13 +79,16 @@ native-build = $(build)/$(platform)-$(arch)$(options) classpath-build = $(build)/classpath test-build = $(build)/test src = src -classpath = classpath +classpath-src = classpath test = test -ifdef gnu - avian-classpath-build = $(build)/avian-classpath +ifneq ($(classpath),avian) + classpath-object-dep = $(build)/classpath-object.dep + classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") else - avian-classpath-build = $(classpath-build) + jni-sources := $(shell find $(classpath-src) -name '*.cpp') + jni-objects = \ + $(call cpp-objects,$(jni-sources),$(classpath-src),$(native-build)) endif input = List @@ -79,12 +98,12 @@ build-cc = gcc mflag = ifneq ($(platform),darwin) - ifeq ($(arch),i386) - mflag = -m32 - endif - ifeq ($(arch),x86_64) - mflag = -m64 - endif + ifeq ($(arch),i386) + mflag = -m32 + endif + ifeq ($(arch),x86_64) + mflag = -m64 + endif endif cxx = $(build-cxx) $(mflag) @@ -112,14 +131,14 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS $(gnu-cflags) + -DUSE_ATOMIC_OPERATIONS $(classpath-cflags) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread cflags = $(build-cflags) -common-lflags = -lm -lz $(gnu-lflags) +common-lflags = -lm -lz $(classpath-lflags) build-lflags = @@ -297,9 +316,6 @@ cpp-objects = $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%.o,$(x))) asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) -jni-sources := $(shell find $(classpath) -name '*.cpp') -jni-objects = $(call cpp-objects,$(jni-sources),$(classpath),$(native-build)) - generated-code = \ $(native-build)/type-enums.cpp \ $(native-build)/type-declarations.cpp \ @@ -307,26 +323,7 @@ generated-code = \ $(native-build)/type-initializations.cpp \ $(native-build)/type-java-initializations.cpp -vm-depends = \ - $(generated-code) \ - $(src)/allocator.h \ - $(src)/common.h \ - $(src)/system.h \ - $(src)/heap.h \ - $(src)/finder.h \ - $(src)/processor.h \ - $(src)/process.h \ - $(src)/stream.h \ - $(src)/constants.h \ - $(src)/jnienv.h \ - $(src)/machine.h \ - $(src)/util.h \ - $(src)/zone.h \ - $(src)/assembler.h \ - $(src)/compiler.h \ - $(src)/$(asm).h \ - $(src)/heapwalk.h \ - $(src)/bootimage.h +vm-depends := $(generated-code) $(wildcard $(src)/*.h) vm-sources = \ $(src)/$(system).cpp \ @@ -335,10 +332,10 @@ vm-sources = \ $(src)/util.cpp \ $(src)/heap.cpp \ $(src)/$(process).cpp \ + $(src)/classpath-$(classpath).cpp \ $(src)/builtin.cpp \ $(src)/jnienv.cpp \ - $(src)/process.cpp \ - $(gnu-sources) + $(src)/process.cpp vm-asm-sources = $(src)/$(asm).S @@ -428,48 +425,37 @@ converter = $(native-build)/binaryToObject static-library = $(native-build)/lib$(name).a executable = $(native-build)/$(name)${exe-suffix} -dynamic-library = $(native-build)/$(so-prefix)$(name)$(so-suffix) +dynamic-library = $(native-build)/$(so-prefix)jvm$(so-suffix) executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix} -classpath-sources := $(shell find $(classpath) -name '*.java') +ifneq ($(classpath),avian) + classpath-sources := \ + $(classpath-src)/avian/Continuations.java \ + $(classpath-src)/avian/Callback.java \ + $(classpath-src)/avian/CallbackReceiver.java \ + $(classpath-src)/avian/IncompatibleContinuationException.java \ + $(classpath-src)/avian/SystemClassLoader.java \ + $(classpath-src)/avian/Machine.java \ + $(classpath-src)/avian/Addendum.java \ + $(classpath-src)/avian/ClassAddendum.java \ + $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/FieldAddendum.java \ + $(classpath-src)/avian/VMClass.java \ + $(classpath-src)/avian/VMField.java \ + $(classpath-src)/avian/VMMethod.java \ + $(classpath-src)/avian/resource/Handler.java +else + classpath-sources := $(shell find $(classpath-src) -name '*.java') +endif + classpath-classes = \ - $(call java-classes,$(classpath-sources),$(classpath),$(classpath-build)) + $(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build)) classpath-object = $(native-build)/classpath-jar.o classpath-dep = $(classpath-build).dep -gnu-blacklist = \ - java/lang/AbstractStringBuffer.class \ - java/lang/reflect/Proxy.class - -gnu-overrides = \ +vm-classes = \ avian/*.class \ - avian/resource/*.class \ - java/lang/Class.class \ - java/lang/Enum.class \ - java/lang/InheritableThreadLocal.class \ - java/lang/Object.class \ - java/lang/StackTraceElement.class \ - java/lang/String.class \ - java/lang/String\$$*.class \ - java/lang/StringBuffer.class \ - java/lang/StringBuilder.class \ - java/lang/StringBuilder\$$*.class \ - java/lang/Thread.class \ - java/lang/Thread\$$*.class \ - java/lang/ThreadGroup.class \ - java/lang/ThreadLocal.class \ - java/lang/Throwable.class \ - java/lang/ref/PhantomReference.class \ - java/lang/ref/Reference.class \ - java/lang/ref/ReferenceQueue.class \ - java/lang/ref/SoftReference.class \ - java/lang/ref/WeakReference.class \ - java/lang/reflect/AccessibleObject.class \ - java/lang/reflect/Constructor.class \ - java/lang/reflect/Field.class \ - java/lang/reflect/Method.class \ - java/lang/reflect/Proxy.class \ - java/lang/reflect/Proxy\$$*.class + avian/resource/*.class test-sources = $(wildcard $(test)/*.java) test-classes = $(call java-classes,$(test-sources),$(test),$(test-build)) @@ -510,7 +496,7 @@ vg: build .PHONY: test test: build /bin/sh $(test)/test.sh 2>/dev/null \ - $(executable) $(mode) "$(flags)" \ + $(test-library-path) $(test-executable) $(mode) "$(flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: tarball @@ -549,27 +535,20 @@ $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) $(native-build)/type-generator.o: \ $(generator-headers) -$(classpath-build)/%.class: $(classpath)/%.java +$(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) $(gnu-jar) +$(classpath-dep): $(classpath-sources) $(classpath-jar) @echo "compiling classpath classes" - @mkdir -p $(avian-classpath-build) - $(javac) -d $(avian-classpath-build) \ - -bootclasspath $(avian-classpath-build) \ - $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) -ifdef gnu - (wd=$$(pwd) && \ - cd $(avian-classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(build)/overrides.jar")" \ - $(gnu-overrides)) @mkdir -p $(classpath-build) +ifneq ($(classpath),avian) (wd=$$(pwd) && \ cd $(classpath-build) && \ - $(jar) xf $(gnu-jar) && \ - rm $(gnu-blacklist) && \ - jar xf "$$($(native-path) "$${wd}/$(build)/overrides.jar")") + $(jar) xf $(classpath-jar)) endif + $(javac) -d $(classpath-build) \ + -bootclasspath $(classpath-build) \ + $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -625,7 +604,7 @@ $(driver-object): $(driver-source) $(driver-dynamic-object): $(driver-source) @echo "compiling $(@)" @mkdir -p $(dir $(@)) - $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)$(name)$(so-suffix)\" \ + $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)jvm$(so-suffix)\" \ -c $(<) $(call output,$(@)) $(boot-object): $(boot-source) @@ -668,14 +647,14 @@ $(generator-objects): $(native-build)/%.o: $(src)/%.cpp $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ -c $(<) -o $(@) -$(jni-objects): $(native-build)/%.o: $(classpath)/%.cpp +$(jni-objects): $(native-build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(gnu-object-dep) +$(static-library): $(classpath-object-dep) $(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call gnu-objects) + $(ar) cru $(@) $(^) $(call classpath-objects) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -687,13 +666,13 @@ $(bootimage-object): $(bootimage-bin) $(converter) _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ writable executable -$(gnu-object-dep): $(gnu-libraries) - @mkdir -p $(build)/gnu-objects - (cd $(build)/gnu-objects && \ - for x in $(gnu-libraries); do ar x $${x}; done) +$(classpath-object-dep): $(classpath-libraries) + @mkdir -p $(build)/classpath-objects + (cd $(build)/classpath-objects && \ + for x in $(classpath-libraries); do ar x $${x}; done) @touch $(@) -$(executable): $(gnu-object-dep) +$(executable): $(classpath-object-dep) $(executable): \ $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ $(boot-object) $(vm-classpath-object) @@ -704,13 +683,13 @@ ifdef msvc -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(^) $(call gnu-objects) + $(dlltool) -z $(@).def $(^) $(call classpath-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(call gnu-objects) $(lflags) -o $(@) + $(ld) $(@).exp $(^) $(call classpath-objects) $(lflags) -o $(@) endif else - $(ld) $(^) $(call gnu-objects) $(rdynamic) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(ld) $(^) $(call classpath-objects) $(rdynamic) $(lflags) \ + $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -740,18 +719,18 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -$(dynamic-library): $(gnu-object-dep) +$(dynamic-library): $(classpath-object-dep) $(dynamic-library): \ $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) $(gnu-libraries) + $(boot-object) $(vm-classpath-object) $(classpath-libraries) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ -IMPLIB:$(native-build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) $(call gnu-objects) $(shared) $(lflags) $(bootimage-lflags) \ - -o $(@) + $(ld) $(^) -Wl,--version-script=openjdk.ld \ + $(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/openjdk.ld b/openjdk.ld new file mode 100644 index 0000000000..fdad025d57 --- /dev/null +++ b/openjdk.ld @@ -0,0 +1,288 @@ +# +# @(#)mapfile-vers-product 1.19 08/02/12 10:56:37 +# + +# +# Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# +# + +# Define public interface. + +SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + + # JVM + JVM_Accept; + JVM_ActiveProcessorCount; + JVM_AllocateNewArray; + JVM_AllocateNewObject; + JVM_ArrayCopy; + JVM_AssertionStatusDirectives; + JVM_Available; + JVM_Bind; + JVM_ClassDepth; + JVM_ClassLoaderDepth; + JVM_Clone; + JVM_Close; + JVM_CX8Field; + JVM_CompileClass; + JVM_CompileClasses; + JVM_CompilerCommand; + JVM_Connect; + JVM_ConstantPoolGetClassAt; + JVM_ConstantPoolGetClassAtIfLoaded; + JVM_ConstantPoolGetDoubleAt; + JVM_ConstantPoolGetFieldAt; + JVM_ConstantPoolGetFieldAtIfLoaded; + JVM_ConstantPoolGetFloatAt; + JVM_ConstantPoolGetIntAt; + JVM_ConstantPoolGetLongAt; + JVM_ConstantPoolGetMethodAt; + JVM_ConstantPoolGetMethodAtIfLoaded; + JVM_ConstantPoolGetMemberRefInfoAt; + JVM_ConstantPoolGetSize; + JVM_ConstantPoolGetStringAt; + JVM_ConstantPoolGetUTF8At; + JVM_CountStackFrames; + JVM_CurrentClassLoader; + JVM_CurrentLoadedClass; + JVM_CurrentThread; + JVM_CurrentTimeMillis; + JVM_DefineClass; + JVM_DefineClassWithSource; + JVM_DesiredAssertionStatus; + JVM_DisableCompiler; + JVM_DoPrivileged; + JVM_DTraceGetVersion; + JVM_DTraceActivate; + JVM_DTraceIsProbeEnabled; + JVM_DTraceIsSupported; + JVM_DTraceDispose; + JVM_DumpAllStacks; + JVM_DumpThreads; + JVM_EnableCompiler; + JVM_Exit; + JVM_FillInStackTrace; + JVM_FindClassFromClass; + JVM_FindClassFromClassLoader; + JVM_FindClassFromBootLoader; + JVM_FindLibraryEntry; + JVM_FindLoadedClass; + JVM_FindPrimitiveClass; + JVM_FindSignal; + JVM_FreeMemory; + JVM_GC; + JVM_GetAllThreads; + JVM_GetArrayElement; + JVM_GetArrayLength; + JVM_GetCPClassNameUTF; + JVM_GetCPFieldClassNameUTF; + JVM_GetCPFieldModifiers; + JVM_GetCPFieldNameUTF; + JVM_GetCPFieldSignatureUTF; + JVM_GetCPMethodClassNameUTF; + JVM_GetCPMethodModifiers; + JVM_GetCPMethodNameUTF; + JVM_GetCPMethodSignatureUTF; + JVM_GetCallerClass; + JVM_GetClassAccessFlags; + JVM_GetClassAnnotations; + JVM_GetClassCPEntriesCount; + JVM_GetClassCPTypes; + JVM_GetClassConstantPool; + JVM_GetClassContext; + JVM_GetClassDeclaredConstructors; + JVM_GetClassDeclaredFields; + JVM_GetClassDeclaredMethods; + JVM_GetClassFieldsCount; + JVM_GetClassInterfaces; + JVM_GetClassLoader; + JVM_GetClassMethodsCount; + JVM_GetClassModifiers; + JVM_GetClassName; + JVM_GetClassNameUTF; + JVM_GetClassSignature; + JVM_GetClassSigners; + JVM_GetComponentType; + JVM_GetDeclaredClasses; + JVM_GetDeclaringClass; + JVM_GetEnclosingMethodInfo; + JVM_GetFieldAnnotations; + JVM_GetFieldIxModifiers; + JVM_GetHostName; + JVM_GetInheritedAccessControlContext; + JVM_GetInterfaceVersion; + JVM_GetLastErrorString; + JVM_GetManagement; + JVM_GetMethodAnnotations; + JVM_GetMethodDefaultAnnotationValue; + JVM_GetMethodIxArgsSize; + JVM_GetMethodIxByteCode; + JVM_GetMethodIxByteCodeLength; + JVM_GetMethodIxExceptionIndexes; + JVM_GetMethodIxExceptionTableEntry; + JVM_GetMethodIxExceptionTableLength; + JVM_GetMethodIxExceptionsCount; + JVM_GetMethodIxLocalsCount; + JVM_GetMethodIxMaxStack; + JVM_GetMethodIxModifiers; + JVM_GetMethodIxNameUTF; + JVM_GetMethodIxSignatureUTF; + JVM_GetMethodParameterAnnotations; + JVM_GetPrimitiveArrayElement; + JVM_GetProtectionDomain; + JVM_GetSockName; + JVM_GetSockOpt; + JVM_GetStackAccessControlContext; + JVM_GetStackTraceDepth; + JVM_GetStackTraceElement; + JVM_GetSystemPackage; + JVM_GetSystemPackages; + JVM_GetThreadStateNames; + JVM_GetThreadStateValues; + JVM_GetVersionInfo; + JVM_Halt; + JVM_HoldsLock; + JVM_IHashCode; + JVM_InitAgentProperties; + JVM_InitProperties; + JVM_InitializeCompiler; + JVM_InitializeSocketLibrary; + JVM_InternString; + JVM_Interrupt; + JVM_InvokeMethod; + JVM_IsArrayClass; + JVM_IsConstructorIx; + JVM_IsInterface; + JVM_IsInterrupted; + JVM_IsNaN; + JVM_IsPrimitiveClass; + JVM_IsSameClassPackage; + JVM_IsSilentCompiler; + JVM_IsSupportedJNIVersion; + JVM_IsThreadAlive; + JVM_LatestUserDefinedLoader; + JVM_Listen; + JVM_LoadClass0; + JVM_LoadLibrary; + JVM_Lseek; + JVM_MaxObjectInspectionAge; + JVM_MaxMemory; + JVM_MonitorNotify; + JVM_MonitorNotifyAll; + JVM_MonitorWait; + JVM_NanoTime; + JVM_NativePath; + JVM_NewArray; + JVM_NewInstanceFromConstructor; + JVM_NewMultiArray; + JVM_OnExit; + JVM_Open; + JVM_PrintStackTrace; + JVM_RaiseSignal; + JVM_RawMonitorCreate; + JVM_RawMonitorDestroy; + JVM_RawMonitorEnter; + JVM_RawMonitorExit; + JVM_Read; + JVM_Recv; + JVM_RecvFrom; + JVM_RegisterSignal; + JVM_ReleaseUTF; + JVM_ResolveClass; + JVM_ResumeThread; + JVM_Send; + JVM_SendTo; + JVM_SetArrayElement; + JVM_SetClassSigners; + JVM_SetLength; + JVM_SetPrimitiveArrayElement; + JVM_SetProtectionDomain; + JVM_SetSockOpt; + JVM_SetThreadPriority; + JVM_Sleep; + JVM_Socket; + JVM_SocketAvailable; + JVM_SocketClose; + JVM_SocketShutdown; + JVM_StartThread; + JVM_StopThread; + JVM_SuspendThread; + JVM_SupportsCX8; + JVM_Sync; + JVM_Timeout; + JVM_TotalMemory; + JVM_TraceInstructions; + JVM_TraceMethodCalls; + JVM_UnloadLibrary; + JVM_Write; + JVM_Yield; + JVM_handle_linux_signal; + + # Old reflection routines + # These do not need to be present in the product build in JDK 1.4 + # but their code has not been removed yet because there will not + # be a substantial code savings until JVM_InvokeMethod and + # JVM_NewInstanceFromConstructor can also be removed; see + # reflectionCompat.hpp. + JVM_GetClassConstructor; + JVM_GetClassConstructors; + JVM_GetClassField; + JVM_GetClassFields; + JVM_GetClassMethod; + JVM_GetClassMethods; + JVM_GetField; + JVM_GetPrimitiveField; + JVM_NewInstance; + JVM_SetField; + JVM_SetPrimitiveField; + + # Needed for dropping VM into JDK 1.3.x, 1.4 + _JVM_native_threads; + jdk_sem_init; + jdk_sem_post; + jdk_sem_wait; + jdk_pthread_sigmask; + jdk_waitpid; + + # miscellaneous functions + jio_fprintf; + jio_printf; + jio_snprintf; + jio_vfprintf; + jio_vsnprintf; + fork1; + numa_warn; + numa_error; + + # Needed because there is no JVM interface for this. + sysThreadAvailableStackWithSlack; + + # This is for Forte Analyzer profiling support. + AsyncGetCallTrace; +}; + diff --git a/src/builtin.cpp b/src/builtin.cpp index 13333a1fb6..2d0d115a3c 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -39,135 +39,14 @@ search(Thread* t, object name, object (*op)(Thread*, object), return reinterpret_cast(r); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } -void -enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, - unsigned limit) -{ - if (*index < limit) { - set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread); - ++ (*index); - - if (x->peer) enumerateThreads(t, x->peer, array, index, limit); - - if (x->child) enumerateThreads(t, x->child, array, index, limit); - } -} - -bool -compatibleArrayTypes(Thread* t, object a, object b) -{ - return classArrayElementSize(t, a) - and classArrayElementSize(t, b) - and (a == b - or (not ((classVmFlags(t, a) & PrimitiveFlag) - or (classVmFlags(t, b) & PrimitiveFlag)))); -} - -void -runOnLoadIfFound(Thread* t, System::Library* library) -{ - void* p = library->resolve("JNI_OnLoad"); - if (p) { - jint (JNICALL * JNI_OnLoad)(Machine*, void*); - memcpy(&JNI_OnLoad, &p, sizeof(void*)); - JNI_OnLoad(t->m, 0); - } -} - } // namespace -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_toString -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - unsigned hash = objectHash(t, this_); - object s = makeString - (t, "%s@0x%x", - &byteArrayBody(t, className(t, objectClass(t, this_)), 0), - hash); - - return reinterpret_cast(s); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_getVMClass -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - - return reinterpret_cast(objectClass(t, o)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_wait -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); - - vm::wait(t, this_, milliseconds); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_notify -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - notify(t, this_); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Object_notifyAll -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - notifyAll(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_hashCode -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - return objectHash(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Object_clone -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - PROTECT(t, o); - - object class_ = objectClass(t, o); - unsigned size = baseSize(t, o, class_) * BytesPerWord; - object clone; - - if (classArrayElementSize(t, class_)) { - clone = static_cast(allocate(t, size, classObjectMask(t, class_))); - memcpy(clone, o, size); - // clear any object header flags: - setObjectClass(t, o, objectClass(t, o)); - } else { - clone = make(t, class_); - memcpy(reinterpret_cast(clone) + 1, - reinterpret_cast(o) + 1, - size - BytesPerWord); - } - - return reinterpret_cast(clone); -} - extern "C" JNIEXPORT void JNICALL Avian_avian_SystemClassLoader_acquireClassLock (Thread* t, object, uintptr_t*) @@ -195,8 +74,6 @@ Avian_avian_SystemClassLoader_defineVMClass (Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); - PROTECT(t, loader); - object b = reinterpret_cast(arguments[1]); int offset = arguments[2]; int length = arguments[3]; @@ -204,20 +81,9 @@ Avian_avian_SystemClassLoader_defineVMClass uint8_t* buffer = static_cast (t->m->heap->allocate(length)); memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = parseClass(t, loader, buffer, length); + object c = defineClass(t, loader, buffer, length); t->m->heap->free(buffer, length); - if (c) { - PROTECT(t, c); - if (getClassLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c, - byteArrayHash); - } - return reinterpret_cast(c); } @@ -260,62 +126,21 @@ Avian_avian_SystemClassLoader_resourceExists stringChars(t, name, RUNTIME_ARRAY_BODY(n)); return t->m->finder->exists(RUNTIME_ARRAY_BODY(n)); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_io_ObjectInputStream_makeInstance +Avian_avian_SystemClassLoader_primitiveClass (Thread* t, object, uintptr_t* arguments) { - object c = reinterpret_cast(arguments[0]); - - return reinterpret_cast(make(t, c)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_primitiveClass -(Thread* t, object, uintptr_t* arguments) -{ - char name = arguments[0]; - - switch (name) { - case 'B': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JbyteType)); - case 'C': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JcharType)); - case 'D': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JdoubleType)); - case 'F': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JfloatType)); - case 'I': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JintType)); - case 'J': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JlongType)); - case 'S': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JshortType)); - case 'V': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JvoidType)); - case 'Z': - return reinterpret_cast - (arrayBody(t, t->m->types, Machine::JbooleanType)); - default: - t->exception = makeIllegalArgumentException(t); - return 0; - } + return reinterpret_cast(primitiveClass(t, arguments[0])); } extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Class_initialize +Avian_avian_SystemClassLoader_initialize (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); @@ -324,7 +149,7 @@ Avian_java_lang_Class_initialize } extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_isAssignableFrom +Avian_avian_SystemClassLoader_isAssignableFrom (Thread* t, object, uintptr_t* arguments) { object this_ = reinterpret_cast(arguments[0]); @@ -333,392 +158,12 @@ Avian_java_lang_Class_isAssignableFrom if (LIKELY(that)) { return vm::isAssignableFrom(t, this_, that); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Field_getPrimitive -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int code = arguments[1]; - int offset = arguments[2]; - - switch (code) { - case ByteField: - return cast(instance, offset); - case BooleanField: - return cast(instance, offset); - case CharField: - return cast(instance, offset); - case ShortField: - return cast(instance, offset); - case IntField: - return cast(instance, offset); - case LongField: - return cast(instance, offset); - case FloatField: - return cast(instance, offset); - case DoubleField: - return cast(instance, offset); - default: - abort(t); - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Field_getObject -(Thread*, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int offset = arguments[1]; - - return reinterpret_cast(cast(instance, offset)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_reflect_Field_setPrimitive -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int code = arguments[1]; - int offset = arguments[2]; - int64_t value; memcpy(&value, arguments + 3, 8); - - switch (code) { - case ByteField: - cast(instance, offset) = static_cast(value); - break; - case BooleanField: - cast(instance, offset) = static_cast(value); - break; - case CharField: - cast(instance, offset) = static_cast(value); - break; - case ShortField: - cast(instance, offset) = static_cast(value); - break; - case IntField: - cast(instance, offset) = static_cast(value); - break; - case LongField: - cast(instance, offset) = static_cast(value); - break; - case FloatField: - cast(instance, offset) = static_cast(value); - break; - case DoubleField: - cast(instance, offset) = static_cast(value); - break; - default: - abort(t); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_reflect_Field_setObject -(Thread* t, object, uintptr_t* arguments) -{ - object instance = reinterpret_cast(arguments[0]); - int offset = arguments[1]; - object value = reinterpret_cast(arguments[2]); - - set(t, instance, offset, value); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Constructor_make -(Thread* t, object, uintptr_t* arguments) -{ - object c = reinterpret_cast(arguments[0]); - - return reinterpret_cast(make(t, c)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Method_getCaller -(Thread* t, object, uintptr_t*) -{ - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t): t(t), method(0), count(0) { } - - virtual bool visit(Processor::StackWalker* walker) { - if (count == 2) { - method = walker->method(); - return false; - } else { - ++ count; - return true; - } - } - - Thread* t; - object method; - unsigned count; - } v(t); - - t->m->processor->walkStack(t, &v); - - return reinterpret_cast(v.method); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Method_invoke -(Thread* t, object, uintptr_t* arguments) -{ - object method = reinterpret_cast(arguments[0]); - object instance = reinterpret_cast(arguments[1]); - object args = reinterpret_cast(arguments[2]); - - object v = t->m->processor->invokeArray(t, method, instance, args); - if (t->exception) { - t->exception = makeInvocationTargetException(t, t->exception); - } - return reinterpret_cast(v); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Array_getLength -(Thread* t, object, uintptr_t* arguments) -{ - object array = reinterpret_cast(arguments[0]); - - if (LIKELY(array)) { - unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); - - if (LIKELY(elementSize)) { - return cast(array, BytesPerWord); - } else { - t->exception = makeIllegalArgumentException(t); - } - } else { - t->exception = makeNullPointerException(t); - } - return 0; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_reflect_Array_makeObjectArray -(Thread* t, object, uintptr_t* arguments) -{ - object elementType = reinterpret_cast(arguments[0]); - int length = arguments[1]; - - return reinterpret_cast - (makeObjectArray(t, classLoader(t, elementType), elementType, length)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Float_floatToRawIntBits -(Thread*, object, uintptr_t* arguments) -{ - return static_cast(*arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Float_intBitsToFloat -(Thread*, object, uintptr_t* arguments) -{ - return static_cast(*arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Double_doubleToRawLongBits -(Thread*, object, uintptr_t* arguments) -{ - int64_t v; memcpy(&v, arguments, 8); - return v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Double_longBitsToDouble -(Thread*, object, uintptr_t* arguments) -{ - int64_t v; memcpy(&v, arguments, 8); - return v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_String_intern -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - return reinterpret_cast(intern(t, this_)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_getVMProperty -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - object found = reinterpret_cast(arguments[1]); - PROTECT(t, found); - - unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); - stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - - int64_t r = 0; - if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { - r = reinterpret_cast(makeString(t, "%s", t->m->finder->path())); - } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { - r = reinterpret_cast(makeString(t, AVIAN_VERSION)); - } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { - r = reinterpret_cast(makeString(t, "ASCII")); - } else { - const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n)); - if (v) { - r = reinterpret_cast(makeString(t, v)); - } - } - - if (r) { - booleanArrayBody(t, found, 0) = true; - } - - return r; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_System_arraycopy -(Thread* t, object, uintptr_t* arguments) -{ - object src = reinterpret_cast(arguments[0]); - int32_t srcOffset = arguments[1]; - object dst = reinterpret_cast(arguments[2]); - int32_t dstOffset = arguments[3]; - int32_t length = arguments[4]; - - if (LIKELY(src and dst)) { - if (LIKELY(compatibleArrayTypes - (t, objectClass(t, src), objectClass(t, dst)))) - { - unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); - - if (LIKELY(elementSize)) { - intptr_t sl = cast(src, BytesPerWord); - intptr_t dl = cast(dst, BytesPerWord); - if (LIKELY(length > 0)) { - if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and - dstOffset >= 0 and dstOffset + length <= dl)) - { - uint8_t* sbody = &cast(src, ArrayBody); - uint8_t* dbody = &cast(dst, ArrayBody); - if (src == dst) { - memmove(dbody + (dstOffset * elementSize), - sbody + (srcOffset * elementSize), - length * elementSize); - } else { - memcpy(dbody + (dstOffset * elementSize), - sbody + (srcOffset * elementSize), - length * elementSize); - } - - if (classObjectMask(t, objectClass(t, dst))) { - mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); - } - - return; - } else { - t->exception = makeIndexOutOfBoundsException(t); - return; - } - } else { - return; - } - } - } - } else { - t->exception = makeNullPointerException(t); - return; - } - - t->exception = makeArrayStoreException(t); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_identityHashCode -(Thread* t, object, uintptr_t* arguments) -{ - object o = reinterpret_cast(arguments[0]); - - if (LIKELY(o)) { - return objectHash(t, o); - } else { - t->exception = makeNullPointerException(t); - return 0; - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_load -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - bool mapName = arguments[1]; - - unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); - stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - - ACQUIRE(t, t->m->classLock); - - const char* builtins = findProperty(t, "avian.builtins"); - if (mapName and builtins) { - const char* s = builtins; - while (*s) { - if (::strncmp(s, RUNTIME_ARRAY_BODY(n), length) == 0 - and (s[length] == ',' or s[length] == 0)) - { - // library is built in to this executable - if (not t->m->triedBuiltinOnLoad) { - t->m->triedBuiltinOnLoad = true; - runOnLoadIfFound(t, t->m->libraries); - } - return; - } else { - while (*s and *s != ',') ++ s; - if (*s) ++ s; - } - } - } - - System::Library* last = t->m->libraries; - for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { - if (lib->name() - and ::strcmp(lib->name(), RUNTIME_ARRAY_BODY(n)) == 0 - and lib->mapName() == mapName) - { - // already loaded - return; - } - last = lib; - } - - System::Library* lib; - if (LIKELY(t->m->system->success - (t->m->system->load(&lib, RUNTIME_ARRAY_BODY(n), mapName)))) - { - last->setNext(lib); - runOnLoadIfFound(t, lib); - } else { - object message = makeString - (t, "library not found: %s", RUNTIME_ARRAY_BODY(n)); - t->exception = makeUnsatisfiedLinkError(t, message); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_gc -(Thread* t, object, uintptr_t*) -{ - collect(t, Heap::MajorCollection); -} - #ifdef AVIAN_HEAPDUMP extern "C" JNIEXPORT void JNICALL @@ -753,193 +198,6 @@ Avian_java_lang_Runtime_exit t->m->system->exit(arguments[1]); } -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Runtime_freeMemory -(Thread*, object, uintptr_t*) -{ - // todo - return 0; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Runtime_totalMemory -(Thread*, object, uintptr_t*) -{ - // todo - return 0; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_addShutdownHook -(Thread* t, object, uintptr_t* arguments) -{ - object hook = reinterpret_cast(arguments[1]); - PROTECT(t, hook); - - ACQUIRE(t, t->m->shutdownLock); - - t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Throwable_trace -(Thread* t, object, uintptr_t* arguments) -{ - int32_t skipCount = arguments[0]; - - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t, int skipCount): - t(t), trace(0), skipCount(skipCount) - { } - - virtual bool visit(Processor::StackWalker* walker) { - if (skipCount == 0) { - object method = walker->method(); - if (isAssignableFrom - (t, arrayBody(t, t->m->types, Machine::ThrowableType), - methodClass(t, method)) - and vm::strcmp(reinterpret_cast(""), - &byteArrayBody(t, methodName(t, method), 0)) - == 0) - { - return true; - } else { - trace = makeTrace(t, walker); - return false; - } - } else { - -- skipCount; - return true; - } - } - - Thread* t; - object trace; - unsigned skipCount; - } v(t, skipCount); - - t->m->processor->walkStack(t, &v); - - if (v.trace == 0) v.trace = makeArray(t, 0); - - return reinterpret_cast(v.trace); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Throwable_resolveTrace -(Thread* t, object, uintptr_t* arguments) -{ - object trace = reinterpret_cast(*arguments); - PROTECT(t, trace); - - unsigned length = arrayLength(t, trace); - object elementType = arrayBody - (t, t->m->types, Machine::StackTraceElementType); - object array = makeObjectArray - (t, classLoader(t, elementType), elementType, length); - PROTECT(t, array); - - object e = 0; - PROTECT(t, e); - - object class_ = 0; - PROTECT(t, class_); - - object method = 0; - PROTECT(t, method); - - for (unsigned i = 0; i < length; ++i) { - e = arrayBody(t, trace, i); - - class_ = className(t, methodClass(t, traceElementMethod(t, e))); - class_ = makeString(t, class_, 0, byteArrayLength(t, class_) - 1, 0); - - method = methodName(t, traceElementMethod(t, e)); - method = makeString(t, method, 0, byteArrayLength(t, method) - 1, 0); - - unsigned line = t->m->processor->lineNumber - (t, traceElementMethod(t, e), traceElementIp(t, e)); - - object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e))); - file = file ? makeString(t, file, 0, byteArrayLength(t, file) - 1, 0) : 0; - - object ste = makeStackTraceElement(t, class_, method, file, line); - set(t, array, ArrayBody + (i * BytesPerWord), ste); - } - - return reinterpret_cast(array); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_currentThread -(Thread* t, object, uintptr_t*) -{ - return reinterpret_cast(t->javaThread); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_doStart -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast - (startThread(t, reinterpret_cast(*arguments))); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Thread_interrupt -(Thread* t, object, uintptr_t* arguments) -{ - int64_t peer; memcpy(&peer, arguments, 8); - - interrupt(t, reinterpret_cast(peer)); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_getStackTrace -(Thread* t, object, uintptr_t* arguments) -{ - int64_t peer; memcpy(&peer, arguments, 8); - - if (reinterpret_cast(peer) == t) { - return reinterpret_cast(makeTrace(t)); - } else { - return reinterpret_cast - (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_activeCount -(Thread* t, object, uintptr_t*) -{ - return t->m->liveCount; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Thread_enumerate -(Thread* t, object, uintptr_t* arguments) -{ - object array = reinterpret_cast(*arguments); - - ACQUIRE_RAW(t, t->m->stateLock); - - unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); - unsigned index = 0; - enumerateThreads(t, t->m->rootThread, array, &index, count); - return count; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Thread_setDaemon -(Thread* t, object, uintptr_t* arguments) -{ - object thread = reinterpret_cast(arguments[0]); - bool daemon = arguments[1] != 0; - - setDaemon(t, thread, daemon); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength (Thread* t, object, uintptr_t* arguments) @@ -973,7 +231,8 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open return reinterpret_cast (t->m->finder->find(RUNTIME_ARRAY_BODY(p))); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); return 0; } } diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp new file mode 100644 index 0000000000..b9b5570eda --- /dev/null +++ b/src/classpath-avian.cpp @@ -0,0 +1,601 @@ +/* Copyright (c) 2010, 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. */ + +#include "machine.h" +#include "classpath-common.h" + +using namespace vm; + +namespace { + +namespace local { + +class MyClasspath : public Classpath { + public: + MyClasspath(Allocator* allocator): + allocator(allocator) + { } + + virtual object + makeJclass(Thread* t, object class_) + { + return vm::makeJclass(t, class_); + } + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) + { + return vm::makeString(t, array, offset, length, 0); + } + + virtual object + makeThread(Thread* t, Thread* parent) + { + object group; + if (parent) { + group = threadGroup(t, parent->javaThread); + } else { + group = makeThreadGroup(t, 0, 0, 0); + } + + const unsigned NewState = 0; + const unsigned NormalPriority = 5; + + return vm::makeThread + (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, + group); + } + + virtual void + runThread(Thread* t) + { + object method = resolveMethod + (t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); + + if (t->exception == 0) { + t->m->processor->invoke(t, method, 0, t->javaThread); + } + } + + virtual object + makeThrowable + (Thread* t, Machine::Type type, object message, object trace, object cause) + { + PROTECT(t, message); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, arrayBody(t, t->m->types, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; + } + + virtual void + dispose() + { + allocator->free(this, sizeof(*this)); + } + + Allocator* allocator; +}; + +void +enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, + unsigned limit) +{ + if (*index < limit) { + set(t, array, ArrayBody + (*index * BytesPerWord), x->javaThread); + ++ (*index); + + if (x->peer) enumerateThreads(t, x->peer, array, index, limit); + + if (x->child) enumerateThreads(t, x->child, array, index, limit); + } +} + +} // namespace local + +} // namespace + +namespace vm { + +Classpath* +makeClasspath(System*, Allocator* allocator) +{ + return new (allocator->allocate(sizeof(local::MyClasspath))) + local::MyClasspath(allocator); +} + +} // namespace vm + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_toString +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + unsigned hash = objectHash(t, this_); + object s = makeString + (t, "%s@0x%x", + &byteArrayBody(t, className(t, objectClass(t, this_)), 0), + hash); + + return reinterpret_cast(s); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_getVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(objectClass(t, o)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_wait +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + int64_t milliseconds; memcpy(&milliseconds, arguments + 1, 8); + + vm::wait(t, this_, milliseconds); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_notify +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + notify(t, this_); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Object_notifyAll +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + notifyAll(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_hashCode +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + return objectHash(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Object_clone +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (clone(t, reinterpret_cast(arguments[0]))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_io_ObjectInputStream_makeInstance +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + + return reinterpret_cast(make(t, c)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getPrimitive +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; + + switch (code) { + case ByteField: + return cast(instance, offset); + case BooleanField: + return cast(instance, offset); + case CharField: + return cast(instance, offset); + case ShortField: + return cast(instance, offset); + case IntField: + return cast(instance, offset); + case LongField: + return cast(instance, offset); + case FloatField: + return cast(instance, offset); + case DoubleField: + return cast(instance, offset); + default: + abort(t); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Field_getObject +(Thread*, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + + return reinterpret_cast(cast(instance, offset)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_reflect_Field_setPrimitive +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int code = arguments[1]; + int offset = arguments[2]; + int64_t value; memcpy(&value, arguments + 3, 8); + + switch (code) { + case ByteField: + cast(instance, offset) = static_cast(value); + break; + case BooleanField: + cast(instance, offset) = static_cast(value); + break; + case CharField: + cast(instance, offset) = static_cast(value); + break; + case ShortField: + cast(instance, offset) = static_cast(value); + break; + case IntField: + cast(instance, offset) = static_cast(value); + break; + case LongField: + cast(instance, offset) = static_cast(value); + break; + case FloatField: + cast(instance, offset) = static_cast(value); + break; + case DoubleField: + cast(instance, offset) = static_cast(value); + break; + default: + abort(t); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_reflect_Field_setObject +(Thread* t, object, uintptr_t* arguments) +{ + object instance = reinterpret_cast(arguments[0]); + int offset = arguments[1]; + object value = reinterpret_cast(arguments[2]); + + set(t, instance, offset, value); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Constructor_make +(Thread* t, object, uintptr_t* arguments) +{ + object c = reinterpret_cast(arguments[0]); + + return reinterpret_cast(make(t, c)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_getCaller +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(getCaller(t, 2)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Method_invoke +(Thread* t, object, uintptr_t* arguments) +{ + object method = reinterpret_cast(arguments[0]); + object instance = reinterpret_cast(arguments[1]); + object args = reinterpret_cast(arguments[2]); + + object v = t->m->processor->invokeArray(t, method, instance, args); + if (t->exception) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, t->exception); + } + return reinterpret_cast(v); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_getLength +(Thread* t, object, uintptr_t* arguments) +{ + object array = reinterpret_cast(arguments[0]); + + if (LIKELY(array)) { + unsigned elementSize = classArrayElementSize(t, objectClass(t, array)); + + if (LIKELY(elementSize)) { + return cast(array, BytesPerWord); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + } + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + } + return 0; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_reflect_Array_makeObjectArray +(Thread* t, object, uintptr_t* arguments) +{ + object elementType = reinterpret_cast(arguments[0]); + int length = arguments[1]; + + return reinterpret_cast + (makeObjectArray(t, classLoader(t, elementType), elementType, length)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_floatToRawIntBits +(Thread*, object, uintptr_t* arguments) +{ + return static_cast(*arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Float_intBitsToFloat +(Thread*, object, uintptr_t* arguments) +{ + return static_cast(*arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_doubleToRawLongBits +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments, 8); + return v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Double_longBitsToDouble +(Thread*, object, uintptr_t* arguments) +{ + int64_t v; memcpy(&v, arguments, 8); + return v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_String_intern +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + return reinterpret_cast(intern(t, this_)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_getVMProperty +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + object found = reinterpret_cast(arguments[1]); + PROTECT(t, found); + + unsigned length = stringLength(t, name); + RUNTIME_ARRAY(char, n, length + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + int64_t r = 0; + if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { + r = reinterpret_cast(makeString(t, "%s", t->m->finder->path())); + } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { + r = reinterpret_cast(makeString(t, AVIAN_VERSION)); + } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { + r = reinterpret_cast(makeString(t, "ASCII")); + } else { + const char* v = findProperty(t, RUNTIME_ARRAY_BODY(n)); + if (v) { + r = reinterpret_cast(makeString(t, v)); + } + } + + if (r) { + booleanArrayBody(t, found, 0) = true; + } + + return r; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_System_arraycopy +(Thread* t, object, uintptr_t* arguments) +{ + arrayCopy(t, reinterpret_cast(arguments[0]), + arguments[1], + reinterpret_cast(arguments[2]), + arguments[3], + arguments[4]); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_System_identityHashCode +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[0]); + + if (LIKELY(o)) { + return objectHash(t, o); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_load +(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + bool mapName = arguments[1]; + + unsigned length = stringLength(t, name); + RUNTIME_ARRAY(char, n, length + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + loadLibrary(t, RUNTIME_ARRAY_BODY(n), mapName, true); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_gc +(Thread* t, object, uintptr_t*) +{ + collect(t, Heap::MajorCollection); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_freeMemory +(Thread*, object, uintptr_t*) +{ + // todo + return 0; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Runtime_totalMemory +(Thread*, object, uintptr_t*) +{ + // todo + return 0; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Runtime_addShutdownHook +(Thread* t, object, uintptr_t* arguments) +{ + object hook = reinterpret_cast(arguments[1]); + PROTECT(t, hook); + + ACQUIRE(t, t->m->shutdownLock); + + t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_trace +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast(getTrace(t, arguments[0])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Throwable_resolveTrace +(Thread* t, object, uintptr_t* arguments) +{ + object trace = reinterpret_cast(*arguments); + PROTECT(t, trace); + + unsigned length = arrayLength(t, trace); + object elementType = arrayBody + (t, t->m->types, Machine::StackTraceElementType); + object array = makeObjectArray + (t, classLoader(t, elementType), elementType, length); + PROTECT(t, array); + + for (unsigned i = 0; i < length; ++i) { + object ste = makeStackTraceElement(t, arrayBody(t, trace, i)); + set(t, array, ArrayBody + (i * BytesPerWord), ste); + } + + return reinterpret_cast(array); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_currentThread +(Thread* t, object, uintptr_t*) +{ + return reinterpret_cast(t->javaThread); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_doStart +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (startThread(t, reinterpret_cast(*arguments))); +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_interrupt +(Thread* t, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + interrupt(t, reinterpret_cast(peer)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_getStackTrace +(Thread* t, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + + if (reinterpret_cast(peer) == t) { + return reinterpret_cast(makeTrace(t)); + } else { + return reinterpret_cast + (t->m->processor->getStackTrace(t, reinterpret_cast(peer))); + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_activeCount +(Thread* t, object, uintptr_t*) +{ + return t->m->liveCount; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Thread_enumerate +(Thread* t, object, uintptr_t* arguments) +{ + object array = reinterpret_cast(*arguments); + + ACQUIRE_RAW(t, t->m->stateLock); + + unsigned count = min(t->m->liveCount, objectArrayLength(t, array)); + unsigned index = 0; + local::enumerateThreads(t, t->m->rootThread, array, &index, count); + return count; +} + +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_setDaemon +(Thread* t, object, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[0]); + bool daemon = arguments[1] != 0; + + setDaemon(t, thread, daemon); +} diff --git a/src/classpath-common.h b/src/classpath-common.h new file mode 100644 index 0000000000..23cccb8684 --- /dev/null +++ b/src/classpath-common.h @@ -0,0 +1,271 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef CLASSPATH_COMMON_H +#define CLASSPATH_COMMON_H + +namespace vm { + +inline object +getCaller(Thread* t, unsigned target) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t, unsigned target): + t(t), method(0), count(0), target(target) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (count == target) { + method = walker->method(); + return false; + } else { + ++ count; + return true; + } + } + + Thread* t; + object method; + unsigned count; + unsigned target; + } v(t, target); + + t->m->processor->walkStack(t, &v); + + return v.method; +} + +inline object +getTrace(Thread* t, unsigned skipCount) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t, int skipCount): + t(t), trace(0), skipCount(skipCount) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (skipCount == 0) { + object method = walker->method(); + if (isAssignableFrom + (t, arrayBody(t, t->m->types, Machine::ThrowableType), + methodClass(t, method)) + and vm::strcmp(reinterpret_cast(""), + &byteArrayBody(t, methodName(t, method), 0)) + == 0) + { + return true; + } else { + trace = makeTrace(t, walker); + return false; + } + } else { + -- skipCount; + return true; + } + } + + Thread* t; + object trace; + unsigned skipCount; + } v(t, skipCount); + + t->m->processor->walkStack(t, &v); + + if (v.trace == 0) v.trace = makeArray(t, 0); + + return v.trace; +} + +inline bool +compatibleArrayTypes(Thread* t, object a, object b) +{ + return classArrayElementSize(t, a) + and classArrayElementSize(t, b) + and (a == b + or (not ((classVmFlags(t, a) & PrimitiveFlag) + or (classVmFlags(t, b) & PrimitiveFlag)))); +} + +inline void +arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, + int32_t dstOffset, int32_t length) +{ + if (LIKELY(src and dst)) { + if (LIKELY(compatibleArrayTypes + (t, objectClass(t, src), objectClass(t, dst)))) + { + unsigned elementSize = classArrayElementSize(t, objectClass(t, src)); + + if (LIKELY(elementSize)) { + intptr_t sl = cast(src, BytesPerWord); + intptr_t dl = cast(dst, BytesPerWord); + if (LIKELY(length > 0)) { + if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl and + dstOffset >= 0 and dstOffset + length <= dl)) + { + uint8_t* sbody = &cast(src, ArrayBody); + uint8_t* dbody = &cast(dst, ArrayBody); + if (src == dst) { + memmove(dbody + (dstOffset * elementSize), + sbody + (srcOffset * elementSize), + length * elementSize); + } else { + memcpy(dbody + (dstOffset * elementSize), + sbody + (srcOffset * elementSize), + length * elementSize); + } + + if (classObjectMask(t, objectClass(t, dst))) { + mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length); + } + + return; + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IndexOutOfBoundsExceptionType); + return; + } + } else { + return; + } + } + } + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + return; + } + + t->exception = t->m->classpath->makeThrowable + (t, Machine::ArrayStoreExceptionType); +} + +void +runOnLoadIfFound(Thread* t, System::Library* library) +{ + void* p = library->resolve("JNI_OnLoad"); + if (p) { + jint (JNICALL * JNI_OnLoad)(Machine*, void*); + memcpy(&JNI_OnLoad, &p, sizeof(void*)); + JNI_OnLoad(t->m, 0); + } +} + +System::Library* +loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) +{ + ACQUIRE(t, t->m->classLock); + + const char* builtins = findProperty(t, "avian.builtins"); + if (mapName and builtins) { + const char* s = builtins; + while (*s) { + unsigned length = strlen(name); + if (::strncmp(s, name, length) == 0 + and (s[length] == ',' or s[length] == 0)) + { + // library is built in to this executable + if (runOnLoad and not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + runOnLoadIfFound(t, t->m->libraries); + } + return t->m->libraries; + } else { + while (*s and *s != ',') ++ s; + if (*s) ++ s; + } + } + } + + System::Library* last = t->m->libraries; + for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { + if (lib->name() + and ::strcmp(lib->name(), name) == 0 + and lib->mapName() == mapName) + { + // already loaded + return lib; + } + last = lib; + } + + System::Library* lib; + if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) { + last->setNext(lib); + if (runOnLoad) { + runOnLoadIfFound(t, lib); + } + return lib; + } else { + object message = makeString(t, "library not found: %s", name); + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); + return 0; + } +} + +object +clone(Thread* t, object o) +{ + PROTECT(t, o); + + object class_ = objectClass(t, o); + unsigned size = baseSize(t, o, class_) * BytesPerWord; + object clone; + + if (classArrayElementSize(t, class_)) { + clone = static_cast(allocate(t, size, classObjectMask(t, class_))); + memcpy(clone, o, size); + // clear any object header flags: + setObjectClass(t, o, objectClass(t, o)); + } else { + clone = make(t, class_); + memcpy(reinterpret_cast(clone) + 1, + reinterpret_cast(o) + 1, + size - BytesPerWord); + } + + return clone; +} + +object +makeStackTraceElement(Thread* t, object e) +{ + PROTECT(t, e); + + object class_ = className(t, methodClass(t, traceElementMethod(t, e))); + PROTECT(t, class_); + + RUNTIME_ARRAY(char, s, byteArrayLength(t, class_)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), + reinterpret_cast(&byteArrayBody(t, class_, 0))); + class_ = makeString(t, "%s", s); + + object method = methodName(t, traceElementMethod(t, e)); + PROTECT(t, method); + + method = t->m->classpath->makeString + (t, method, 0, byteArrayLength(t, method) - 1); + + unsigned line = t->m->processor->lineNumber + (t, traceElementMethod(t, e), traceElementIp(t, e)); + + object file = classSourceFile(t, methodClass(t, traceElementMethod(t, e))); + file = file ? t->m->classpath->makeString + (t, file, 0, byteArrayLength(t, file) - 1) : 0; + + return makeStackTraceElement(t, class_, method, file, line); +} + +} // namespace vm + +#endif//CLASSPATH_COMMON_H diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp new file mode 100644 index 0000000000..39c6592bc9 --- /dev/null +++ b/src/classpath-openjdk.cpp @@ -0,0 +1,2096 @@ +/* Copyright (c) 2010, 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. */ + +#include "machine.h" +#include "classpath-common.h" + +// todo: move platform-specific stuff into system.h and implementations + +#ifdef PLATFORM_WINDOWS + +# include +# include +# include +# include + +# define CLOSE _close +# define READ _read +# define WRITE _write + +# ifdef _MSC_VER +# define S_ISREG(x) ((x) | _S_IFREG) +# define S_ISDIR(x) ((x) | _S_IFDIR) +# define S_IRUSR _S_IREAD +# define S_IWUSR _S_IWRITE +# else +# define OPEN _wopen +# define CREAT _wcreat +# endif + +#else // not PLATFORM_WINDOWS + +# include +# include +# include +# include +# include + +# define OPEN open +# define CLOSE close +# define READ read +# define WRITE write +# define LSEEK lseek + +#endif // not PLATFORM_WINDOWS + +using namespace vm; + +namespace { + +#ifdef _MSC_VER +inline int +OPEN(string_t path, int mask, int mode) +{ + int fd; + if (_wsopen_s(&fd, path, mask, _SH_DENYNO, mode) == 0) { + return fd; + } else { + return -1; + } +} + +inline int +CREAT(string_t path, int mode) +{ + return OPEN(path, _O_CREAT, mode); +} +#endif + +namespace local { + +const unsigned InterfaceVersion = 4; + +Machine* globalMachine; + + +const char* +primitiveName(Thread* t, object c) +{ + if (c == primitiveClass(t, 'V')) { + return "void"; + } else if (c == primitiveClass(t, 'Z')) { + return "boolean"; + } else if (c == primitiveClass(t, 'B')) { + return "byte"; + } else if (c == primitiveClass(t, 'C')) { + return "char"; + } else if (c == primitiveClass(t, 'S')) { + return "short"; + } else if (c == primitiveClass(t, 'I')) { + return "int"; + } else if (c == primitiveClass(t, 'F')) { + return "float"; + } else if (c == primitiveClass(t, 'J')) { + return "long"; + } else if (c == primitiveClass(t, 'D')) { + return "double"; + } else { + abort(t); + } +} + +object +getClassName(Thread* t, object c) +{ + if (className(t, c) == 0) { + if (classVmFlags(t, c) & PrimitiveFlag) { + PROTECT(t, c); + + object name = makeByteArray(t, primitiveName(t, c)); + + set(t, c, ClassName, name); + } else { + abort(t); + } + } + + return className(t, c); +} + +object +makeClassNameString(Thread* t, object name) +{ + RUNTIME_ARRAY(char, s, byteArrayLength(t, name)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), + reinterpret_cast(&byteArrayBody(t, name, 0))); + + return makeString(t, "%s", s); +} + +class MyClasspath : public Classpath { + public: + MyClasspath(Allocator* allocator): + allocator(allocator) + { } + + virtual object + makeJclass(Thread* t, object class_) + { + object name = makeClassNameString(t, getClassName(t, class_)); + + return vm::makeJclass + (t, 0, 0, name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, class_); + } + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) + { + if (objectClass(t, array) + == arrayBody(t, t->m->types, Machine::ByteArrayType)) + { + PROTECT(t, array); + + object charArray = makeCharArray(t, length); + for (int i = 0; i < length; ++i) { + charArrayBody(t, charArray, i) = byteArrayBody(t, array, offset + i); + } + + array = charArray; + } + return vm::makeString(t, array, offset, length, 0); + } + + virtual object + makeThread(Thread* t, Thread* parent) + { + const unsigned MaxPriority = 10; + const unsigned NormalPriority = 5; + + object group; + if (parent) { + group = threadGroup(t, parent->javaThread); + } else { + group = makeThreadGroup + (t, 0, 0, MaxPriority, false, false, false, 0, 0, 0, 0, 0); + } + + return vm::makeThread + (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, t->m->loader, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, false); + } + + virtual void + runThread(Thread* t) + { + object method = resolveMethod + (t, t->m->loader, "java/lang/Thread", "run", "()V"); + + if (LIKELY(t->exception == 0)) { + t->m->processor->invoke(t, method, t->javaThread); + } + } + + virtual object + makeThrowable + (Thread* t, Machine::Type type, object message, object trace, object cause) + { + PROTECT(t, message); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, arrayBody(t, t->m->types, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; + } + + virtual void + boot(Thread* t) + { + globalMachine = t->m; + + if (loadLibrary(t, "java", true, true) == 0) { + abort(t); + } + + t->m->processor->invoke + (t, t->m->loader, "java/lang/System", "initializeSystemClass", "()V", 0); + } + + virtual void + dispose() + { + allocator->free(this, sizeof(*this)); + } + + Allocator* allocator; +}; + +struct JVM_ExceptionTableEntryType{ + jint start_pc; + jint end_pc; + jint handler_pc; + jint catchType; +}; + +struct jvm_version_info { + unsigned int jvm_version; + unsigned int update_version: 8; + unsigned int special_update_version: 8; + unsigned int reserved1: 16; + unsigned int reserved2; + unsigned int is_attach_supported: 1; + unsigned int is_kernel_jvm: 1; + unsigned int: 30; + unsigned int: 32; + unsigned int: 32; +}; + +unsigned +countMethods(Thread* t, object c, bool publicOnly) +{ + object table = classMethodTable(t, c); + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') + { + ++ count; + } + } + return count; +} + +unsigned +countFields(Thread* t, object c, bool publicOnly) +{ + object table = classFieldTable(t, c); + if (publicOnly) { + return objectArrayLength(t, table); + } else { + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmField = arrayBody(t, table, i); + if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { + ++ count; + } + } + return count; + } +} + +unsigned +countConstructors(Thread* t, object c, bool publicOnly) +{ + object table = classMethodTable(t, c); + unsigned count = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and strcmp(reinterpret_cast + (&byteArrayBody(t, methodName(t, vmMethod), 0)), + "") == 0) + { + ++ count; + } + } + return count; +} + +object +resolveClassBySpec(Thread* t, object loader, const char* spec, + unsigned specLength) +{ + switch (*spec) { + case 'L': { + RUNTIME_ARRAY(char, s, specLength - 1); + memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2); + RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0; + return resolveClass(t, loader, s); + } + + case '[': { + RUNTIME_ARRAY(char, s, specLength + 1); + memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength); + RUNTIME_ARRAY_BODY(s)[specLength] = 0; + return resolveClass(t, loader, s); + } + + default: + return primitiveClass(t, *spec); + } +} + +object +resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) +{ + object c = resolveClassBySpec(t, loader, spec, specLength); + + if (UNLIKELY(t->exception)) return 0; + + return getJClass(t, c); +} + +object +resolveParameterTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + PROTECT(t, loader); + PROTECT(t, spec); + + object list = 0; + PROTECT(t, list); + + unsigned offset = 1; + unsigned count = 0; + while (byteArrayBody(t, spec, offset) != ')') { + switch (byteArrayBody(t, spec, offset)) { + case 'L': { + unsigned start = offset; + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + if (UNLIKELY(t->exception)) { + return 0; + } + + list = makePair(t, type, list); + + ++ count; + } break; + + case '[': { + unsigned start = offset; + while (byteArrayBody(t, spec, offset) == '[') ++ offset; + switch (byteArrayBody(t, spec, offset)) { + case 'L': + ++ offset; + while (byteArrayBody(t, spec, offset) != ';') ++ offset; + ++ offset; + break; + + default: + ++ offset; + break; + } + + object type = resolveClassBySpec + (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), + offset - start); + if (UNLIKELY(t->exception)) { + return 0; + } + + list = makePair(t, type, list); + ++ count; + } break; + + default: + list = makePair + (t, primitiveClass(t, byteArrayBody(t, spec, offset)), list); + ++ offset; + ++ count; + break; + } + } + + *parameterCount = count; + *returnTypeSpec = offset + 1; + return list; +} + +object +resolveParameterJTypes(Thread* t, object loader, object spec, + unsigned* parameterCount, unsigned* returnTypeSpec) +{ + object list = resolveParameterTypes + (t, loader, spec, parameterCount, returnTypeSpec); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, list); + + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), + *parameterCount); + PROTECT(t, array); + + for (int i = *parameterCount - 1; i >= 0; --i) { + object c = getJClass(t, pairFirst(t, list)); + set(t, array, ArrayBody + (i * BytesPerWord), c); + list = pairSecond(t, list); + } + + return array; +} + +object +resolveExceptionJTypes(Thread* t, object loader, object addendum) +{ + if (addendum == 0) { + return makeObjectArray + (t, loader, arrayBody(t, t->m->types, Machine::JclassType), 0); + } + + PROTECT(t, loader); + PROTECT(t, addendum); + + object array = makeObjectArray + (t, loader, arrayBody(t, t->m->types, Machine::JclassType), + shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); + PROTECT(t, array); + + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject(t, addendumPool(t, addendum), index); + + if (objectClass(t, o) + == arrayBody(t, t->m->types, Machine::ReferenceType)) + { + o = resolveClass(t, loader, referenceName(t, o)); + if (UNLIKELY(t->exception)) return 0; + + set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), + o); + } + + o = getJClass(t, o); + + set(t, array, ArrayBody + (i * BytesPerWord), o); + } + + return array; +} + +void +setProperty(Thread* t, object method, object properties, + const char* name, const void* value, const char* format = "%s") +{ + PROTECT(t, method); + PROTECT(t, properties); + + object n = makeString(t, "%s", name); + PROTECT(t, n); + + object v = makeString(t, format, value); + + t->m->processor->invoke(t, method, properties, n, v); +} + +} // namespace local + +} // namespace + +namespace vm { + +Classpath* +makeClasspath(System*, Allocator* allocator) +{ + return new (allocator->allocate(sizeof(local::MyClasspath))) + local::MyClasspath(allocator); +} + +} // namespace vm + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_lang_Class_getSuperclass +(Thread* t, object, uintptr_t* arguments) +{ + object super = classSuper + (t, jclassVmClass(t, reinterpret_cast(arguments[0]))); + + return super ? reinterpret_cast(getJClass(t, super)) : 0; +} + +extern "C" JNIEXPORT void +Avian_sun_misc_Unsafe_registerNatives +(Thread*, object, uintptr_t*) +{ + // ignore +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_staticFieldOffset +(Thread* t, object, uintptr_t* arguments) +{ + object jfield = reinterpret_cast(arguments[1]); + return fieldOffset + (t, arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_staticFieldBase +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (classStaticTable + (t, jclassVmClass + (t, jfieldClazz(t, reinterpret_cast(arguments[1]))))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_objectFieldOffset +(Thread* t, object, uintptr_t* arguments) +{ + object jfield = reinterpret_cast(arguments[1]); + return fieldOffset + (t, arrayBody + (t, classFieldTable + (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getObjectVolatile +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + unsigned offset = arguments[2]; + object value = cast(o, offset); + loadMemoryBarrier(); + return reinterpret_cast(value); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapInt +(Thread*, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int32_t expect = arguments[4]; + int32_t update = arguments[5]; + + return __sync_bool_compare_and_swap + (&cast(target, offset), expect, update); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapLong +(Thread*, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int64_t expect; memcpy(&expect, arguments + 4, 8); + int64_t update; memcpy(&update, arguments + 6, 8); + + return __sync_bool_compare_and_swap + (&cast(target, offset), expect, update); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_allocateMemory +(Thread* t, object, uintptr_t* arguments) +{ + void* p = malloc(arguments[1]); + if (p) { + return reinterpret_cast(p); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::OutOfMemoryErrorType); + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_freeMemory +(Thread*, object, uintptr_t* arguments) +{ + void* p = reinterpret_cast(arguments[1]); + if (p) { + free(p); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getByte__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_ensureClassInitialized +(Thread* t, object, uintptr_t* arguments) +{ + initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_GetInterfaceVersion() +{ + return local::InterfaceVersion; +} + +extern "C" JNIEXPORT jint JNICALL +JVM_IHashCode(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + return objectHash(t, *o); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorWait(Thread* t, jobject o, jlong milliseconds) +{ + ENTER(t, Thread::ActiveState); + + vm::wait(t, *o, milliseconds); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorNotify(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + notify(t, *o); +} + +extern "C" JNIEXPORT void JNICALL +JVM_MonitorNotifyAll(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + notifyAll(t, *o); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_Clone(Thread* t, jobject o) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, clone(t, *o)); +} + +extern "C" JNIEXPORT jstring JNICALL +JVM_InternString(Thread* t, jstring s) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, intern(t, *s)); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_CurrentTimeMillis(Thread* t, jclass) +{ + return t->m->system->now(); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_NanoTime(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ArrayCopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, + jint dstOffset, jint length) +{ + ENTER(t, Thread::ActiveState); + + arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_InitProperties(Thread* t, jobject properties) +{ + ENTER(t, Thread::ActiveState); + + object method = resolveMethod + (t, t->m->loader, "java/util/Properties", "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); + + if (UNLIKELY(t->exception)) { + return 0; + } + + PROTECT(t, method); + +#ifdef PLATFORM_WINDOWS + local::setProperty(t, method, *properties, "line.separator", "\r\n"); + local::setProperty(t, method, *properties, "file.separator", "\\"); + local::setProperty(t, method, *properties, "path.separator", ";"); + local::setProperty(t, method, *properties, "os.name", "Windows"); + + TCHAR buffer[MAX_PATH]; + GetTempPath(MAX_PATH, buffer); + + local::setProperty(t, method, *properties, "java.io.tmpdir", buffer); + local::setProperty(t, method, *properties, "java.home", buffer); + local::setProperty(t, method, *properties, "user.home", + _wgetenv(L"USERPROFILE"), "%ls"); + + GetCurrentDirectory(MAX_PATH, buffer); + + local::setProperty(t, method, *properties, "user.dir", buffer); +#else + local::setProperty(t, method, *properties, "line.separator", "\n"); + local::setProperty(t, method, *properties, "file.separator", "/"); + local::setProperty(t, method, *properties, "path.separator", ":"); +# ifdef __APPLE__ + local::setProperty(t, method, *properties, "os.name", "Mac OS X"); +# else + local::setProperty(t, method, *properties, "os.name", "Linux"); +# endif + local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); + local::setProperty(t, method, *properties, "java.home", "/tmp"); + local::setProperty(t, method, *properties, "user.home", getenv("HOME")); + local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); + + // todo: set this to something sane: + local::setProperty(t, method, *properties, "sun.boot.library.path", + getenv("LD_LIBRARY_PATH")); + +#endif + local::setProperty(t, method, *properties, "file.encoding", "ASCII"); +#ifdef ARCH_x86_32 + local::setProperty(t, method, *properties, "os.arch", "x86"); +#elif defined ARCH_x86_64 + local::setProperty(t, method, *properties, "os.arch", "x86_64"); +#elif defined ARCH_powerpc + local::setProperty(t, method, *properties, "os.arch", "ppc"); +#elif defined ARCH_arm + local::setProperty(t, method, *properties, "os.arch", "arm"); +#else + local::setProperty(t, method, *properties, "os.arch", "unknown"); +#endif + + for (unsigned i = 0; i < t->m->propertyCount; ++i) { + const char* start = t->m->properties[i]; + const char* p = start; + while (*p and *p != '=') ++p; + + if (*p == '=') { + RUNTIME_ARRAY(char, name, (p - start) + 1); + memcpy(name, start, p - start); + name[p - start] = 0; + local::setProperty + (t, method, *properties, RUNTIME_ARRAY_BODY(name), p + 1); + } + } + + return properties; +} + +extern "C" JNIEXPORT void JNICALL +JVM_OnExit(void (*)(void)) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Exit(jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Halt(jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GC() +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + collect(t, Heap::MajorCollection); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_MaxObjectInspectionAge(void) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_TraceInstructions(jboolean) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_TraceMethodCalls(jboolean) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_TotalMemory(void) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_FreeMemory(void) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_MaxMemory(void) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ActiveProcessorCount(void) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +JVM_LoadLibrary(const char* name) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + return loadLibrary(t, name, false, false); +} + +extern "C" JNIEXPORT void JNICALL +JVM_UnloadLibrary(void*) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +JVM_FindLibraryEntry(void* library, const char* name) +{ + Thread* t = static_cast(local::globalMachine->localThread->get()); + + ENTER(t, Thread::ActiveState); + + return static_cast(library)->resolve(name); +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSupportedJNIVersion(jint version) +{ + return version <= JNI_VERSION_1_4; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsNaN(jdouble) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_FillInStackTrace(Thread* t, jobject throwable) +{ + ENTER(t, Thread::ActiveState); + + object trace = getTrace(t, 1); + set(t, *throwable, ThrowableTrace, trace); +} + +extern "C" JNIEXPORT void JNICALL +JVM_PrintStackTrace(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetStackTraceDepth(Thread* t, jobject throwable) +{ + ENTER(t, Thread::ActiveState); + + return arrayLength(t, throwableTrace(t, *throwable)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetStackTraceElement(Thread* t, jobject throwable, jint index) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, makeStackTraceElement + (t, arrayBody(t, throwableTrace(t, *throwable), index))); +} + +extern "C" JNIEXPORT void JNICALL +JVM_InitializeCompiler (Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSilentCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_CompileClass(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_CompileClasses(Thread*, jclass, jstring) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_CompilerCommand(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_EnableCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_DisableCompiler(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_StartThread(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + startThread(t, *thread); +} + +extern "C" JNIEXPORT void JNICALL +JVM_StopThread(Thread*, jobject, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsThreadAlive(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + Thread* p = reinterpret_cast(threadPeer(t, *thread)); + if (p) { + switch (p->state) { + case Thread::ActiveState: + case Thread::IdleState: + case Thread::ExclusiveState: + return true; + + case Thread::NoState: + case Thread::ZombieState: + case Thread::JoinedState: + case Thread::ExitState: + return false; + + default: + abort(t); + } + } else { + return false; + } +} + +extern "C" JNIEXPORT void JNICALL +JVM_SuspendThread(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ResumeThread(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetThreadPriority(Thread*, jobject, jint) +{ + // ignore +} + +extern "C" JNIEXPORT void JNICALL +JVM_Yield(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Sleep(Thread* t, jclass, jlong milliseconds) +{ + ENTER(t, Thread::ActiveState); + + if (threadSleepLock(t, t->javaThread) == 0) { + object lock = makeJobject(t); + set(t, t->javaThread, ThreadSleepLock, lock); + } + + acquire(t, threadSleepLock(t, t->javaThread)); + vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); + release(t, threadSleepLock(t, t->javaThread)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_CurrentThread(Thread* t, jclass) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, t->javaThread); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_CountStackFrames(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_Interrupt(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsInterrupted(Thread*, jobject, jboolean) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_HoldsLock(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_DumpAllStacks(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetAllThreads(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_DumpThreads(Thread*, jclass, jobjectArray) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_CurrentLoadedClass(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_CurrentClassLoader(Thread*) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassContext(Thread*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ClassDepth(Thread*, jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ClassLoaderDepth(Thread*) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetSystemPackage(Thread*, jstring) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetSystemPackages(Thread*) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_AllocateNewObject(Thread*, jobject, jclass, + jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_AllocateNewArray(Thread*, jobject, jclass, + jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_LatestUserDefinedLoader(Thread*) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_LoadClass0(Thread*, jobject, jclass, + jstring) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetArrayLength(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetArrayElement(Thread*, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jvalue JNICALL +JVM_GetPrimitiveArrayElement(Thread*, jobject, jint, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetArrayElement(Thread*, jobject, jint, jobject) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetPrimitiveArrayElement(Thread*, jobject, jint, jvalue, + unsigned char) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewArray(Thread* t, jclass elementClass, jint length) +{ + ENTER(t, Thread::ActiveState); + + object c = jclassVmClass(t, *elementClass); + + if (classVmFlags(t, c) & PrimitiveFlag) { + const char* name = reinterpret_cast + (&byteArrayBody(t, local::getClassName(t, c), 0)); + + switch (*name) { + case 'b': + if (name[1] == 'o') { + return makeLocalReference(t, makeBooleanArray(t, length)); + } else { + return makeLocalReference(t, makeByteArray(t, length)); + } + case 'c': return makeLocalReference(t, makeCharArray(t, length)); + case 'd': return makeLocalReference(t, makeDoubleArray(t, length)); + case 'f': return makeLocalReference(t, makeFloatArray(t, length)); + case 'i': return makeLocalReference(t, makeIntArray(t, length)); + case 'l': return makeLocalReference(t, makeLongArray(t, length)); + case 's': return makeLocalReference(t, makeShortArray(t, length)); + default: abort(t); + } + } else { + return makeLocalReference + (t, makeObjectArray(t, t->m->loader, c, length)); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewMultiArray(Thread*, jclass, jintArray) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_GetCallerClass(Thread* t, int target) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, getJClass(t, methodClass(t, getCaller(t, target)))); +} + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindPrimitiveClass(Thread* t, const char* name) +{ + ENTER(t, Thread::ActiveState); + + switch (*name) { + case 'b': + if (name[1] == 'o') { + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbooleanType))); + } else { + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbyteType))); + } + case 'c': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JcharType))); + case 'd': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JdoubleType))); + case 'f': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JfloatType))); + case 'i': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JintType))); + case 'l': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JlongType))); + case 's': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JshortType))); + case 'v': + return makeLocalReference + (t, getJClass(t, arrayBody(t, t->m->types, Machine::JvoidType))); + default: + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +JVM_ResolveClass(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, + jobject loader, jboolean throwError) +{ + ENTER(t, Thread::ActiveState); + + object c = resolveClass(t, loader ? *loader : t->m->loader, name); + if (t->exception) { + if (throwError) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoClassDefFoundErrorType, + throwableMessage(t, t->exception), + throwableTrace(t, t->exception), + throwableCause(t, t->exception)); + } + return 0; + } + + if (init) { + PROTECT(t, c); + + initClass(t, c); + } + + return makeLocalReference(t, getJClass(t, c)); +} + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindClassFromClass(Thread*, const char*, jboolean, + jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_FindLoadedClass(Thread*, jobject, jstring) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_DefineClass(Thread*, const char*, jobject, const jbyte*, + jsize, jobject) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_DefineClassWithSource(Thread*, const char*, jobject, + const jbyte*, jsize, jobject, + const char*) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetClassName(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, jclassName(t, *c)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassInterfaces(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object table = classInterfaceTable(t, jclassVmClass(t, *c)); + if (table) { + unsigned stride = + (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; + + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), + arrayLength(t, table) / stride); + PROTECT(t, array); + + for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { + object interface = getJClass(t, arrayBody(t, table, i * stride)); + set(t, array, ArrayBody + (i * BytesPerWord), interface); + } + + return makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), + 0)); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetClassLoader(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object loader = classLoader(t, jclassVmClass(t, *c)); + return loader == t->m->loader ? 0 : makeLocalReference(t, loader); +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsInterface(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) != 0; +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassSigners(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetClassSigners(Thread*, jclass, jobjectArray) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetProtectionDomain(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_SetProtectionDomain(Thread*, jclass, jobject) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsArrayClass(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classArrayDimensions(t, jclassVmClass(t, *c)) != 0; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsPrimitiveClass(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return (classVmFlags(t, jclassVmClass(t, *c)) & PrimitiveFlag) != 0; +} + +extern "C" JNIEXPORT jclass JNICALL +JVM_GetComponentType(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + uint8_t n = byteArrayBody(t, className(t, jclassVmClass(t, *c)), 1); + if (n != 'L' and n != '[') { + return makeLocalReference(t, getJClass(t, primitiveClass(t, n))); + } else { + return makeLocalReference + (t, getJClass(t, classStaticTable(t, jclassVmClass(t, *c)))); + } +} + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassModifiers(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return classFlags(t, jclassVmClass(t, *c)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetDeclaredClasses(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_GetDeclaringClass(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_GetClassSignature(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jbyteArray JNICALL +JVM_GetClassAnnotations(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, addendumAnnotationTable(t, classAddendum(t, jclassVmClass(t, *c)))); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JmethodType), + local::countMethods(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + PROTECT(t, vmMethod); + + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and byteArrayBody(t, methodName(t, vmMethod), 0) != '<') + { + object name = intern + (t, t->m->classpath->makeString + (t, methodName(t, vmMethod), 0, byteArrayLength + (t, methodName(t, vmMethod)) - 1)); + PROTECT(t, name); + + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, parameterTypes); + + object returnType = local::resolveJType + (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast + (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), + byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, returnType); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, exceptionTypes); + + object signature = t->m->classpath->makeString + (t, methodSpec(t, vmMethod), 0, byteArrayLength + (t, methodSpec(t, vmMethod)) - 1); + + object annotationTable = methodAddendum(t, vmMethod) == 0 + ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + + if (annotationTable) { + fprintf(stderr, "method %s.%s has annotations\n", + &byteArrayBody(t, className(t, jclassVmClass(t, *c)), 0), + &byteArrayBody(t, methodName(t, vmMethod), 0)); + + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + object method = makeJmethod + (t, true, *c, i, name, returnType, parameterTypes, exceptionTypes, + methodFlags(t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, + 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); + } + } + + return makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JmethodType), + 0)); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classFieldTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JfieldType), + local::countFields(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmField = arrayBody(t, table, i); + PROTECT(t, vmField); + + if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { + object name = intern + (t, t->m->classpath->makeString + (t, fieldName(t, vmField), 0, byteArrayLength + (t, fieldName(t, vmField)) - 1)); + PROTECT(t, name); + + object type = local::resolveClassBySpec + (t, classLoader(t, jclassVmClass(t, *c)), + reinterpret_cast + (&byteArrayBody(t, fieldSpec(t, vmField), 0)), + byteArrayLength(t, fieldSpec(t, vmField)) - 1); + + if (UNLIKELY(t->exception)) { + return 0; + } + + type = getJClass(t, type); + + object signature = t->m->classpath->makeString + (t, fieldSpec(t, vmField), 0, byteArrayLength + (t, fieldSpec(t, vmField)) - 1); + + object annotationTable = fieldAddendum(t, vmField) == 0 + ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); + + if (annotationTable) { + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + addendumPool(t, fieldAddendum(t, vmField))); + } + + object field = makeJfield + (t, true, *c, i, name, type, fieldFlags + (t, vmField), signature, 0, annotationTable, 0, 0, 0, 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), field); + } + } + + return makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JfieldType), 0)); + } +} + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) +{ + ENTER(t, Thread::ActiveState); + + object table = classMethodTable(t, jclassVmClass(t, *c)); + if (table) { + object array = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JconstructorType), + local::countConstructors(t, jclassVmClass(t, *c), publicOnly)); + PROTECT(t, array); + + unsigned ai = 0; + for (unsigned i = 0; i < arrayLength(t, table); ++i) { + object vmMethod = arrayBody(t, table, i); + PROTECT(t, vmMethod); + + if (((not publicOnly) or (methodFlags(t, vmMethod) & ACC_PUBLIC)) + and strcmp(reinterpret_cast + (&byteArrayBody(t, methodName(t, vmMethod), 0)), + "") == 0) + { + unsigned parameterCount; + unsigned returnTypeSpec; + object parameterTypes = local::resolveParameterJTypes + (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), + ¶meterCount, &returnTypeSpec); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, parameterTypes); + + object exceptionTypes = local::resolveExceptionJTypes + (t, classLoader(t, jclassVmClass(t, *c)), + methodAddendum(t, vmMethod)); + + if (UNLIKELY(t->exception)) return 0; + + PROTECT(t, exceptionTypes); + + object signature = t->m->classpath->makeString + (t, methodSpec(t, vmMethod), 0, byteArrayLength + (t, methodSpec(t, vmMethod)) - 1); + + object annotationTable = methodAddendum(t, vmMethod) == 0 + ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); + + if (annotationTable) { + set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + addendumPool(t, methodAddendum(t, vmMethod))); + } + + object method = makeJconstructor + (t, true, *c, i, parameterTypes, exceptionTypes, methodFlags + (t, vmMethod), signature, 0, annotationTable, 0, 0, 0, 0, 0); + + assert(t, ai < objectArrayLength(t, array)); + + set(t, array, ArrayBody + ((ai++) * BytesPerWord), method); + } + } + + return makeLocalReference(t, array); + } else { + return makeLocalReference + (t, makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JconstructorType), + 0)); + } +} + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassAccessFlags(Thread* t, jclass c) +{ + return JVM_GetClassModifiers(t, c); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_InvokeMethod(Thread* t, jobject method, jobject instance, + jobjectArray arguments) +{ + ENTER(t, Thread::ActiveState); + + object vmMethod = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jmethodClazz(t, *method))), + jmethodSlot(t, *method)); + + object result; + if (arguments) { + result = t->m->processor->invokeArray + (t, vmMethod, instance ? *instance : 0, *arguments); + } else { + result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); + } + + return result ? makeLocalReference(t, result) : 0; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_NewInstanceFromConstructor(Thread* t, jobject constructor, + jobjectArray arguments) +{ + ENTER(t, Thread::ActiveState); + + object instance = make + (t, jclassVmClass(t, jconstructorClazz(t, *constructor))); + PROTECT(t, instance); + + object method = arrayBody + (t, classMethodTable + (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), + jconstructorSlot(t, *constructor)); + + if (arguments) { + t->m->processor->invokeArray(t, method, instance, *arguments); + } else { + t->m->processor->invoke(t, method, instance); + } + + if (UNLIKELY(t->exception)) { + return 0; + } else { + return makeLocalReference(t, instance); + } +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetClassConstantPool(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference + (t, makeConstantPool + (t, addendumPool(t, classAddendum(t, jclassVmClass(t, *c))))); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_ConstantPoolGetSize(Thread* t, jobject, jobject pool) +{ + if (pool == 0) return 0; + + ENTER(t, Thread::ActiveState); + + return singletonCount(t, *pool); +} + +extern "C" JNIEXPORT jclass JNICALL +JVM_ConstantPoolGetClassAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jclass JNICALL +JVM_ConstantPoolGetClassAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetMethodAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetMethodAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetFieldAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_ConstantPoolGetFieldAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_ConstantPoolGetMemberRefInfoAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_ConstantPoolGetIntAt(Thread* t, jobject, jobject pool, jint index) +{ + ENTER(t, Thread::ActiveState); + + return singletonValue(t, *pool, index - 1); +} + +extern "C" JNIEXPORT jlong JNICALL +JVM_ConstantPoolGetLongAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jfloat JNICALL +JVM_ConstantPoolGetFloatAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jdouble JNICALL +JVM_ConstantPoolGetDoubleAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_ConstantPoolGetStringAt(Thread*, jobject, jobject, jint) { abort(); } + +extern "C" JNIEXPORT jstring JNICALL +JVM_ConstantPoolGetUTF8At(Thread* t, jobject, jobject pool, jint index) +{ + ENTER(t, Thread::ActiveState); + + object array = singletonObject(t, *pool, index - 1); + + return makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1)); +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_DoPrivileged +(Thread* t, jclass, jobject action, jobject, jboolean wrapException) +{ + ENTER(t, Thread::ActiveState); + + object privilegedAction = resolveClass + (t, t->m->loader, "java/security/PrivilegedAction"); + + if (UNLIKELY(t->exception)) { + return 0; + } + + object method; + if (instanceOf(t, privilegedAction, *action)) { + method = resolveMethod + (t, privilegedAction, "run", "()Ljava/lang/Object;"); + } else { + object privilegedExceptionAction = resolveClass + (t, t->m->loader, "java/security/PrivilegedExceptionAction"); + + if (UNLIKELY(t->exception)) { + return 0; + } + + method = resolveMethod + (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); + } + + if (LIKELY(t->exception == 0)) { + object result = t->m->processor->invoke(t, method, *action); + + if (LIKELY(t->exception == 0)) { + return makeLocalReference(t, result); + } else { + if (wrapException and not + (instanceOf + (t, arrayBody(t, t->m->types, Machine::ErrorType), t->exception) + or instanceOf + (t, arrayBody(t, t->m->types, Machine::RuntimeExceptionType), + t->exception))) + { + object cause = t->exception; + PROTECT(t, cause); + + t->exception = 0; + + object paeClass = resolveClass + (t, t->m->loader, "java/security/PrivilegedActionException"); + + if (LIKELY(t->exception == 0)) { + PROTECT(t, paeClass); + + object paeConstructor = resolveMethod + (t, paeClass, "", "(Ljava/lang/Exception;)V"); + PROTECT(t, paeConstructor); + + if (LIKELY(t->exception == 0)) { + object result = make(t, paeClass); + PROTECT(t, result); + + t->m->processor->invoke(t, paeConstructor, result, cause); + + if (LIKELY(t->exception == 0)) { + t->exception = result; + } + } + } + } + } + } + + return 0; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetInheritedAccessControlContext(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_GetStackAccessControlContext(Thread*, jclass) +{ + return 0; +} + +extern "C" JNIEXPORT void* JNICALL +JVM_RegisterSignal(jint, void*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_RaiseSignal(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_FindSignal(const char*) +{ + return -1; +} + +extern "C" JNIEXPORT jboolean JNICALL +JVM_DesiredAssertionStatus(Thread*, jclass, jclass) +{ + return false; +} + +extern "C" JNIEXPORT jobject JNICALL +JVM_AssertionStatusDirectives(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_SupportsCX8(void) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetClassNameUTF(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetClassCPTypes(Thread*, jclass, unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassCPEntriesCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassFieldsCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetClassMethodsCount(Thread*, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionIndexes(Thread*, jclass, jint, + unsigned short*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionsCount(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxByteCode(Thread*, jclass, jint, + unsigned char*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxByteCodeLength(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetMethodIxExceptionTableEntry(Thread*, jclass, jint, + jint, + local::JVM_ExceptionTableEntryType*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxExceptionTableLength(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetFieldIxModifiers(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxModifiers(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxLocalsCount(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxArgsSize(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetMethodIxMaxStack(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsConstructorIx(Thread*, jclass, int) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetMethodIxNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetMethodIxSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldSignatureUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPFieldClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT const char* JNICALL +JVM_GetCPMethodClassNameUTF(Thread*, jclass, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetCPFieldModifiers(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetCPMethodModifiers(Thread*, jclass, int, jclass) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_ReleaseUTF(const char*) { abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +JVM_IsSameClassPackage(Thread*, jclass, jclass) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetLastErrorString(char* dst, int length) +{ + strncpy(dst, strerror(errno), length); + return strlen(dst); +} + +extern "C" JNIEXPORT char* JNICALL +JVM_NativePath(char* path) +{ + return path; +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Open(const char* name, jint flags, jint mode) +{ + return OPEN(name, flags, mode); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Close(jint fd) +{ + return CLOSE(fd); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Read(jint fd, char* dst, jint length) +{ + return READ(fd, dst, length); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Write(jint fd, char* src, jint length) +{ + return WRITE(fd, src, length); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_Available(jint, jlong*) { abort(); } + +extern "C" JNIEXPORT jlong JNICALL +JVM_Lseek(jint fd, jlong offset, jint start) +{ + return LSEEK(fd, offset, start); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_SetLength(jint, jlong) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Sync(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_InitializeSocketLibrary(void) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Socket(jint, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketClose(jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketShutdown(jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Recv(jint, char*, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Send(jint, char*, jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Timeout(int, long) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Listen(jint, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Connect(jint, struct sockaddr*, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Bind(jint, struct sockaddr*, jint) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_Accept(jint, struct sockaddr*, jint*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_RecvFrom(jint, char*, int, + int, struct sockaddr*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SendTo(jint, char*, int, + int, struct sockaddr*, int) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SocketAvailable(jint, jint*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetSockName(jint, struct sockaddr*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_GetSockOpt(jint, int, int, char*, int*) { abort(); } + +extern "C" JNIEXPORT jint JNICALL +JVM_SetSockOpt(jint, int, int, const char*, int) { abort(); } + +extern "C" JNIEXPORT struct protoent* JNICALL +JVM_GetProtoByName(char*) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +JVM_GetHostByAddr(const char*, int, int) { abort(); } + +extern "C" JNIEXPORT struct hostent* JNICALL +JVM_GetHostByName(char*) { abort(); } + +extern "C" JNIEXPORT int JNICALL +JVM_GetHostName(char*, int) { abort(); } + +extern "C" JNIEXPORT void* JNICALL +JVM_RawMonitorCreate(void) +{ + System* s = local::globalMachine->system; + System::Monitor* lock; + if (s->success(s->make(&lock))) { + return lock; + } else { + return 0; + } +} + +extern "C" JNIEXPORT void JNICALL +JVM_RawMonitorDestroy(void* lock) +{ + static_cast(lock)->dispose(); +} + +extern "C" JNIEXPORT jint JNICALL +JVM_RawMonitorEnter(void* lock) +{ + static_cast(lock)->acquire + (static_cast + (local::globalMachine->localThread->get())->systemThread); + + return 0; +} + +extern "C" JNIEXPORT void JNICALL +JVM_RawMonitorExit(void* lock) +{ + static_cast(lock)->release + (static_cast + (local::globalMachine->localThread->get())->systemThread); +} + +extern "C" JNIEXPORT void* JNICALL +JVM_GetManagement(jint) { abort(); } + +extern "C" JNIEXPORT jobject JNICALL +JVM_InitAgentProperties(Thread*, jobject) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetEnclosingMethodInfo(JNIEnv*, jclass) { abort(); } + +extern "C" JNIEXPORT jintArray JNICALL +JVM_GetThreadStateValues(JNIEnv*, jint) { abort(); } + +extern "C" JNIEXPORT jobjectArray JNICALL +JVM_GetThreadStateNames(JNIEnv*, jint, jintArray) { abort(); } + +extern "C" JNIEXPORT void JNICALL +JVM_GetVersionInfo(JNIEnv*, local::jvm_version_info*, size_t) { abort(); } + +extern "C" JNIEXPORT int +jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) +{ + return vm::vsnprintf(dst, size, format, a); +} + +extern "C" JNIEXPORT int +jio_snprintf(char* dst, size_t size, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vsnprintf(dst, size, format, a); + + va_end(a); + + return r; +} + +extern "C" JNIEXPORT int +jio_vfprintf(FILE* stream, const char* format, va_list a) +{ + return vfprintf(stream, format, a); +} + +extern "C" JNIEXPORT int +jio_fprintf(FILE* stream, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vfprintf(stream, format, a); + + va_end(a); + + return r; +} diff --git a/src/common.h b/src/common.h index 1a672feb6d..316eeef81c 100644 --- a/src/common.h +++ b/src/common.h @@ -465,6 +465,16 @@ replace(char a, char b, char* c) for (; *c; ++c) if (*c == a) *c = b; } +inline void +replace(char a, char b, char* dst, const char* src) +{ + unsigned i = 0; + for (; src[i]; ++ i) { + dst[i] = src[i] == a ? b : src[i]; + } + dst[i] = 0; +} + class Machine; class Thread; diff --git a/src/compile-x86.S b/src/compile-x86.S index 7dd9349f40..9e86527444 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -22,7 +22,7 @@ #ifdef __x86_64__ -#define THREAD_STACK 2216 +#define THREAD_STACK 2224 #if defined __MINGW32__ || defined __CYGWIN32__ diff --git a/src/compile.cpp b/src/compile.cpp index a35fa98905..5619dd0769 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -40,7 +40,7 @@ namespace { namespace local { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -259,10 +259,10 @@ object findMethod(Thread* t, object method, object instance) { if ((methodFlags(t, method) & ACC_STATIC) == 0) { - if (methodVirtual(t, method)) { - return findVirtualMethod(t, method, objectClass(t, instance)); - } else if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { + if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { return findInterfaceMethod(t, method, objectClass(t, instance)); + } else if (methodVirtual(t, method)) { + return findVirtualMethod(t, method, objectClass(t, instance)); } } return method; @@ -2142,7 +2142,8 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) return methodAddress(t, target); } } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2414,7 +2415,8 @@ makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length) (makeObjectArray(t, loader, class_, length)); } else { object message = makeString(t, "%d", length); - t->exception = makeNegativeArraySizeException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } } @@ -2463,7 +2465,8 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length) return reinterpret_cast(constructor(t, length)); } else { object message = makeString(t, "%d", length); - t->exception = makeNegativeArraySizeException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } } @@ -2497,7 +2500,8 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) if (LIKELY(o)) { set(t, o, offset, value); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2508,7 +2512,8 @@ acquireMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { acquire(t, o); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2519,7 +2524,8 @@ releaseMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { release(t, o); } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2535,7 +2541,8 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1]; if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { object message = makeString(t, "%d", RUNTIME_ARRAY_BODY(counts)[i]); - t->exception = makeNegativeArraySizeException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); return 0; } } @@ -2589,7 +2596,8 @@ throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { t->tracing = true; - t->exception = makeArrayIndexOutOfBoundsException(t, 0); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType); t->tracing = false; } else { // not enough memory available for a new exception and stack trace @@ -2606,7 +2614,8 @@ throw_(MyThread* t, object o) if (LIKELY(o)) { t->exception = o; } else { - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } // printTrace(t, t->exception); @@ -2622,7 +2631,8 @@ checkCast(MyThread* t, object class_, object o) (t, "%s as %s", &byteArrayBody(t, className(t, objectClass(t, o)), 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeClassCastException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassCastExceptionType, message); unwind(t); } } @@ -6125,34 +6135,32 @@ resolveNative(MyThread* t, object method) initClass(t, methodClass(t, method)); - if (LIKELY(t->exception == 0) - and unresolved(t, methodCompiled(t, method))) - { - void* function = resolveNativeMethod(t, method); - if (UNLIKELY(function == 0)) { + if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { + object native = resolveNativeMethod(t, method); + if (UNLIKELY(native == 0)) { object message = makeString (t, "%s.%s%s", &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); return; } - // ensure other threads see updated methodVmFlags before - // methodCompiled, since we don't want them using the slow calling - // convention on a function that expects the fast calling - // convention: + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: storeStoreMemoryBarrier(); - methodCompiled(t, method) = reinterpret_cast(function); + set(t, method, MethodCode, native); } } uint64_t -invokeNativeFast(MyThread* t, object method) +invokeNativeFast(MyThread* t, object method, void* function) { - return reinterpret_cast(methodCompiled(t, method)) + return reinterpret_cast(function) (t, method, static_cast(t->stack) + t->arch->frameFooterSize() @@ -6160,7 +6168,7 @@ invokeNativeFast(MyThread* t, object method) } uint64_t -invokeNativeSlow(MyThread* t, object method) +invokeNativeSlow(MyThread* t, object method, void* function) { PROTECT(t, method); @@ -6232,7 +6240,6 @@ invokeNativeSlow(MyThread* t, object method) } } - void* function = reinterpret_cast(methodCompiled(t, method)); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); uint64_t result; @@ -6247,7 +6254,7 @@ invokeNativeSlow(MyThread* t, object method) if (methodFlags(t, method) & ACC_STATIC) { acquire(t, methodClass(t, method)); } else { - acquire(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[0])); + acquire(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } @@ -6268,7 +6275,7 @@ invokeNativeSlow(MyThread* t, object method) if (methodFlags(t, method) & ACC_STATIC) { release(t, methodClass(t, method)); } else { - release(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[0])); + release(t, *reinterpret_cast(RUNTIME_ARRAY_BODY(args)[1])); } } @@ -6327,10 +6334,11 @@ invokeNativeSlow(MyThread* t, object method) uint64_t invokeNative2(MyThread* t, object method) { - if (methodVmFlags(t, method) & FastNative) { - return invokeNativeFast(t, method); + object native = methodCode(t, method); + if (nativeFast(t, native)) { + return invokeNativeFast(t, method, nativeFunction(t, native)); } else { - return invokeNativeSlow(t, method); + return invokeNativeSlow(t, method, nativeFunction(t, native)); } } @@ -6829,7 +6837,8 @@ callContinuation(MyThread* t, object continuation, object result, action = Call; } } else { - t->exception = makeIncompatibleContinuationException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IncompatibleContinuationExceptionType); action = Throw; } } else { @@ -7165,7 +7174,8 @@ class SegFaultHandler: public System::SignalHandler { if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { t->tracing = true; - t->exception = makeNullPointerException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); t->tracing = false; } else { // not enough memory available for a new NPE and stack trace @@ -7269,6 +7279,7 @@ class MyProcessor: public Processor { t->init(); if (false) { + fprintf(stderr, "%d\n", difference(&(t->stack), t)); fprintf(stderr, "%d\n", difference(&(t->continuation), t)); fprintf(stderr, "%d\n", difference(&(t->exception), t)); fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); @@ -7518,7 +7529,7 @@ class MyProcessor: public Processor { assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); - unsigned size = parameterFootprint(t, methodSpec, false); + unsigned size = parameterFootprint(t, methodSpec, this_ == 0); RUNTIME_ARRAY(uintptr_t, array, size); RUNTIME_ARRAY(bool, objectMask, size); ArgumentList list @@ -7765,6 +7776,31 @@ class MyProcessor: public Processor { abort(t); } } + + virtual void registerNative(Thread* t, object method, void* function) { + PROTECT(t, method); + + expect(t, methodFlags(t, method) & ACC_NATIVE); + + object native = makeNative(t, function, false); + + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, native); + } + + virtual void unregisterNatives(Thread* t, object c) { + if (classMethodTable(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object method = arrayBody(t, classMethodTable(t, c), i); + if (methodFlags(t, method) & ACC_NATIVE) { + set(t, method, MethodCode, 0); + } + } + } + } System* s; Allocator* allocator; diff --git a/src/continuations-x86.S b/src/continuations-x86.S index c55679d0ba..5dc0ba9e10 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 2224 +#define THREAD_CONTINUATION 2232 #define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232 -#define THREAD_EXCEPTION_OFFSET 2240 -#define THREAD_EXCEPTION_HANDLER 2248 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2240 +#define THREAD_EXCEPTION_OFFSET 2248 +#define THREAD_EXCEPTION_HANDLER 2256 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 diff --git a/src/interpret.cpp b/src/interpret.cpp index 28754a0a3b..7d362c27d9 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -509,7 +509,9 @@ resolveNativeMethodData(Thread* t, object method) &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = makeUnsatisfiedLinkError(t, message); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); } } } @@ -524,7 +526,8 @@ checkStack(Thread* t, object method) + codeMaxStack(t, methodCode(t, method)) > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); } } @@ -680,15 +683,15 @@ invokeNativeSlow(Thread* t, object method) &byteArrayBody(t, methodName(t, method), 0)); } -// if (strcmp(reinterpret_cast -// (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), -// "org/eclipse/swt/internal/C") == 0 -// and strcmp(reinterpret_cast -// (&byteArrayBody(t, methodName(t, method), 0)), -// "memmove") == 0) -// { -// asm("int3"); -// } + // if (strcmp(reinterpret_cast + // (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), + // "org/eclipse/swt/internal/C") == 0 + // and strcmp(reinterpret_cast + // (&byteArrayBody(t, methodName(t, method), 0)), + // "memmove") == 0) + // { + // asm("int3"); + // } { ENTER(t, Thread::IdleState); @@ -931,13 +934,15 @@ interpret(Thread* t) { pushObject(t, objectArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - objectArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + object message = makeString + (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -953,13 +958,15 @@ interpret(Thread* t) { set(t, array, ArrayBody + (index * BytesPerWord), value); } else { - object message = makeString(t, "%d not in [0,%d)", index, - objectArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + object message = makeString + (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1002,7 +1009,8 @@ interpret(Thread* t) class_, count)); } else { object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } goto loop; @@ -1023,7 +1031,8 @@ interpret(Thread* t) if (LIKELY(array)) { pushInt(t, cast(array, BytesPerWord)); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1051,7 +1060,8 @@ interpret(Thread* t) case athrow: { exception = popObject(t); if (UNLIKELY(exception == 0)) { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } goto throw_; @@ -1071,7 +1081,8 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { @@ -1083,12 +1094,15 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1110,7 +1124,8 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { @@ -1121,12 +1136,14 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1147,11 +1164,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1169,11 +1188,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1191,7 +1212,8 @@ interpret(Thread* t) &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); - exception = makeClassCastException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ClassCastExceptionType, message); goto throw_; } } @@ -1228,11 +1250,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1250,11 +1274,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1428,11 +1454,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1450,11 +1478,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1566,7 +1596,8 @@ interpret(Thread* t) } } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1658,11 +1689,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1687,11 +1720,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1958,7 +1993,8 @@ interpret(Thread* t) (t, method, objectClass(t, peekObject(t, sp - parameterFootprint))); goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1983,7 +2019,8 @@ interpret(Thread* t) goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2014,7 +2051,8 @@ interpret(Thread* t) code = findVirtualMethod(t, method, class_); goto invoke; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2150,11 +2188,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2179,11 +2219,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2413,7 +2455,8 @@ interpret(Thread* t) if (LIKELY(o)) { acquire(t, o); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2423,7 +2466,8 @@ interpret(Thread* t) if (LIKELY(o)) { release(t, o); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2441,7 +2485,8 @@ interpret(Thread* t) counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { object message = makeString(t, "%d", counts[i]); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } @@ -2514,7 +2559,8 @@ interpret(Thread* t) pushObject(t, array); } else { object message = makeString(t, "%d", count); - exception = makeNegativeArraySizeException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } } goto loop; @@ -2576,7 +2622,8 @@ interpret(Thread* t) break; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2587,7 +2634,8 @@ interpret(Thread* t) if (LIKELY(o)) { cast(o, fieldOffset(t, field)) = value; } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2597,7 +2645,8 @@ interpret(Thread* t) if (LIKELY(o)) { set(t, o, fieldOffset(t, field), value); } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } } break; @@ -2727,11 +2776,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2749,11 +2800,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = makeArrayIndexOutOfBoundsException(t, message); + exception = t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = makeNullPointerException(t); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -3195,7 +3248,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } @@ -3220,7 +3274,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } @@ -3244,7 +3299,8 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) > Thread::StackSizeInWords / 2)) { - t->exception = makeStackOverflowError(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::StackOverflowErrorType); return 0; } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index a7b7b0cb6f..532819b0d1 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -156,6 +156,49 @@ ReleaseStringChars(Thread* t, jstring s, const jchar* chars) t->m->heap->free(chars, (stringLength(t, *s) + 1) * sizeof(jchar)); } +void JNICALL +GetStringRegion(Thread* t, jstring s, jsize start, jsize length, jchar* dst) +{ + ENTER(t, Thread::ActiveState); + + stringChars(t, *s, start, length, dst); +} + +const jchar* JNICALL +GetStringCritical(Thread* t, jstring s, jboolean* isCopy) +{ + if ((t->criticalLevel ++) == 0) { + enter(t, Thread::ActiveState); + } + + if (isCopy) { + *isCopy = true; + } + + object data = stringData(t, *s); + if (objectClass(t, data) + == arrayBody(t, t->m->types, Machine::ByteArrayType)) + { + return GetStringChars(t, s, isCopy); + } else { + return &charArrayBody(t, data, stringOffset(t, *s)); + } +} + +void JNICALL +ReleaseStringCritical(Thread* t, jstring s, const jchar* chars) +{ + if (objectClass(t, stringData(t, *s)) + == arrayBody(t, t->m->types, Machine::ByteArrayType)) + { + ReleaseStringChars(t, s, chars); + } + + if ((-- t->criticalLevel) == 0) { + enter(t, Thread::IdleState); + } +} + jsize JNICALL GetStringUTFLength(Thread* t, jstring s) { @@ -186,6 +229,15 @@ ReleaseStringUTFChars(Thread* t, jstring s, const char* chars) t->m->heap->free(chars, stringLength(t, *s) + 1); } +void JNICALL +GetStringUTFRegion(Thread* t, jstring s, jsize start, jsize length, char* dst) +{ + ENTER(t, Thread::ActiveState); + + stringUTFChars + (t, *s, start, length, dst, stringUTFLength(t, *s, start, length)); +} + jsize JNICALL GetArrayLength(Thread* t, jarray array) { @@ -206,9 +258,8 @@ NewString(Thread* t, const jchar* chars, jsize size) a = makeCharArray(t, size); memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } - object s = makeString(t, a, 0, size, 0); - return makeLocalReference(t, s); + return makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size)); } jstring JNICALL @@ -218,15 +269,11 @@ NewStringUTF(Thread* t, const char* chars) ENTER(t, Thread::ActiveState); - object a = 0; - unsigned size = strlen(chars); - if (size) { - a = makeByteArray(t, size); - memcpy(&byteArrayBody(t, a, 0), chars, size); - } - object s = makeString(t, a, 0, size, 0); + object array = parseUtf8(t, chars, strlen(chars)); - return makeLocalReference(t, s); + return makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1)); } void @@ -240,6 +287,19 @@ replace(int a, int b, const char* in, int8_t* out) *out = 0; } +jclass JNICALL +DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, + jsize length) +{ + ENTER(t, Thread::ActiveState); + + object c = defineClass + (t, loader ? *loader : t->m->loader, + reinterpret_cast(buffer), length); + + return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); +} + jclass JNICALL FindClass(Thread* t, const char* name) { @@ -279,6 +339,20 @@ ThrowNew(Thread* t, jclass c, const char* message) return 0; } +jint JNICALL +Throw(Thread* t, jthrowable throwable) +{ + if (t->exception) { + return -1; + } + + ENTER(t, Thread::ActiveState); + + t->exception = *throwable; + + return 0; +} + void JNICALL DeleteLocalRef(Thread* t, jobject r) { @@ -329,6 +403,14 @@ IsInstanceOf(Thread* t, jobject o, jclass c) return instanceOf(t, jclassVmClass(t, *c), *o); } +jboolean JNICALL +IsAssignableFrom(Thread* t, jclass a, jclass b) +{ + ENTER(t, Thread::ActiveState); + + return isAssignableFrom(t, jclassVmClass(t, *a), jclassVmClass(t, *b)); +} + object findMethod(Thread* t, jclass c, const char* name, const char* spec) { @@ -362,7 +444,10 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec) ENTER(t, Thread::ActiveState); object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) { + printTrace(t, t->exception); + return 0; + } assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); @@ -1116,7 +1201,7 @@ SetStaticObjectField(Thread* t, jclass c, jfieldID field, jobject v) { ENTER(t, Thread::ActiveState); - set(t, classStaticTable(t, *c), field, (v ? *v : 0)); + set(t, classStaticTable(t, jclassVmClass(t, *c)), field, (v ? *v : 0)); } void JNICALL @@ -1222,6 +1307,12 @@ DeleteGlobalRef(Thread* t, jobject r) } } +jint JNICALL +EnsureLocalCapacity(Thread*, jint) +{ + return 0; +} + jthrowable JNICALL ExceptionOccurred(Thread* t) { @@ -1832,6 +1923,34 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) } } +jint JNICALL +RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, + jint methodCount) +{ + ENTER(t, Thread::ActiveState); + + for (int i = 0; i < methodCount; ++i) { + if (methods[i].function) { + object method = findMethod(t, c, methods[i].name, methods[i].signature); + if (UNLIKELY(t->exception)) return -1; + + t->m->processor->registerNative(t, method, methods[i].function); + } + } + + return 0; +} + +jint JNICALL +UnregisterNatives(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + t->m->processor->unregisterNatives(t, *c); + + return 0; +} + jint JNICALL MonitorEnter(Thread* t, jobject o) { @@ -1948,14 +2067,20 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->GetStringLength = local::GetStringLength; envTable->GetStringChars = local::GetStringChars; envTable->ReleaseStringChars = local::ReleaseStringChars; + envTable->GetStringRegion = local::GetStringRegion; + envTable->GetStringCritical = local::GetStringCritical; + envTable->ReleaseStringCritical = local::ReleaseStringCritical; envTable->GetStringUTFLength = local::GetStringUTFLength; envTable->GetStringUTFChars = local::GetStringUTFChars; envTable->ReleaseStringUTFChars = local::ReleaseStringUTFChars; + envTable->GetStringUTFRegion = local::GetStringUTFRegion; envTable->GetArrayLength = local::GetArrayLength; envTable->NewString = local::NewString; envTable->NewStringUTF = local::NewStringUTF; + envTable->DefineClass = local::DefineClass; envTable->FindClass = local::FindClass; envTable->ThrowNew = local::ThrowNew; + envTable->Throw = local::Throw; envTable->ExceptionCheck = local::ExceptionCheck; #ifdef AVIAN_GNU envTable->NewDirectByteBuffer = vm::NewDirectByteBuffer; @@ -1969,6 +2094,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; envTable->IsInstanceOf = local::IsInstanceOf; + envTable->IsAssignableFrom = local::IsAssignableFrom; envTable->GetFieldID = local::GetFieldID; envTable->GetMethodID = local::GetMethodID; envTable->GetStaticMethodID = local::GetStaticMethodID; @@ -2054,6 +2180,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->NewGlobalRef = local::NewGlobalRef; envTable->NewWeakGlobalRef = local::NewGlobalRef; envTable->DeleteGlobalRef = local::DeleteGlobalRef; + envTable->EnsureLocalCapacity = local::EnsureLocalCapacity; envTable->ExceptionOccurred = local::ExceptionOccurred; envTable->ExceptionDescribe = local::ExceptionDescribe; envTable->ExceptionClear = local::ExceptionClear; @@ -2103,6 +2230,8 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->GetPrimitiveArrayCritical = local::GetPrimitiveArrayCritical; envTable->ReleasePrimitiveArrayCritical = local::ReleasePrimitiveArrayCritical; + envTable->RegisterNatives = local::RegisterNatives; + envTable->UnregisterNatives = local::UnregisterNatives; envTable->MonitorEnter = local::MonitorEnter; envTable->MonitorExit = local::MonitorExit; envTable->GetJavaVM = local::GetJavaVM; @@ -2201,6 +2330,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) Heap* h = makeHeap(s, heapLimit); Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary); Processor* p = makeProcessor(s, h, true); + Classpath* c = makeClasspath(s, h); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); @@ -2212,11 +2342,14 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } *m = new (h->allocate(sizeof(Machine))) - Machine(s, h, f, p, properties, propertyCount); + Machine(s, h, f, p, c, properties, propertyCount); *t = p->makeThread(*m, 0, 0); enter(*t, Thread::ActiveState); + + c->boot(*t); + enter(*t, Thread::IdleState); return 0; diff --git a/src/machine.cpp b/src/machine.cpp index 0b4ddcb461..e1d2af8ec6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -196,10 +196,12 @@ turnOffTheLights(Thread* t) System* s = m->system; Heap* h = m->heap; Processor* p = m->processor; + Classpath* c = m->classpath; Finder* f = m->finder; m->dispose(); h->disposeFixies(); + c->dispose(); p->dispose(); h->dispose(); f->dispose(); @@ -227,23 +229,6 @@ killZombies(Thread* t, Thread* o) } } -object -makeJavaThread(Thread* t, Thread* parent) -{ - object group; - if (parent) { - group = threadGroup(t, parent->javaThread); - } else { - group = makeThreadGroup(t, 0, 0, 0); - } - - const unsigned NewState = 0; - const unsigned NormalPriority = 5; - - return makeThread - (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, group); -} - unsigned footprint(Thread* t) { @@ -377,13 +362,12 @@ referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p) object q = jreferenceQueue(t, *p); - set(t, *p, JreferenceJNext, *p); if (referenceQueueFront(t, q)) { - set(t, referenceQueueRear(t, q), JreferenceJNext, *p); + set(t, *p, JreferenceJNext, referenceQueueFront(t, q)); } else { - set(t, q, ReferenceQueueFront, *p); + set(t, *p, JreferenceJNext, *p); } - set(t, q, ReferenceQueueRear, *p); + set(t, q, ReferenceQueueFront, *p); jreferenceQueue(t, *p) = 0; } @@ -793,8 +777,8 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) parsePoolEntry(t, s, index, pool, si); object value = singletonObject(t, pool, si); - value = makeString - (t, value, 0, cast(value, BytesPerWord) - 1, 0); + value = t->m->classpath->makeString + (t, value, 0, cast(value, BytesPerWord) - 1); value = intern(t, value); set(t, pool, SingletonBody + (i * BytesPerWord), value); } @@ -1046,7 +1030,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - addendum = makeAddendum(t, pool, body); + addendum = makeFieldAddendum(t, pool, body); } else { s.skip(length); } @@ -1082,9 +1066,8 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) classVmFlags(t, class_) |= HasFinalMemberFlag; } - unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord; - if (excess) { - memberOffset += BytesPerWord - excess; + while (memberOffset % fieldSize(t, code)) { + ++ memberOffset; } fieldOffset(t, field) = memberOffset; @@ -1392,14 +1375,29 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) &byteArrayBody(t, name, 0)) == 0) { code = parseCode(t, s, pool); + } else if (vm::strcmp(reinterpret_cast("Exceptions"), + &byteArrayBody(t, name, 0)) == 0) + { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0); + } + unsigned exceptionCount = s.read2(); + object body = makeShortArray(t, exceptionCount); + for (unsigned i = 0; i < exceptionCount; ++i) { + shortArrayBody(t, body, i) = s.read2(); + } + set(t, addendum, MethodAddendumExceptionTable, body); } else if (vm::strcmp(reinterpret_cast ("RuntimeVisibleAnnotations"), &byteArrayBody(t, name, 0)) == 0) { + if (addendum == 0) { + addendum = makeMethodAddendum(t, pool, 0, 0); + } object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - addendum = makeAddendum(t, pool, body); + set(t, addendum, AddendumAnnotationTable, body); } else { s.skip(length); } @@ -1549,7 +1547,6 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) if (abstractVirtuals) { PROTECT(t, vtable); - PROTECT(t, abstractVirtuals); unsigned oldLength = arrayLength(t, classMethodTable(t, class_)); object newMethodTable = makeArray @@ -1673,8 +1670,7 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) // verify that the classes have the same layout expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_)); - expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType) - or classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); + expect(t, classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_)); expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0); @@ -2079,8 +2075,8 @@ class HeapClient: public Heap::Client { namespace vm { Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor, const char** properties, - unsigned propertyCount): + Processor* processor, Classpath* classpath, + const char** properties, unsigned propertyCount): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) @@ -2088,6 +2084,7 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, heap(heap), finder(finder), processor(processor), + classpath(classpath), rootThread(0), exclusive(0), finalizeThread(0), @@ -2199,7 +2196,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): backupHeapIndex(0), useBackupHeap(false), waiting(false), - tracing(false) + tracing(false), + daemon(false) #ifdef VM_STRESS , stress(false) #endif // VM_STRESS @@ -2248,10 +2246,11 @@ Thread::init() m->jniMethodTable = makeVector(this, 0, 0); - m->nullPointerException = makeNullPointerException(this); + m->nullPointerException = m->classpath->makeThrowable + (this, Machine::NullPointerExceptionType); - m->arrayIndexOutOfBoundsException - = makeArrayIndexOutOfBoundsException(this, 0); + m->arrayIndexOutOfBoundsException = m->classpath->makeThrowable + (this, Machine::IndexOutOfBoundsExceptionType); m->localThread->set(this); } else { @@ -2262,7 +2261,7 @@ Thread::init() expect(this, m->system->success(m->system->make(&lock))); if (javaThread == 0) { - this->javaThread = makeJavaThread(this, parent); + this->javaThread = m->classpath->makeThread(this, parent); } threadPeer(this, javaThread) = reinterpret_cast(this); @@ -2365,6 +2364,7 @@ enter(Thread* t, Thread::State s) return; } + #ifdef USE_ATOMIC_OPERATIONS # define INCREMENT atomicIncrement # define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock) @@ -2408,6 +2408,24 @@ enter(Thread* t, Thread::State s) } break; case Thread::IdleState: + // The java.lang.Thread implementation may or may not notify the + // VM when the daemon field in the Java object changes, so we sync + // up the native field whenever the thread transitions to idle: + if (t->daemon != threadDaemon(t, t->javaThread)) { + ACQUIRE_LOCK; + + t->daemon = threadDaemon(t, t->javaThread); + + if (t->daemon) { + ++ t->m->daemonCount; + } else { + expect(t, t->m->daemonCount); + -- t->m->daemonCount; + } + + t->m->stateLock->notifyAll(t->systemThread); + } + if (t->state == Thread::ActiveState) { // fast path assert(t, t->m->activeCount > 0); @@ -2420,6 +2438,7 @@ enter(Thread* t, Thread::State s) t->m->stateLock->notifyAll(t->systemThread); } + break; } else { // fall through to slow path @@ -2692,91 +2711,98 @@ makeString(Thread* t, const char* format, ...) object s = ::makeByteArray(t, format, a); va_end(a); - return makeString(t, s, 0, byteArrayLength(t, s) - 1, 0); + return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); } - int -stringUTFLength(Thread* t, object string) { - int length = 0; +stringUTFLength(Thread* t, object string, unsigned start, unsigned length) +{ + unsigned result = 0; - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) { - length = stringLength(t, string); + == arrayBody(t, t->m->types, Machine::ByteArrayType)) + { + result = length; } else { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i); - if (!c) length += 1; // null char (was 2 bytes in Java) - else if (c < 0x80) length += 1; // ASCII char - else if (c < 0x800) length += 2; // two-byte char - else length += 3; // three-byte char + for (unsigned i = 0; i < length; ++i) { + uint16_t c = charArrayBody + (t, data, stringOffset(t, string) + start + i); + if (c == 0) result += 1; // null char (was 2 bytes in Java) + else if (c < 0x80) result += 1; // ASCII char + else if (c < 0x800) result += 2; // two-byte char + else result += 3; // three-byte char } } } - return length; + return result; } void -stringChars(Thread* t, object string, char* chars) +stringChars(Thread* t, object string, unsigned start, unsigned length, + char* chars) { - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); if (objectClass(t, data) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { memcpy(chars, - &byteArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string)); + &byteArrayBody(t, data, stringOffset(t, string) + start), + length); } else { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - chars[i] = charArrayBody(t, data, stringOffset(t, string) + i); + for (unsigned i = 0; i < length; ++i) { + chars[i] = charArrayBody(t, data, stringOffset(t, string) + start + i); } } } - chars[stringLength(t, string)] = 0; + chars[length] = 0; } void -stringChars(Thread* t, object string, uint16_t* chars) +stringChars(Thread* t, object string, unsigned start, unsigned length, + uint16_t* chars) { - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); if (objectClass(t, data) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { - for (unsigned i = 0; i < stringLength(t, string); ++i) { - chars[i] = byteArrayBody(t, data, stringOffset(t, string) + i); + for (unsigned i = 0; i < length; ++i) { + chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i); } } else { memcpy(chars, - &charArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string) * sizeof(uint16_t)); + &charArrayBody(t, data, stringOffset(t, string) + start), + length * sizeof(uint16_t)); } } - chars[stringLength(t, string)] = 0; + chars[length] = 0; } void -stringUTFChars(Thread* t, object string, char* chars, unsigned length UNUSED) +stringUTFChars(Thread* t, object string, unsigned start, unsigned length, + char* chars, unsigned charsLength UNUSED) { - assert(t, static_cast(stringUTFLength(t, string)) == length); + assert(t, static_cast + (stringUTFLength(t, string, start, length)) == charsLength); - if (stringLength(t, string)) { + if (length) { object data = stringData(t, string); if (objectClass(t, data) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { memcpy(chars, - &byteArrayBody(t, data, stringOffset(t, string)), - stringLength(t, string)); - chars[stringLength(t, string)] = 0; + &byteArrayBody(t, data, stringOffset(t, string) + start), + length); + chars[length] = 0; } else { int j = 0; - for (unsigned i = 0; i < stringLength(t, string); ++i) { - uint16_t c = charArrayBody(t, data, stringOffset(t, string) + i); + for (unsigned i = 0; i < length; ++i) { + uint16_t c = charArrayBody + (t, data, stringOffset(t, string) + start + i); if(!c) { // null char chars[j++] = 0; } else if (c < 0x80) { // ASCII char @@ -3118,7 +3144,8 @@ resolveSystemClass(Thread* t, object spec) hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash); } else if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassNotFoundExceptionType, message); } } @@ -3191,7 +3218,8 @@ resolveClass(Thread* t, object loader, object spec) byteArrayHash); } else if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeClassNotFoundException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassNotFoundExceptionType, message); } return class_; @@ -3216,7 +3244,8 @@ resolveMethod(Thread* t, object class_, const char* methodName, (t, "%s %s not found in %s", methodName, methodSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeNoSuchMethodError(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoSuchMethodErrorType, message); return 0; } else { return method; @@ -3246,7 +3275,8 @@ resolveField(Thread* t, object class_, const char* fieldName, (t, "%s %s not found in %s", fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeNoSuchFieldError(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoSuchFieldErrorType, message); return 0; } else { return field; @@ -3324,7 +3354,9 @@ preInitClass(Thread* t, object c) } else if (classVmFlags(t, c) & InitErrorFlag) { object message = makeString (t, "%s", &byteArrayBody(t, className(t, c), 0)); - t->exception = makeNoClassDefFoundError(t, message); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::NoClassDefFoundErrorType, message); } else { classVmFlags(t, c) |= InitFlag; return true; @@ -3341,7 +3373,9 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { - t->exception = makeExceptionInInitializerError(t, t->exception); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); + classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; } else { @@ -3412,7 +3446,7 @@ findInTable(Thread* t, object table, object name, object spec, object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - object (*makeError)(Thread*, object)) + Machine::Type errorType) { object originalClass = class_; @@ -3440,7 +3474,7 @@ findInHierarchy(Thread* t, object class_, object name, object spec, &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), &byteArrayBody(t, className(t, originalClass), 0)); - t->exception = makeError(t, message); + t->exception = t->m->classpath->makeThrowable(t, errorType, message); } return o; @@ -3596,7 +3630,7 @@ collect(Thread* t, Heap::CollectionType type) if (m->objectsToFinalize and m->finalizeThread == 0) { m->finalizeThread = m->processor->makeThread - (m, makeJavaThread(t, m->rootThread), m->rootThread); + (m, t->m->classpath->makeThread(t, m->rootThread), m->rootThread); if (not t->m->system->success (m->system->start(&(m->finalizeThread->runnable)))) @@ -3695,7 +3729,8 @@ void printTrace(Thread* t, object exception) { if (exception == 0) { - exception = makeNullPointerException(t, 0, makeTrace(t), 0); + exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); } for (object e = exception; e; e = throwableCause(t, e)) { @@ -3738,6 +3773,10 @@ printTrace(Thread* t, object exception) fprintf(stderr, "(line %d)\n", line); } } + + if (e == throwableCause(t, e)) { + break; + } } } @@ -3792,17 +3831,6 @@ makeTrace(Thread* t, Thread* target) return v.trace ? v.trace : makeArray(t, 0); } -void -runJavaThread(Thread* t) -{ - object method = resolveMethod - (t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); - - if (t->exception == 0) { - t->m->processor->invoke(t, method, 0, t->javaThread); - } -} - void runFinalizeThread(Thread* t) { @@ -3833,6 +3861,47 @@ runFinalizeThread(Thread* t) } } +object +parseUtf8(Thread* t, const char* data, unsigned length) +{ + class Client: public Stream::Client { + public: + Client(Thread* t): t(t) { } + + virtual void NO_RETURN handleError() { + vm::abort(t); + } + + private: + Thread* t; + } client(t); + + Stream s(&client, reinterpret_cast(data), length); + + return ::parseUtf8(t, s, length); +} + +object +defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) +{ + PROTECT(t, loader); + + object c = parseClass(t, loader, buffer, length); + + if (c) { + PROTECT(t, c); + if (getClassLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c, + byteArrayHash); + } + + return c; +} + void noop() { } @@ -3857,7 +3926,7 @@ vmPrintTrace(Thread* t) int line = t->m->processor->lineNumber (t, walker->method(), walker->ip()); - fprintf(stderr, " at %s.%s ", class_, method); + fprintf(stderr, " at %s.%s (%x) ", class_, method, walker->ip()); switch (line) { case NativeLine: diff --git a/src/machine.h b/src/machine.h index b406a455ca..cc2394a757 100644 --- a/src/machine.h +++ b/src/machine.h @@ -97,7 +97,6 @@ const unsigned ContinuationFlag = 1 << 11; const unsigned ClassInitFlag = 1 << 0; const unsigned CompiledFlag = 1 << 1; const unsigned ConstructorFlag = 1 << 2; -const unsigned FastNative = 1 << 3; #ifndef JNI_VERSION_1_6 #define JNI_VERSION_1_6 0x00010006 @@ -1151,6 +1150,8 @@ class Reference { unsigned count; }; +class Classpath; + class Machine { public: enum Type { @@ -1164,7 +1165,8 @@ class Machine { }; Machine(System* system, Heap* heap, Finder* finder, Processor* processor, - const char** properties, unsigned propertyCount); + Classpath* classpath, const char** properties, + unsigned propertyCount); ~Machine() { dispose(); @@ -1178,6 +1180,7 @@ class Machine { Heap* heap; Finder* finder; Processor* processor; + Classpath* classpath; Thread* rootThread; Thread* exclusive; Thread* finalizeThread; @@ -1371,11 +1374,45 @@ class Thread { bool useBackupHeap; bool waiting; bool tracing; -#ifdef VM_STRESS + bool daemon; bool stress; -#endif // VM_STRESS }; +class Classpath { + public: + virtual object + makeJclass(Thread* t, object class_) = 0; + + virtual object + makeString(Thread* t, object array, int32_t offset, int32_t length) = 0; + + virtual object + makeThread(Thread* t, Thread* parent) = 0; + + virtual void + runThread(Thread* t) = 0; + + virtual object + makeThrowable + (Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) = 0; + + virtual void + boot(Thread* t) = 0; + + virtual void + dispose() = 0; +}; + +inline void +runJavaThread(Thread* t) +{ + t->m->classpath->runThread(t); +} + +Classpath* +makeClasspath(System* system, Allocator* allocator); + typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); inline object @@ -1731,160 +1768,10 @@ makeTrace(Thread* t) return makeTrace(t, t); } -inline object -makeRuntimeException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeRuntimeException(t, message, trace, 0); -} - -inline object -makeIllegalStateException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeIllegalStateException(t, message, trace, 0); -} - -inline object -makeIllegalArgumentException(Thread* t) -{ - return makeIllegalArgumentException(t, 0, makeTrace(t), 0); -} - -inline object -makeIllegalMonitorStateException(Thread* t) -{ - return makeIllegalMonitorStateException(t, 0, makeTrace(t), 0); -} - -inline object -makeIndexOutOfBoundsException(Thread* t) -{ - return makeIndexOutOfBoundsException(t, 0, makeTrace(t), 0); -} - -inline object -makeArrayIndexOutOfBoundsException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeArrayIndexOutOfBoundsException(t, message, trace, 0); -} - -inline object -makeArrayStoreException(Thread* t) -{ - return makeArrayStoreException(t, 0, makeTrace(t), 0); -} - -inline object -makeNegativeArraySizeException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNegativeArraySizeException(t, message, trace, 0); -} - -inline object -makeClassCastException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeClassCastException(t, message, trace, 0); -} - -inline object -makeClassNotFoundException(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeClassNotFoundException(t, message, trace, 0, 0); -} - -inline object -makeNullPointerException(Thread* t) -{ - return makeNullPointerException(t, 0, makeTrace(t), 0); -} - -inline object -makeInvocationTargetException(Thread* t, object targetException) -{ - PROTECT(t, targetException); - object trace = makeTrace(t); - return makeRuntimeException(t, 0, trace, targetException); -} - -inline object -makeInterruptedException(Thread* t) -{ - return makeInterruptedException(t, 0, makeTrace(t), 0); -} - -inline object -makeIncompatibleContinuationException(Thread* t) -{ - return makeIncompatibleContinuationException(t, 0, makeTrace(t), 0); -} - -inline object -makeStackOverflowError(Thread* t) -{ - return makeStackOverflowError(t, 0, makeTrace(t), 0); -} - -inline object -makeNoSuchFieldError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoSuchFieldError(t, message, trace, 0); -} - -inline object -makeNoSuchMethodError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoSuchMethodError(t, message, trace, 0); -} - -inline object -makeNoClassDefFoundError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeNoClassDefFoundError(t, message, trace, 0); -} - -inline object -makeUnsatisfiedLinkError(Thread* t, object message) -{ - PROTECT(t, message); - object trace = makeTrace(t); - return makeUnsatisfiedLinkError(t, message, trace, 0); -} - -inline object -makeExceptionInInitializerError(Thread* t, object cause) -{ - PROTECT(t, cause); - object trace = makeTrace(t); - return makeExceptionInInitializerError(t, 0, trace, cause, cause); -} - -inline object -makeIncompatibleClassChangeError(Thread* t) -{ - return makeIncompatibleClassChangeError(t, 0, makeTrace(t), 0); -} - inline object makeNew(Thread* t, object class_) { - assert(t, t->state == Thread::ActiveState); + assert(t, t->state == Thread::NoState or t->state == Thread::ActiveState); PROTECT(t, class_); unsigned sizeInBytes = pad(classFixedSize(t, class_)); @@ -1917,16 +1804,43 @@ object makeString(Thread* t, const char* format, ...); int -stringUTFLength(Thread* t, object string); +stringUTFLength(Thread* t, object string, unsigned start, unsigned length); + +inline int +stringUTFLength(Thread* t, object string) +{ + return stringUTFLength(t, string, 0, stringLength(t, string)); +} void -stringChars(Thread* t, object string, char* chars); +stringChars(Thread* t, object string, unsigned start, unsigned length, + char* chars); + +inline void +stringChars(Thread* t, object string, char* chars) +{ + stringChars(t, string, 0, stringLength(t, string), chars); +} void -stringChars(Thread* t, object string, uint16_t* chars); +stringChars(Thread* t, object string, unsigned start, unsigned length, + uint16_t* chars); + +inline void +stringChars(Thread* t, object string, uint16_t* chars) +{ + stringChars(t, string, 0, stringLength(t, string), chars); +} void -stringUTFChars(Thread* t, object string, char* chars, unsigned length); +stringUTFChars(Thread* t, object string, unsigned start, unsigned length, + char* chars, unsigned charsLength); + +inline void +stringUTFChars(Thread* t, object string, char* chars, unsigned charsLength) +{ + stringUTFChars(t, string, 0, stringLength(t, string), chars, charsLength); +} bool isAssignableFrom(Thread* t, object a, object b); @@ -2159,6 +2073,9 @@ emptyMethod(Thread* t, object method) and (codeBody(t, methodCode(t, method), 0) == return_); } +object +parseUtf8(Thread* t, const char* data, unsigned length); + object parseClass(Thread* t, object loader, const uint8_t* data, unsigned length); @@ -2264,13 +2181,13 @@ findMethodInClass(Thread* t, object class_, object name, object spec) object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - object (*makeError)(Thread*, object)); + Machine::Type errorType); inline object findMethod(Thread* t, object class_, object name, object spec) { return findInHierarchy - (t, class_, name, spec, findMethodInClass, makeNoSuchMethodError); + (t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType); } inline object @@ -2690,10 +2607,12 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - t->exception = makeInterruptedException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::InterruptedExceptionType); } } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { @@ -2722,7 +2641,8 @@ notify(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } } @@ -2739,7 +2659,8 @@ notifyAll(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { - t->exception = makeIllegalMonitorStateException(t); + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalMonitorStateExceptionType); } } @@ -2756,6 +2677,7 @@ setDaemon(Thread* t, object thread, bool daemon) if ((threadDaemon(t, thread) != 0) != daemon) { threadDaemon(t, thread) = daemon; + t->daemon = daemon; if (daemon) { ++ t->m->daemonCount; @@ -2947,7 +2869,7 @@ resolveClassInPool(Thread* t, object method, unsigned index) inline object resolve(Thread* t, object loader, object method, unsigned index, object (*find)(vm::Thread*, object, object, object), - object (*makeError)(vm::Thread*, object)) + Machine::Type errorType) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) @@ -2962,7 +2884,7 @@ resolve(Thread* t, object loader, object method, unsigned index, o = findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), - find, makeError); + find, errorType); if (UNLIKELY(t->exception)) return 0; set(t, codePool(t, methodCode(t, method)), @@ -2976,7 +2898,7 @@ inline object resolveField(Thread* t, object loader, object method, unsigned index) { return resolve(t, loader, method, index, findFieldInClass, - makeNoSuchFieldError); + Machine::NoSuchFieldErrorType); } inline object @@ -2990,7 +2912,7 @@ inline object resolveMethod(Thread* t, object loader, object method, unsigned index) { return resolve(t, loader, method, index, findMethodInClass, - makeNoSuchMethodError); + Machine::NoSuchMethodErrorType); } inline object @@ -3004,6 +2926,8 @@ inline object getJClass(Thread* t, object c) { if (classAddendum(t, c) == 0) { + PROTECT(t, c); + ACQUIRE(t, t->m->classLock); object addendum = makeClassAddendum(t, 0, 0, 0, 0); @@ -3013,9 +2937,11 @@ getJClass(Thread* t, object c) object jclass = classAddendumClass(t, classAddendum(t, c)); if (jclass == 0) { + PROTECT(t, c); + ACQUIRE(t, t->m->classLock); - jclass = makeJclass(t, c); + jclass = t->m->classpath->makeJclass(t, c); set(t, classAddendum(t, c), ClassAddendumClass, jclass); } @@ -3023,6 +2949,29 @@ getJClass(Thread* t, object c) return jclass; } +inline object +primitiveClass(Thread* t, char name) +{ + switch (name) { + case 'B': return arrayBody(t, t->m->types, Machine::JbyteType); + case 'C': return arrayBody(t, t->m->types, Machine::JcharType); + case 'D': return arrayBody(t, t->m->types, Machine::JdoubleType); + case 'F': return arrayBody(t, t->m->types, Machine::JfloatType); + case 'I': return arrayBody(t, t->m->types, Machine::JintType); + case 'J': return arrayBody(t, t->m->types, Machine::JlongType); + case 'S': return arrayBody(t, t->m->types, Machine::JshortType); + case 'V': return arrayBody(t, t->m->types, Machine::JvoidType); + case 'Z': return arrayBody(t, t->m->types, Machine::JbooleanType); + default: + t->exception = t->m->classpath->makeThrowable + (t, Machine::IllegalArgumentExceptionType); + return 0; + } +} + +object +defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); + void dumpHeap(Thread* t, FILE* out); diff --git a/src/posix.cpp b/src/posix.cpp index 0d34e2828a..a40d555334 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -755,7 +755,7 @@ class MySystem: public System { return 0; } else { -// fprintf(stderr, "dlerror: %s\n", dlerror()); + fprintf(stderr, "dlerror: %s\n", dlerror()); return 1; } } diff --git a/src/process.cpp b/src/process.cpp index e4897dcaf0..090d253170 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -207,18 +207,17 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, namespace vm { -void* +object resolveNativeMethod(Thread* t, object method) { void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3); if (p) { - methodVmFlags(t, method) |= FastNative; - return p; + return makeNative(t, p, true); } p = ::resolveNativeMethod(t, method, "Java_", 5, -1); if (p) { - return p; + return makeNative(t, p, false); } return 0; diff --git a/src/process.h b/src/process.h index 95da97cde8..ae1f2831fa 100644 --- a/src/process.h +++ b/src/process.h @@ -56,7 +56,7 @@ isSpecialMethod(Thread* t, object method, object class_) and isSuperclass(t, methodClass(t, method), class_); } -void* +object resolveNativeMethod(Thread* t, object method); inline void diff --git a/src/processor.h b/src/processor.h index 398b2d930b..8cff2b0782 100644 --- a/src/processor.h +++ b/src/processor.h @@ -153,6 +153,10 @@ class Processor { walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) = 0; + virtual void registerNative(Thread* t, object method, void* function) = 0; + + virtual void unregisterNatives(Thread* t, object c) = 0; + object invoke(Thread* t, object method, object this_, ...) { diff --git a/src/system.h b/src/system.h index fb3b85df80..a58d3bba73 100644 --- a/src/system.h +++ b/src/system.h @@ -87,7 +87,7 @@ class System { class Library { public: - virtual void* resolve(const char* function) = 0; + virtual void* resolve(const char* symbol) = 0; virtual const char* name() = 0; virtual bool mapName() = 0; virtual Library* next() = 0; diff --git a/src/type-generator.cpp b/src/type-generator.cpp index fc0fb72061..0e8a6bc758 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -400,6 +400,8 @@ class Array : public Scalar { o->typeName = typeName; o->name = name; o->elementSize = elementSize; + o->noassert = false; + o->nogc = false; return o; } }; @@ -455,7 +457,7 @@ memberTypeName(Object* o) } } -const char* +const char*& memberName(Object* o) { switch (o->type) { @@ -987,8 +989,11 @@ class MemberIterator { offset_ += padding_; -// printf("size: %d; padding: %d; alignment: %d; offset: %d;\n", -// size_, padding_, alignment_, offset_); +// fprintf(stderr, +// "type: %s; member: %s; size: %d; padding: %d; alignment: %d;" +// " offset: %d;\n", +// typeName(type), memberName(member), size_, padding_, alignment_, +// offset_); return member; } @@ -1087,6 +1092,27 @@ parseArray(Object* t, Object* p, Object* declarations) typeName, name, sizeOf(typeName, declarations)); } +Object* +parseMember(Object* t, Object* p, Object* declarations); + +Object* +parseMember(Object* t, Object* p, Object* declarations, bool* isNew) +{ + Object* member = parseMember(t, p, declarations); + for (MemberIterator it(t); it.hasMore();) { + Object* m = it.next(); + if (equal(memberName(m), memberName(member))) { + if (not equal(memberTypeName(m), memberTypeName(member))) { + abort(); + } + *isNew = false; + return m; + } + } + *isNew = true; + return member; +} + Object* parseMember(Object* t, Object* p, Object* declarations) { @@ -1094,13 +1120,24 @@ parseMember(Object* t, Object* p, Object* declarations) if (equal(spec, "array")) { return parseArray(t, cdr(p), declarations); } else if (equal(spec, "noassert")) { - Object* member = parseMember(t, cdr(p), declarations); + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); memberNoAssert(member) = true; - return member; + return isNew ? member : 0; } else if (equal(spec, "nogc")) { - Object* member = parseMember(t, cdr(p), declarations); + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); memberNoGC(member) = true; - return member; + return isNew ? member : 0; + } else if (equal(spec, "require")) { + bool isNew; + Object* member = parseMember(t, cdr(p), declarations, &isNew); + return isNew ? member : 0; + } else if (equal(spec, "alias")) { + bool isNew; + Object* member = parseMember(t, cdr(cdr(p)), declarations, &isNew); + memberName(member) = string(car(cdr(p))); + return isNew ? member : 0; } else { return Scalar::make(t, declaration(spec, declarations), spec, string(car(cdr(p))), @@ -1120,7 +1157,9 @@ parseSubdeclaration(Object* t, Object* p, Object* declarations) assert(typeSuper(t)->type == Object::Type); } else { Object* member = parseMember(t, p, declarations); - addMember(t, member); + if (member) { + addMember(t, member); + } } } @@ -1311,14 +1350,6 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) Object* member = Scalar::make (type, 0, memberType, name, sizeOf(memberType, declarations)); - if (equal(typeJavaName(type), "java/lang/ref/Reference") - and (equal(name, "vmNext") - or equal(name, "target") - or equal(name, "queue"))) - { - memberNoGC(member) = true; - } - addMember(type, member); } } @@ -1379,8 +1410,10 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, parseSubdeclaration(t, car(p), declarations); } else { Object* member = parseMember(t, car(p), declarations); - assert(member->type == Object::Scalar); - addMember(t, member); + if (member) { + assert(member->type == Object::Scalar); + addMember(t, member); + } } } diff --git a/src/types.def b/src/types.def index 143252e352..bdf13bf0fb 100644 --- a/src/types.def +++ b/src/types.def @@ -3,7 +3,18 @@ (type class avian/VMClass (array void* vtable)) -(type jclass java/lang/Class) +(type jclass java/lang/Class + (require object vmClass)) + +(type jaccessibleObject java/lang/reflect/AccessibleObject) + +(type jfield java/lang/reflect/Field) + +(type jmethod java/lang/reflect/Method) + +(type jconstructor java/lang/reflect/Constructor) + +(type constantPool sun/reflect/ConstantPool) (type singleton (array uintptr_t body)) @@ -22,6 +33,10 @@ (type classAddendum avian/ClassAddendum) +(type methodAddendum avian/MethodAddendum) + +(type fieldAddendum avian/FieldAddendum) + (type nativeMethodData (void* function) (uint16_t argumentTableSize) @@ -30,6 +45,10 @@ (type pointer (void* value)) +(type native + (void* function) + (uint8_t fast)) + (pod exceptionHandler (uint16_t start) (uint16_t end) @@ -142,15 +161,23 @@ (type callbackReceiver avian/CallbackReceiver) -(type string java/lang/String) +(type string java/lang/String + (alias data object value) + (alias length uint32_t count) + (alias hashCode uint32_t hash)) -(type thread java/lang/Thread) +(type thread java/lang/Thread + (require object sleepLock) + (require uint8_t interrupted) + (alias peer uint64_t eetop)) (type threadGroup java/lang/ThreadGroup) (type stackTraceElement java/lang/StackTraceElement) -(type throwable java/lang/Throwable) +(type throwable java/lang/Throwable + (alias message object detailMessage) + (alias trace object backtrace)) (type exception java/lang/Exception) @@ -184,6 +211,8 @@ (type virtualMachineError java/lang/VirtualMachineError) +(type outOfMemoryError java/lang/OutOfMemoryError) + (type stackOverflowError java/lang/StackOverflowError) (type linkageError java/lang/LinkageError) @@ -221,9 +250,17 @@ (type double java/lang/Double) -(type referenceQueue java/lang/ref/ReferenceQueue) +(type referenceQueue java/lang/ref/ReferenceQueue + (alias front object head)) -(type jreference java/lang/ref/Reference) +(type jreference java/lang/ref/Reference + (alias target object referent) + (alias queue object queue) + (alias jNext object next) + (alias vmNext object discovered) + (nogc object target) + (nogc object queue) + (nogc object vmNext)) (type weakReference java/lang/ref/WeakReference) diff --git a/test/test.sh b/test/test.sh index 55b4ff54a6..786c9e24c0 100644 --- a/test/test.sh +++ b/test/test.sh @@ -4,6 +4,7 @@ log=build/log.txt vg="nice valgrind --leak-check=full --num-callers=32 \ --freelist-vol=100000000 --error-exitcode=1" +library_path=${1}; shift vm=${1}; shift mode=${1}; shift flags=${1}; shift @@ -18,10 +19,11 @@ for test in ${tests}; do case ${mode} in debug|debug-fast|fast|small ) - ${vm} ${flags} ${test} >>${log} 2>&1;; + LD_LIBRARY_PATH=${library_path} ${vm} ${flags} ${test} >>${log} 2>&1;; stress* ) - ${vg} ${vm} ${flags} ${test} >>${log} 2>&1;; + LD_LIBRARY_PATH=${library_path} ${vg} ${vm} ${flags} ${test} \ + >>${log} 2>&1;; * ) echo "unknown mode: ${mode}" >&2 From b62d07996f52e7d7fbcf43469e51f92ff0930123 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Sep 2010 17:44:53 -0600 Subject: [PATCH 026/274] avoid including path name of libjvm.so in avian-dynamic --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index d388a28570..87567a58ab 100644 --- a/makefile +++ b/makefile @@ -741,7 +741,7 @@ ifdef msvc -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(^) $(lflags) -o $(@) + $(ld) $(<) -L$(native-build) -ljvm $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) From ea2509666a3c4785c30bf5d8de20b33ecb77b877 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Sep 2010 17:45:52 -0600 Subject: [PATCH 027/274] reverse operands when calling builtin isAssignableFrom Our builtin function reverses the meanings of the operands relative to the JNI method. --- src/jnienv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 532819b0d1..02c7af652e 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -404,7 +404,7 @@ IsInstanceOf(Thread* t, jobject o, jclass c) } jboolean JNICALL -IsAssignableFrom(Thread* t, jclass a, jclass b) +IsAssignableFrom(Thread* t, jclass b, jclass a) { ENTER(t, Thread::ActiveState); From 66280458c8c8d25f7db33c3a0a3b422624b2ede8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Sep 2010 17:47:23 -0600 Subject: [PATCH 028/274] implement more JVM_* methods --- src/classpath-openjdk.cpp | 74 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 39c6592bc9..29c8866250 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -10,6 +10,7 @@ #include "machine.h" #include "classpath-common.h" +#include "util.h" // todo: move platform-specific stuff into system.h and implementations @@ -711,7 +712,10 @@ JVM_CurrentTimeMillis(Thread* t, jclass) } extern "C" JNIEXPORT jlong JNICALL -JVM_NanoTime(Thread*, jclass) { abort(); } +JVM_NanoTime(Thread* t, jclass) +{ + return t->m->system->now() * 1000 * 1000; +} extern "C" JNIEXPORT void JNICALL JVM_ArrayCopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, @@ -1030,7 +1034,27 @@ extern "C" JNIEXPORT jobject JNICALL JVM_CurrentClassLoader(Thread*) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassContext(Thread*) { abort(); } +JVM_GetClassContext(Thread* t) +{ + ENTER(t, Thread::ActiveState); + + object trace = getTrace(t, 1); + PROTECT(t, trace); + + object context = makeObjectArray + (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), + arrayLength(t, trace)); + PROTECT(t, context); + + for (unsigned i = 0; i < arrayLength(t, trace); ++i) { + object c = getJClass + (t, methodClass(t, traceElementMethod(t, arrayBody(t, trace, i)))); + + set(t, context, ArrayBody + (i * BytesPerWord), c); + } + + return makeLocalReference(t, context); +} extern "C" JNIEXPORT jint JNICALL JVM_ClassDepth(Thread*, jstring) { abort(); } @@ -1196,7 +1220,32 @@ JVM_FindClassFromClass(Thread*, const char*, jboolean, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_FindLoadedClass(Thread*, jobject, jstring) { abort(); } +JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) +{ + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->classLock); + + object spec = makeByteArray(t, stringLength(t, *name) + 1); + { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); + stringChars(t, *name, s); + replace('.', '/', s); + } + + object c; + if (loader == 0 or *loader == t->m->loader) { + c = findLoadedSystemClass(t, spec); + } else { + object map = classLoaderMap(t, *loader); + if (map) { + c = hashMapFind(t, map, spec, byteArrayHash, byteArrayEqual); + } else { + c = 0; + } + } + + return c ? makeLocalReference(t, getJClass(t, c)) : 0; +} extern "C" JNIEXPORT jclass JNICALL JVM_DefineClass(Thread*, const char*, jobject, const jbyte*, @@ -1790,7 +1839,10 @@ extern "C" JNIEXPORT jobject JNICALL JVM_AssertionStatusDirectives(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_SupportsCX8(void) { abort(); } +JVM_SupportsCX8() +{ + return true; +} extern "C" JNIEXPORT const char* JNICALL JVM_GetClassNameUTF(Thread*, jclass) { abort(); } @@ -1924,7 +1976,19 @@ JVM_Write(jint fd, char* src, jint length) } extern "C" JNIEXPORT jint JNICALL -JVM_Available(jint, jlong*) { abort(); } +JVM_Available(jint fd, jlong* result) +{ + int current = LSEEK(fd, 0, SEEK_CUR); + if (current == -1) return 0; + + int end = LSEEK(fd, 0, SEEK_END); + if (end == -1) return 0; + + if (LSEEK(fd, current, SEEK_SET) == -1) return 0; + + *result = end - current; + return 1; +} extern "C" JNIEXPORT jlong JNICALL JVM_Lseek(jint fd, jlong offset, jint start) From fc2c6d5100e2c0ee0ee2242e3a27520365dd50e5 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 13:28:29 +0200 Subject: [PATCH 029/274] implement toLowerCase(Locale) in the default case --- classpath/java/lang/String.java | 40 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 143c60fd72..9362822b65 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -236,19 +236,31 @@ public final class String } public String toLowerCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toLowerCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toLowerCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toLowerCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public String toUpperCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toUpperCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toUpperCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toUpperCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public int indexOf(int c) { @@ -581,11 +593,19 @@ public final class String } public String toUpperCase(Locale locale) { - throw new UnsupportedOperationException(); + if (locale == Locale.ENGLISH) { + return toUpperCase(); + } else { + throw new UnsupportedOperationException("toUpperCase("+locale+')'); + } } public String toLowerCase(Locale locale) { - throw new UnsupportedOperationException(); + if (locale == Locale.ENGLISH) { + return toLowerCase(); + } else { + throw new UnsupportedOperationException("toLowerCase("+locale+')'); + } } public static String format(Locale locale, String format, Object ... args) { From 5dadac2cb8b7ceb387600d5098007fb635e5a057 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 14:01:33 +0200 Subject: [PATCH 030/274] API additions for compatibility with harmony's java.util package --- classpath/java/io/ObjectInputStream.java | 4 ++ classpath/java/io/ObjectOutputStream.java | 4 ++ classpath/java/util/Arrays.java | 6 +++ classpath/java/util/Collections.java | 21 +++++++++ .../util/ConcurrentModificationException.java | 47 +++++++++++++++++++ classpath/java/util/HashMap.java | 4 +- classpath/java/util/Map.java | 2 +- classpath/java/util/TreeMap.java | 5 +- classpath/java/util/WeakHashMap.java | 4 +- 9 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 classpath/java/util/ConcurrentModificationException.java diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 001a192a73..8447e10efa 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -79,6 +79,10 @@ public class ObjectInputStream extends InputStream { read('d'); return readDoubleToken(); } + + public void defaultReadObject() throws IOException { + throw new UnsupportedOperationException(); + } private void skipSpace() throws IOException { int c; diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 42d080f676..90743a5b32 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -82,6 +82,10 @@ public class ObjectOutputStream extends OutputStream { out.print(v); } + public void defaultWriteObject() throws IOException { + throw new UnsupportedOperationException(); + } + private void writeObject(Object o, IdentityHashMap map, int nextId) throws IOException diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index 8206988d90..cf05144d7d 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -148,5 +148,11 @@ public class Arrays { array[i] = value; } } + + public static void fill(T[] array, T value) { + for (int i=0;i (c.iterator()); } + public static Comparator reverseOrder(Comparator cmp) { + return new ReverseComparator(cmp); + } + static class IteratorEnumeration implements Enumeration { private final Iterator it; @@ -379,4 +384,20 @@ public class Collections { it.remove(); } } + + private static final class ReverseComparator implements Comparator { + + Comparator cmp; + + public ReverseComparator(Comparator cmp) { + this.cmp = cmp; + } + + @Override + public int compare(T o1, T o2) { + return - cmp.compare(o1, o2); + } + + } + } diff --git a/classpath/java/util/ConcurrentModificationException.java b/classpath/java/util/ConcurrentModificationException.java new file mode 100644 index 0000000000..28fe2bf7ee --- /dev/null +++ b/classpath/java/util/ConcurrentModificationException.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2010, 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.util; + +/** + * @author zsombor + * + */ +public class ConcurrentModificationException extends RuntimeException { + + /** + * @param message + * @param cause + */ + public ConcurrentModificationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public ConcurrentModificationException(String message) { + super(message); + } + + /** + * @param cause + */ + public ConcurrentModificationException(Throwable cause) { + super(cause); + } + + /** + * + */ + public ConcurrentModificationException() { + } + +} diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index c0a8a2474a..0f00f920b2 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -269,8 +269,10 @@ public class HashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { diff --git a/classpath/java/util/Map.java b/classpath/java/util/Map.java index 5b58bbb4f9..cd20bbc809 100644 --- a/classpath/java/util/Map.java +++ b/classpath/java/util/Map.java @@ -40,6 +40,6 @@ public interface Map { public V getValue(); - public void setValue(V value); + public V setValue(V value); } } diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java index 686e9ffda3..b3141422cd 100644 --- a/classpath/java/util/TreeMap.java +++ b/classpath/java/util/TreeMap.java @@ -112,9 +112,12 @@ public class TreeMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } + } private class KeySet implements Set { diff --git a/classpath/java/util/WeakHashMap.java b/classpath/java/util/WeakHashMap.java index d8fdbc7968..81365b9816 100644 --- a/classpath/java/util/WeakHashMap.java +++ b/classpath/java/util/WeakHashMap.java @@ -114,8 +114,10 @@ public class WeakHashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { From 6985e8150385ccb16e77549c4b1f0726839075e2 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 14:28:09 +0200 Subject: [PATCH 031/274] add Properties.load(Reader) implementation --- classpath/java/util/Properties.java | 45 +++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 749869823b..1ff67dcf16 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -14,10 +14,15 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.IOException; +import java.io.Reader; public class Properties extends Hashtable { public void load(InputStream in) throws IOException { - new Parser().parse(in, this); + new InputStreamParser(in).parse(this); + } + + public void load(Reader reader) throws IOException { + new ReaderParser(reader).parse(this); } public void store(OutputStream out, String comment) throws IOException { @@ -53,7 +58,7 @@ public class Properties extends Hashtable { return keys(); } - private static class Parser { + private abstract static class Parser { private StringBuilder key = null; private StringBuilder value = null; private StringBuilder current = null; @@ -79,13 +84,15 @@ public class Properties extends Hashtable { key = value = current = null; } - private void parse(InputStream in, Map map) + abstract int readCharacter() throws IOException; + + void parse(Map map) throws IOException { boolean escaped = false; int c; - while ((c = in.read()) != -1) { + while ((c = readCharacter()) != -1) { if (c == '\\') { if (escaped) { escaped = false; @@ -98,7 +105,7 @@ public class Properties extends Hashtable { case '#': case '!': if (key == null) { - while ((c = in.read()) != -1 && c != '\n'); + while ((c = readCharacter()) != -1 && c != '\n'); } else { append(c); } @@ -153,4 +160,32 @@ public class Properties extends Hashtable { finishLine(map); } } + + static class InputStreamParser extends Parser { + InputStream in; + + + public InputStreamParser(InputStream in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + + static class ReaderParser extends Parser { + Reader in; + + public ReaderParser(Reader in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + } From 7376425b24b3fbc1e37f46129143fdd152a3f8aa Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 14:47:45 +0200 Subject: [PATCH 032/274] dummy SecurityManager and related classes added --- classpath/java/lang/SecurityManager.java | 30 +++++++++++++++++++ classpath/java/lang/System.java | 9 ++++++ classpath/java/security/AccessController.java | 6 +++- classpath/java/security/AllPermission.java | 8 ++++- classpath/java/security/BasicPermission.java | 19 ++++++++++++ classpath/java/security/Permission.java | 16 ++++++++++ .../java/security/SecurityPermission.java | 19 ++++++++++++ 7 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 classpath/java/lang/SecurityManager.java create mode 100644 classpath/java/security/BasicPermission.java create mode 100644 classpath/java/security/SecurityPermission.java diff --git a/classpath/java/lang/SecurityManager.java b/classpath/java/lang/SecurityManager.java new file mode 100644 index 0000000000..0b522c5bfb --- /dev/null +++ b/classpath/java/lang/SecurityManager.java @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, 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; + +import java.security.AccessController; +import java.security.Permission; +import java.security.SecurityPermission; + +public class SecurityManager { + + public SecurityManager() { + } + + public void checkPermission(Permission perm) { + AccessController.checkPermission(perm); + } + + public void checkSecurityAccess(String target) { + checkPermission(new SecurityPermission(target)); + } + +} diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index ac3ee11b3a..c060493e7c 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -22,6 +22,7 @@ import java.util.Properties; public abstract class System { private static Property properties; + private static SecurityManager securityManager; // static { // loadLibrary("natives"); // } @@ -118,6 +119,14 @@ public abstract class System { public static void exit(int code) { Runtime.getRuntime().exit(code); } + + public static SecurityManager getSecurityManager() { + return securityManager; + } + + public static void setSecurityManager(SecurityManager securityManager) { + System.securityManager = securityManager; + } private static class Property { public final String name; diff --git a/classpath/java/security/AccessController.java b/classpath/java/security/AccessController.java index 804dfe70a7..b219e450ae 100644 --- a/classpath/java/security/AccessController.java +++ b/classpath/java/security/AccessController.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008, 2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -21,5 +21,9 @@ public class AccessController { public static Object doPrivileged (PrivilegedAction action) { return action.run(); } + + public static void checkPermission(Permission perm) throws AccessControlException { + + } } diff --git a/classpath/java/security/AllPermission.java b/classpath/java/security/AllPermission.java index 6bc99d53e8..b35004f609 100644 --- a/classpath/java/security/AllPermission.java +++ b/classpath/java/security/AllPermission.java @@ -10,4 +10,10 @@ package java.security; -public class AllPermission extends Permission { } +public class AllPermission extends Permission { + public AllPermission() { + super(""); + } + + +} diff --git a/classpath/java/security/BasicPermission.java b/classpath/java/security/BasicPermission.java new file mode 100644 index 0000000000..756e70139d --- /dev/null +++ b/classpath/java/security/BasicPermission.java @@ -0,0 +1,19 @@ +/* Copyright (c) 2010, 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.security; + +public class BasicPermission extends Permission { + + public BasicPermission(String name) { + super(name); + } + +} diff --git a/classpath/java/security/Permission.java b/classpath/java/security/Permission.java index bc6c438e18..528795a127 100644 --- a/classpath/java/security/Permission.java +++ b/classpath/java/security/Permission.java @@ -11,6 +11,22 @@ package java.security; public abstract class Permission { + + protected String name; + + public Permission(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + '['+name+']'; + } + public PermissionCollection newPermissionCollection() { return null; } diff --git a/classpath/java/security/SecurityPermission.java b/classpath/java/security/SecurityPermission.java new file mode 100644 index 0000000000..22660f6111 --- /dev/null +++ b/classpath/java/security/SecurityPermission.java @@ -0,0 +1,19 @@ +/* Copyright (c) 2010, 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.security; + +public class SecurityPermission extends BasicPermission { + + public SecurityPermission(String name) { + super(name); + } + +} From 6752505cb898c6f6b0276a31bb1b04b45350f678 Mon Sep 17 00:00:00 2001 From: Zsombor Gegesy Date: Sun, 15 Aug 2010 15:06:36 +0200 Subject: [PATCH 033/274] add File.canRead()/File.canWrite() implementation --- classpath/java-io.cpp | 25 +++++++++++++++++++++++++ classpath/java/io/File.java | 12 ++++++++++++ test/FileOutput.java | 1 + 3 files changed, 38 insertions(+) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 134045bdd2..05b54da2c9 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -377,6 +377,31 @@ Java_java_io_File_delete(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canRead(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = access(chars, R_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = access(chars, W_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + + extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) { diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index c3fa42932f..86ef77c6a3 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -60,7 +60,19 @@ public class File { public boolean isFile() { return isFile(path); } + + private static native boolean canRead(String path); + + public boolean canRead() { + return canRead(path); + } + private static native boolean canWrite(String path); + + public boolean canWrite() { + return canWrite(path); + } + public String getName() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { diff --git a/test/FileOutput.java b/test/FileOutput.java index db4273f650..29df89da9a 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -1,3 +1,4 @@ +import java.io.File; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.File; From 522f8ca1a5227d989adf313ee8041d24ff29707b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Sep 2010 14:29:27 -0600 Subject: [PATCH 034/274] javadoc grammar correction in Continuations.java --- classpath/avian/Continuations.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index ecec10b348..42565830d4 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -128,7 +128,7 @@ public class Continuations { * receiver.receive(Callback), propagate the exception * thrown by that method, return the result passed to the * handleResult(T) method of the continuation, or throw the - * exception passed to the handleException(Throwable) of the + * exception passed to the handleException(Throwable) method of the * continuation. */ public static native T callWithCurrentContinuation From d5b35bea6ee98e31d13755f994513b4d5ef0594f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Sep 2010 14:41:01 -0600 Subject: [PATCH 035/274] remove redundant import from FileOutput.java --- test/FileOutput.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/FileOutput.java b/test/FileOutput.java index 29df89da9a..db4273f650 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -1,4 +1,3 @@ -import java.io.File; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.File; From 74a87a7f4f17f72beb6dda18e6aaf88fdf0ec239 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 12 Sep 2010 14:46:14 -0600 Subject: [PATCH 036/274] use _waccess on windows to implement File.can{Read|Write} --- classpath/java-io.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 05b54da2c9..f134d6dc0c 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -25,6 +25,7 @@ # include # include +# define ACCESS _waccess # define CLOSE _close # define READ _read # define WRITE _write @@ -56,6 +57,7 @@ typedef wchar_t char_t; # include # include "sys/mman.h" +# define ACCESS access # define OPEN open # define CLOSE close # define READ read @@ -382,7 +384,7 @@ Java_java_io_File_canRead(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { - int r = access(chars, R_OK); + int r = ACCESS(chars, R_OK); releaseChars(e, path, chars); return (r == 0); } @@ -394,7 +396,7 @@ Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) { string_t chars = getChars(e, path); if (chars) { - int r = access(chars, W_OK); + int r = ACCESS(chars, W_OK); releaseChars(e, path, chars); return (r == 0); } From 76132bec901b04044b94a4ed4f730422ced7f345 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Sep 2010 19:50:24 -0600 Subject: [PATCH 037/274] set wsaInitialized to true on success in Java_java_net_Socket_init --- classpath/java-net.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classpath/java-net.cpp b/classpath/java-net.cpp index bd94f3e52c..20d853adc2 100644 --- a/classpath/java-net.cpp +++ b/classpath/java-net.cpp @@ -29,6 +29,8 @@ Java_java_net_Socket_init(JNIEnv* ONLY_ON_WINDOWS(e), jclass) int r = WSAStartup(MAKEWORD(2, 2), &data); if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { throwNew(e, "java/io/IOException", "WSAStartup failed"); + } else { + wsaInitialized = true; } } #endif From 561ee6dff99cb50f5c41bebae79e05d8cfef2926 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 13 Sep 2010 20:38:55 -0600 Subject: [PATCH 038/274] add debug logging to finder.cpp --- src/finder.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/finder.cpp b/src/finder.cpp index ae784eb48c..7ad3245c7a 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -16,6 +16,8 @@ using namespace vm; namespace { +const bool DebugFind = false; + const char* append(System* s, const char* a, const char* b, const char* c) @@ -141,6 +143,9 @@ class DirectoryElement: public Element { s->free(file); if (s->success(status)) { + if (DebugFind) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } return region; } else { return 0; @@ -487,7 +492,11 @@ class JarElement: public Element { while (*name == '/') name++; - return (index ? index->find(name, region->start()) : 0); + System::Region* r = (index ? index->find(name, region->start()) : 0); + if (DebugFind and r) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } + return r; } virtual bool exists(const char* name) { From d819a75f361bf573b503ae1cbe8dd49500a5fa4a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 14 Sep 2010 10:49:41 -0600 Subject: [PATCH 039/274] more work towards OpenJDK classpath support The biggest change in this commit is to split the system classloader into two: one for boot classes (e.g. java.lang.*) and another for application classes. This is necessary to make OpenJDK's security checks happy. The rest of the changes include bugfixes and additional JVM method implementations in classpath-openjdk.cpp. --- classpath/avian/Classes.java | 7 +- classpath/avian/SystemClassLoader.java | 6 +- classpath/java/lang/Class.java | 75 ++-- classpath/java/lang/ClassLoader.java | 4 +- classpath/java/lang/OutOfMemoryError.java | 2 +- classpath/java/lang/reflect/Field.java | 3 +- classpath/java/lang/reflect/Proxy.java | 3 +- classpath/sun/reflect/ConstantPool.java | 13 + makefile | 2 +- src/bootimage.h | 6 +- src/builtin.cpp | 110 +---- src/classpath-avian.cpp | 115 ++++- src/classpath-common.h | 5 +- src/classpath-openjdk.cpp | 471 +++++++++++++++----- src/compile-x86.S | 2 +- src/compile.cpp | 390 +++++++---------- src/continuations-x86.S | 8 +- src/gnu.cpp | 505 ---------------------- src/heapdump.cpp | 3 +- src/interpret.cpp | 231 ++++------ src/jnienv.cpp | 57 +-- src/machine.cpp | 485 +++++++++++---------- src/machine.h | 206 ++++++--- src/process.h | 3 +- src/processor.h | 6 +- src/type-generator.cpp | 2 +- src/types.def | 5 - src/util.cpp | 16 +- 28 files changed, 1250 insertions(+), 1491 deletions(-) create mode 100644 classpath/sun/reflect/ConstantPool.java delete mode 100644 src/gnu.cpp diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index f312690606..c73c00931d 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -104,14 +104,15 @@ public class Classes { byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); return Enum.valueOf - (getClass(loadVMClass(loader, typeName, 1, typeName.length - 3)), + (SystemClassLoader.getClass + (loadVMClass(loader, typeName, 1, typeName.length - 3)), new String(name, 0, name.length - 1, false)); } case 'c':{ byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - return getClass(loadVMClass(loader, name, 1, name.length - 3)); + return SystemClassLoader.getClass(loadVMClass(loader, name, 1, name.length - 3)); } case '@': @@ -136,7 +137,7 @@ public class Classes { { byte[] typeName = (byte[]) Singleton.getObject(pool, read2(in) - 1); Object[] annotation = new Object[(read2(in) + 1) * 2]; - annotation[1] = getClass + annotation[1] = SystemClassLoader.getClass (loadVMClass(loader, typeName, 1, typeName.length - 3)); for (int i = 2; i < annotation.length; i += 2) { diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index d93be28114..3054afe15a 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -14,7 +14,7 @@ import java.net.URL; import java.net.MalformedURLException; public class SystemClassLoader extends ClassLoader { - private static native VMClass findVMClass(String name) + private native VMClass findVMClass(String name) throws ClassNotFoundException; protected Class findClass(String name) throws ClassNotFoundException { @@ -23,14 +23,14 @@ public class SystemClassLoader extends ClassLoader { public static native Class getClass(VMClass vmClass); - private static native VMClass findLoadedVMClass(String name); + private native VMClass findLoadedVMClass(String name); protected Class reallyFindLoadedClass(String name){ VMClass c = findLoadedVMClass(name); return c == null ? null : getClass(c); } - private static native boolean resourceExists(String name); + private native boolean resourceExists(String name); protected URL findResource(String name) { if (resourceExists(name)) { diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 6d234f3765..65021739fb 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -14,6 +14,7 @@ import avian.VMClass; import avian.ClassAddendum; import avian.AnnotationInvocationHandler; import avian.SystemClassLoader; +import avian.Classes; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -69,23 +70,23 @@ public final class Class public static String getName(VMClass c) { if (c.name == null) { if ((c.vmFlags & PrimitiveFlag) != 0) { - if (c == SystemClassLoader.primitiveClass('V')) { + if (c == Classes.primitiveClass('V')) { c.name = "void\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('Z')) { + } else if (c == Classes.primitiveClass('Z')) { c.name = "boolean\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('B')) { + } else if (c == Classes.primitiveClass('B')) { c.name = "byte\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('C')) { + } else if (c == Classes.primitiveClass('C')) { c.name = "char\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('S')) { + } else if (c == Classes.primitiveClass('S')) { c.name = "short\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('I')) { + } else if (c == Classes.primitiveClass('I')) { c.name = "int\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('F')) { + } else if (c == Classes.primitiveClass('F')) { c.name = "float\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('J')) { + } else if (c == Classes.primitiveClass('J')) { c.name = "long\0".getBytes(); - } else if (c == SystemClassLoader.primitiveClass('D')) { + } else if (c == Classes.primitiveClass('D')) { c.name = "double\0".getBytes(); } else { throw new AssertionError(); @@ -150,9 +151,9 @@ public final class Class loader = Class.class.vmClass.loader; } Class c = loader.loadClass(name); - SystemClassLoader.link(c.vmClass, loader); + Classes.link(c.vmClass, loader); if (initialize) { - SystemClassLoader.initialize(c.vmClass); + Classes.initialize(c.vmClass); } return c; } @@ -170,7 +171,7 @@ public final class Class } else { if (name.length() == 1) { return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass(name.charAt(0))); + (Classes.primitiveClass(name.charAt(0))); } else { throw new ClassNotFoundException(name); } @@ -184,29 +185,21 @@ public final class Class if (isArray()) { String n = getName(); if ("[Z".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('Z')); + return SystemClassLoader.getClass(Classes.primitiveClass('Z')); } else if ("[B".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('B')); + return SystemClassLoader.getClass(Classes.primitiveClass('B')); } else if ("[S".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('S')); + return SystemClassLoader.getClass(Classes.primitiveClass('S')); } else if ("[C".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('C')); + return SystemClassLoader.getClass(Classes.primitiveClass('C')); } else if ("[I".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('I')); + return SystemClassLoader.getClass(Classes.primitiveClass('I')); } else if ("[F".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('F')); + return SystemClassLoader.getClass(Classes.primitiveClass('F')); } else if ("[J".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('J')); + return SystemClassLoader.getClass(Classes.primitiveClass('J')); } else if ("[D".equals(n)) { - return SystemClassLoader.getClass - (SystemClassLoader.primitiveClass('D')); + return SystemClassLoader.getClass(Classes.primitiveClass('D')); } if (vmClass.staticTable == null) throw new AssertionError(); @@ -217,12 +210,12 @@ public final class Class } public boolean isAssignableFrom(Class c) { - return SystemClassLoader.isAssignableFrom(vmClass, c.vmClass); + return Classes.isAssignableFrom(vmClass, c.vmClass); } private static Field findField(VMClass vmClass, String name) { if (vmClass.fieldTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); for (int i = 0; i < vmClass.fieldTable.length; ++i) { if (Field.getName(vmClass.fieldTable[i]).equals(name)) { @@ -269,7 +262,7 @@ public final class Class Class[] parameterTypes) { if (vmClass.methodTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); if (parameterTypes == null) { parameterTypes = new Class[0]; @@ -365,7 +358,7 @@ public final class Class public Constructor[] getDeclaredConstructors() { Constructor[] array = new Constructor[countConstructors(false)]; if (vmClass.methodTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int index = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { @@ -381,7 +374,7 @@ public final class Class public Constructor[] getConstructors() { Constructor[] array = new Constructor[countConstructors(true)]; if (vmClass.methodTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int index = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { @@ -423,7 +416,7 @@ public final class Class public Field[] getFields() { Field[] array = new Field[countPublicFields()]; if (vmClass.fieldTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int ai = 0; for (int i = 0; i < vmClass.fieldTable.length; ++i) { @@ -454,7 +447,7 @@ public final class Class public Method[] getDeclaredMethods() { Method[] array = new Method[countMethods(false)]; if (vmClass.methodTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int ai = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { @@ -470,7 +463,7 @@ public final class Class public Method[] getMethods() { Method[] array = new Method[countMethods(true)]; if (vmClass.methodTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int index = 0; for (int i = 0; i < vmClass.methodTable.length; ++i) { @@ -487,7 +480,7 @@ public final class Class public Class[] getInterfaces() { if (vmClass.interfaceTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); int stride = (isInterface() ? 1 : 2); Class[] array = new Class[vmClass.interfaceTable.length / stride]; @@ -534,8 +527,8 @@ public final class Class } public static boolean isInstance(VMClass c, Object o) { - return o != null && SystemClassLoader.isAssignableFrom - (c, SystemClassLoader.getVMClass(o)); + return o != null && Classes.isAssignableFrom + (c, Classes.getVMClass(o)); } public boolean isInstance(Object o) { @@ -620,7 +613,7 @@ public final class Class public T getAnnotation(Class class_) { for (VMClass c = vmClass; c != null; c = c.super_) { if (c.addendum != null && c.addendum.annotationTable != null) { - SystemClassLoader.link(c, c.loader); + Classes.link(c, c.loader); Object[] table = (Object[]) c.addendum.annotationTable; for (int i = 0; i < table.length; ++i) { @@ -636,7 +629,7 @@ public final class Class public Annotation[] getDeclaredAnnotations() { if (vmClass.addendum.annotationTable != null) { - SystemClassLoader.link(vmClass); + Classes.link(vmClass); Object[] table = (Object[]) vmClass.addendum.annotationTable; Annotation[] array = new Annotation[table.length]; diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index c63d971440..dbd376b62f 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -47,7 +47,7 @@ public abstract class ClassLoader { } return avian.SystemClassLoader.getClass - (avian.SystemClassLoader.defineVMClass(this, b, offset, length)); + (avian.Classes.defineVMClass(this, b, offset, length)); } protected Class findClass(String name) throws ClassNotFoundException { @@ -88,7 +88,7 @@ public abstract class ClassLoader { } protected void resolveClass(Class c) { - avian.SystemClassLoader.link(c.vmClass, this); + avian.Classes.link(c.vmClass, this); } private ClassLoader getParent() { diff --git a/classpath/java/lang/OutOfMemoryError.java b/classpath/java/lang/OutOfMemoryError.java index 29cae34d73..977da303e3 100644 --- a/classpath/java/lang/OutOfMemoryError.java +++ b/classpath/java/lang/OutOfMemoryError.java @@ -12,7 +12,7 @@ package java.lang; public class OutOfMemoryError extends VirtualMachineError { public OutOfMemoryError(String message) { - super(message, null); + super(message); } public OutOfMemoryError() { diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index b8f9ac0cf3..23fe3bf40f 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -13,6 +13,7 @@ package java.lang.reflect; import avian.VMField; import avian.AnnotationInvocationHandler; import avian.SystemClassLoader; +import avian.Classes; import java.lang.annotation.Annotation; @@ -204,7 +205,7 @@ public class Field extends AccessibleObject { } else { throw new IllegalArgumentException ("needed " + getType() + ", got " - + Class.getName(SystemClassLoader.vmClass(target)) + + + Class.getName(Classes.vmClass(target)) + " when setting " + Class.getName(vmField.class_) + "." + getName()); } break; diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index 15119c8d30..804450f123 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -515,8 +515,7 @@ public class Proxy { byte[] classData = out.toByteArray(); return avian.SystemClassLoader.getClass - (avian.SystemClassLoader.defineVMClass - (loader, classData, 0, classData.length)); + (avian.Classes.defineVMClass(loader, classData, 0, classData.length)); } public static Object newProxyInstance(ClassLoader loader, diff --git a/classpath/sun/reflect/ConstantPool.java b/classpath/sun/reflect/ConstantPool.java new file mode 100644 index 0000000000..582ce67607 --- /dev/null +++ b/classpath/sun/reflect/ConstantPool.java @@ -0,0 +1,13 @@ +/* Copyright (c) 2010, 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 sun.reflect; + +public class ConstantPool { } diff --git a/makefile b/makefile index 87567a58ab..e1af555cb4 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -#MAKEFLAGS = -s +MAKEFLAGS = -s name = avian version = 0.3 diff --git a/src/bootimage.h b/src/bootimage.h index b76a77b7fa..ada3ce41d9 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -55,11 +55,13 @@ class BootImage { unsigned heapSize; unsigned codeSize; - unsigned classCount; + unsigned bootClassCount; + unsigned appClassCount; unsigned stringCount; unsigned callCount; - unsigned loader; + unsigned bootLoader; + unsigned appLoader; unsigned types; unsigned methodTree; unsigned methodTreeSentinal; diff --git a/src/builtin.cpp b/src/builtin.cpp index 2d0d115a3c..c1dc0f5c29 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -18,10 +18,11 @@ using namespace vm; namespace { int64_t -search(Thread* t, object name, object (*op)(Thread*, object), - bool replaceDots) +search(Thread* t, object loader, object name, + object (*op)(Thread*, object, object), bool replaceDots) { if (LIKELY(name)) { + PROTECT(t, loader); PROTECT(t, name); object n = makeByteArray(t, stringLength(t, name) + 1); @@ -32,7 +33,7 @@ search(Thread* t, object name, object (*op)(Thread*, object), replace('.', '/', s); } - object r = op(t, n); + object r = op(t, loader, n); if (t->exception) { return 0; } @@ -45,86 +46,45 @@ search(Thread* t, object name, object (*op)(Thread*, object), } } +object +resolveSystemClassThrow(Thread* t, object loader, object spec) +{ + return resolveSystemClass(t, loader, spec, true); +} + } // namespace -extern "C" JNIEXPORT void JNICALL -Avian_avian_SystemClassLoader_acquireClassLock -(Thread* t, object, uintptr_t*) -{ - acquire(t, t->m->classLock); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_SystemClassLoader_releaseClassLock -(Thread* t, object, uintptr_t*) -{ - release(t, t->m->classLock); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_getVMClass -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast - (objectClass(t, reinterpret_cast(arguments[0]))); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_defineVMClass -(Thread* t, object, uintptr_t* arguments) -{ - object loader = reinterpret_cast(arguments[0]); - object b = reinterpret_cast(arguments[1]); - int offset = arguments[2]; - int length = arguments[3]; - - uint8_t* buffer = static_cast - (t->m->heap->allocate(length)); - memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = defineClass(t, loader, buffer, length); - t->m->heap->free(buffer, length); - - return reinterpret_cast(c); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findLoadedVMClass (Thread* t, object, uintptr_t* arguments) { - object name = reinterpret_cast(arguments[0]); + object loader = reinterpret_cast(arguments[0]); + object name = reinterpret_cast(arguments[1]); - return search(t, name, findLoadedSystemClass, true); + return search(t, loader, name, findLoadedClass, true); } extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_findVMClass (Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - - return search(t, name, resolveSystemClass, true); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_resolveVMClass -(Thread* t, object, uintptr_t* arguments) { object loader = reinterpret_cast(arguments[0]); - object spec = reinterpret_cast(arguments[1]); + object name = reinterpret_cast(arguments[1]); - return reinterpret_cast(resolveClass(t, loader, spec)); + return search(t, loader, name, resolveSystemClassThrow, true); } extern "C" JNIEXPORT int64_t JNICALL Avian_avian_SystemClassLoader_resourceExists (Thread* t, object, uintptr_t* arguments) { - object name = reinterpret_cast(arguments[0]); + object loader = reinterpret_cast(arguments[0]); + object name = reinterpret_cast(arguments[1]); if (LIKELY(name)) { RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - return t->m->finder->exists(RUNTIME_ARRAY_BODY(n)); + return getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); @@ -133,35 +93,11 @@ Avian_avian_SystemClassLoader_resourceExists } extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_primitiveClass +Avian_avian_SystemClassLoader_getClass (Thread* t, object, uintptr_t* arguments) { - return reinterpret_cast(primitiveClass(t, arguments[0])); -} - -extern "C" JNIEXPORT void JNICALL -Avian_avian_SystemClassLoader_initialize -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - - initClass(t, this_); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_isAssignableFrom -(Thread* t, object, uintptr_t* arguments) -{ - object this_ = reinterpret_cast(arguments[0]); - object that = reinterpret_cast(arguments[1]); - - if (LIKELY(that)) { - return vm::isAssignableFrom(t, this_, that); - } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); - return 0; - } + return reinterpret_cast + (getJClass(t, reinterpret_cast(arguments[0]))); } #ifdef AVIAN_HEAPDUMP @@ -208,7 +144,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - System::Region* r = t->m->finder->find(RUNTIME_ARRAY_BODY(p)); + System::Region* r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); if (r) { jint rSize = r->length(); r->dispose(); @@ -229,7 +165,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open stringChars(t, path, RUNTIME_ARRAY_BODY(p)); return reinterpret_cast - (t->m->finder->find(RUNTIME_ARRAY_BODY(p))); + (t->m->appFinder->find(RUNTIME_ARRAY_BODY(p))); } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index b9b5570eda..6d64767ed7 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -49,15 +49,16 @@ class MyClasspath : public Classpath { const unsigned NormalPriority = 5; return vm::makeThread - (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, t->m->loader, 0, 0, - group); + (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, + root(t, Machine::BootLoader), 0, 0, group); } virtual void runThread(Thread* t) { object method = resolveMethod - (t, t->m->loader, "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); + (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", + "(Ljava/lang/Thread;)V"); if (t->exception == 0) { t->m->processor->invoke(t, method, 0, t->javaThread); @@ -75,7 +76,7 @@ class MyClasspath : public Classpath { trace = makeTrace(t); } - object result = make(t, arrayBody(t, t->m->types, type)); + object result = make(t, vm::type(t, type)); set(t, result, ThrowableMessage, message); set(t, result, ThrowableTrace, trace); @@ -84,6 +85,12 @@ class MyClasspath : public Classpath { return result; } + virtual void + boot(Thread*) + { + // ignore + } + virtual void dispose() { @@ -352,7 +359,7 @@ Avian_java_lang_reflect_Array_makeObjectArray int length = arguments[1]; return reinterpret_cast - (makeObjectArray(t, classLoader(t, elementType), elementType, length)); + (makeObjectArray(t, elementType, length)); } extern "C" JNIEXPORT int64_t JNICALL @@ -408,7 +415,8 @@ Avian_java_lang_System_getVMProperty int64_t r = 0; if (::strcmp(RUNTIME_ARRAY_BODY(n), "java.lang.classpath") == 0) { - r = reinterpret_cast(makeString(t, "%s", t->m->finder->path())); + r = reinterpret_cast + (makeString(t, "%s", t->m->appFinder->path())); } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "avian.version") == 0) { r = reinterpret_cast(makeString(t, AVIAN_VERSION)); } else if (::strcmp(RUNTIME_ARRAY_BODY(n), "file.encoding") == 0) { @@ -499,7 +507,8 @@ Avian_java_lang_Runtime_addShutdownHook ACQUIRE(t, t->m->shutdownLock); - t->m->shutdownHooks = makePair(t, hook, t->m->shutdownHooks); + setRoot(t, Machine::ShutdownHooks, + makePair(t, hook, root(t, Machine::ShutdownHooks))); } extern "C" JNIEXPORT int64_t JNICALL @@ -516,15 +525,13 @@ Avian_java_lang_Throwable_resolveTrace object trace = reinterpret_cast(*arguments); PROTECT(t, trace); - unsigned length = arrayLength(t, trace); - object elementType = arrayBody - (t, t->m->types, Machine::StackTraceElementType); - object array = makeObjectArray - (t, classLoader(t, elementType), elementType, length); + unsigned length = objectArrayLength(t, trace); + object elementType = type(t, Machine::StackTraceElementType); + object array = makeObjectArray(t, elementType, length); PROTECT(t, array); for (unsigned i = 0; i < length; ++i) { - object ste = makeStackTraceElement(t, arrayBody(t, trace, i)); + object ste = makeStackTraceElement(t, objectArrayBody(t, trace, i)); set(t, array, ArrayBody + (i * BytesPerWord), ste); } @@ -599,3 +606,85 @@ Avian_java_lang_Thread_setDaemon setDaemon(t, thread, daemon); } + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_acquireClassLock +(Thread* t, object, uintptr_t*) +{ + acquire(t, t->m->classLock); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_releaseClassLock +(Thread* t, object, uintptr_t*) +{ + release(t, t->m->classLock); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_resolveVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object spec = reinterpret_cast(arguments[1]); + + return reinterpret_cast(resolveClass(t, loader, spec)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_primitiveClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast(primitiveClass(t, arguments[0])); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_defineVMClass +(Thread* t, object, uintptr_t* arguments) +{ + object loader = reinterpret_cast(arguments[0]); + object b = reinterpret_cast(arguments[1]); + int offset = arguments[2]; + int length = arguments[3]; + + uint8_t* buffer = static_cast + (t->m->heap->allocate(length)); + memcpy(buffer, &byteArrayBody(t, b, offset), length); + object c = defineClass(t, loader, buffer, length); + t->m->heap->free(buffer, length); + + return reinterpret_cast(c); +} + +extern "C" JNIEXPORT void JNICALL +Avian_avian_Classes_initialize +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + initClass(t, this_); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_isAssignableFrom +(Thread* t, object, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object that = reinterpret_cast(arguments[1]); + + if (LIKELY(that)) { + return vm::isAssignableFrom(t, this_, that); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType); + return 0; + } +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_Classes_getVMClass +(Thread* t, object, uintptr_t* arguments) +{ + return reinterpret_cast + (objectClass(t, reinterpret_cast(arguments[0]))); +} diff --git a/src/classpath-common.h b/src/classpath-common.h index 23cccb8684..b9f1ef69b0 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -56,8 +56,7 @@ getTrace(Thread* t, unsigned skipCount) if (skipCount == 0) { object method = walker->method(); if (isAssignableFrom - (t, arrayBody(t, t->m->types, Machine::ThrowableType), - methodClass(t, method)) + (t, type(t, Machine::ThrowableType), methodClass(t, method)) and vm::strcmp(reinterpret_cast(""), &byteArrayBody(t, methodName(t, method), 0)) == 0) @@ -80,7 +79,7 @@ getTrace(Thread* t, unsigned skipCount) t->m->processor->walkStack(t, &v); - if (v.trace == 0) v.trace = makeArray(t, 0); + if (v.trace == 0) v.trace = makeObjectArray(t, 0); return v.trace; } diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 29c8866250..6871a3a9e6 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -40,6 +40,7 @@ # include # include # include +# include # include # include @@ -77,10 +78,10 @@ CREAT(string_t path, int mode) namespace local { const unsigned InterfaceVersion = 4; +const unsigned PageSize = 4 * 1024; Machine* globalMachine; - const char* primitiveName(Thread* t, object c) { @@ -144,6 +145,8 @@ class MyClasspath : public Classpath { virtual object makeJclass(Thread* t, object class_) { + PROTECT(t, class_); + object name = makeClassNameString(t, getClassName(t, class_)); return vm::makeJclass @@ -153,9 +156,7 @@ class MyClasspath : public Classpath { virtual object makeString(Thread* t, object array, int32_t offset, int32_t length) { - if (objectClass(t, array) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, array) == type(t, Machine::ByteArrayType)) { PROTECT(t, array); object charArray = makeCharArray(t, length); @@ -183,19 +184,25 @@ class MyClasspath : public Classpath { } return vm::makeThread - (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, t->m->loader, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, false); + (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, + root(t, Machine::BootLoader), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, + 0, false); } virtual void runThread(Thread* t) { object method = resolveMethod - (t, t->m->loader, "java/lang/Thread", "run", "()V"); + (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); if (LIKELY(t->exception == 0)) { t->m->processor->invoke(t, method, t->javaThread); } + + acquire(t, t->javaThread); + t->flags &= ~Thread::ActiveFlag; + notifyAll(t, t->javaThread); + release(t, t->javaThread); } virtual object @@ -209,7 +216,7 @@ class MyClasspath : public Classpath { trace = makeTrace(t); } - object result = make(t, arrayBody(t, t->m->types, type)); + object result = make(t, vm::type(t, type)); set(t, result, ThrowableMessage, message); set(t, result, ThrowableTrace, trace); @@ -228,7 +235,22 @@ class MyClasspath : public Classpath { } t->m->processor->invoke - (t, t->m->loader, "java/lang/System", "initializeSystemClass", "()V", 0); + (t, root(t, Machine::BootLoader), "java/lang/System", + "initializeSystemClass", "()V", 0); + if (UNLIKELY(t->exception)) return; + + object constructor = resolveMethod + (t, type(t, Machine::ClassLoaderType), "", + "(Ljava/lang/ClassLoader;)V"); + if (UNLIKELY(t->exception)) return; + PROTECT(t, constructor); + + t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); + if (UNLIKELY(t->exception)) return; + + t->m->processor->invoke + (t, constructor, root(t, Machine::AppLoader), + root(t, Machine::BootLoader)); } virtual void @@ -281,16 +303,16 @@ countFields(Thread* t, object c, bool publicOnly) { object table = classFieldTable(t, c); if (publicOnly) { - return objectArrayLength(t, table); - } else { unsigned count = 0; for (unsigned i = 0; i < arrayLength(t, table); ++i) { object vmField = arrayBody(t, table, i); - if ((not publicOnly) or (fieldFlags(t, vmField) & ACC_PUBLIC)) { + if (fieldFlags(t, vmField) & ACC_PUBLIC) { ++ count; } } return count; + } else { + return objectArrayLength(t, table); } } @@ -430,8 +452,7 @@ resolveParameterJTypes(Thread* t, object loader, object spec, PROTECT(t, list); object array = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), - *parameterCount); + (t, type(t, Machine::JclassType), *parameterCount); PROTECT(t, array); for (int i = *parameterCount - 1; i >= 0; --i) { @@ -447,15 +468,14 @@ object resolveExceptionJTypes(Thread* t, object loader, object addendum) { if (addendum == 0) { - return makeObjectArray - (t, loader, arrayBody(t, t->m->types, Machine::JclassType), 0); + return makeObjectArray(t, type(t, Machine::JclassType), 0); } PROTECT(t, loader); PROTECT(t, addendum); object array = makeObjectArray - (t, loader, arrayBody(t, t->m->types, Machine::JclassType), + (t, type(t, Machine::JclassType), shortArrayLength(t, methodAddendumExceptionTable(t, addendum))); PROTECT(t, array); @@ -467,9 +487,7 @@ resolveExceptionJTypes(Thread* t, object loader, object addendum) object o = singletonObject(t, addendumPool(t, addendum), index); - if (objectClass(t, o) - == arrayBody(t, t->m->types, Machine::ReferenceType)) - { + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass(t, loader, referenceName(t, o)); if (UNLIKELY(t->exception)) return 0; @@ -532,6 +550,38 @@ Avian_sun_misc_Unsafe_registerNatives // ignore } +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoader_2Ljava_security_ProtectionDomain_2 +(Thread* t, object, uintptr_t* arguments) +{ + //object name = reinterpret_cast(arguments[1]); + object data = reinterpret_cast(arguments[2]); + int32_t offset = arguments[3]; + int32_t length = arguments[4]; + object loader = reinterpret_cast(arguments[5]); + //object domain = reinterpret_cast(arguments[6]); + + uint8_t* buffer = static_cast + (t->m->heap->allocate(length)); + memcpy(buffer, &byteArrayBody(t, data, offset), length); + object c = defineClass(t, loader, buffer, length); + + return c ? reinterpret_cast(getJClass(t, c)) : 0; +} + +extern "C" JNIEXPORT int64_t +Avian_sun_misc_Unsafe_allocateInstance +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[1])); + PROTECT(t, c); + + initClass(t, c); + if (UNLIKELY(t->exception)) return 0; + + return reinterpret_cast(make(t, c)); +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldOffset (Thread* t, object, uintptr_t* arguments) @@ -564,15 +614,90 @@ Avian_sun_misc_Unsafe_objectFieldOffset (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getObject +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putObject +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uintptr_t value = arguments[4]; + + set(t, o, offset, reinterpret_cast(value)); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int32_t value = arguments[4]; + + cast(o, offset) = value; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getBoolean +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + return cast(o, offset); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putBoolean +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + uint8_t value = arguments[4]; + + cast(o, offset) = value; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__Ljava_lang_Object_2JJ +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + int64_t value; memcpy(&value, arguments + 4, 8); + + cast(o, offset) = value; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getObjectVolatile (Thread*, object, uintptr_t* arguments) { object o = reinterpret_cast(arguments[1]); - unsigned offset = arguments[2]; - object value = cast(o, offset); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + uintptr_t value = cast(o, offset); loadMemoryBarrier(); - return reinterpret_cast(value); + return value; } extern "C" JNIEXPORT int64_t JNICALL @@ -588,6 +713,25 @@ Avian_sun_misc_Unsafe_compareAndSwapInt (&cast(target, offset), expect, update); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_compareAndSwapObject +(Thread* t, object, uintptr_t* arguments) +{ + object target = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + intptr_t expect = arguments[4]; + intptr_t update = arguments[5]; + + bool success = __sync_bool_compare_and_swap + (&cast(target, offset), expect, update); + + if (success) { + mark(t, target, offset); + } + + return success; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_compareAndSwapLong (Thread*, object, uintptr_t* arguments) @@ -625,6 +769,17 @@ Avian_sun_misc_Unsafe_freeMemory } } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_setMemory +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t count; memcpy(&count, arguments + 3, 8); + int8_t v = arguments[5]; + + memset(reinterpret_cast(p), v, count); +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putLong__JJ (Thread*, object, uintptr_t* arguments) @@ -635,6 +790,16 @@ Avian_sun_misc_Unsafe_putLong__JJ *reinterpret_cast(p) = v; } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__JI +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int32_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_getByte__J (Thread*, object, uintptr_t* arguments) @@ -644,6 +809,22 @@ Avian_sun_misc_Unsafe_getByte__J return *reinterpret_cast(p); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_pageSize +(Thread*, object, uintptr_t*) +{ + return local::PageSize; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_ensureClassInitialized (Thread* t, object, uintptr_t* arguments) @@ -732,7 +913,7 @@ JVM_InitProperties(Thread* t, jobject properties) ENTER(t, Thread::ActiveState); object method = resolveMethod - (t, t->m->loader, "java/util/Properties", "setProperty", + (t, root(t, Machine::BootLoader), "java/util/Properties", "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); if (UNLIKELY(t->exception)) { @@ -776,6 +957,9 @@ JVM_InitProperties(Thread* t, jobject properties) local::setProperty(t, method, *properties, "sun.boot.library.path", getenv("LD_LIBRARY_PATH")); + local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", + "avian"); + #endif local::setProperty(t, method, *properties, "file.encoding", "ASCII"); #ifdef ARCH_x86_32 @@ -811,10 +995,16 @@ extern "C" JNIEXPORT void JNICALL JVM_OnExit(void (*)(void)) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_Exit(jint) { abort(); } +JVM_Exit(jint code) +{ + exit(code); +} extern "C" JNIEXPORT void JNICALL -JVM_Halt(jint) { abort(); } +JVM_Halt(jint code) +{ + exit(code); +} extern "C" JNIEXPORT void JNICALL JVM_GC() @@ -896,7 +1086,7 @@ JVM_GetStackTraceDepth(Thread* t, jobject throwable) { ENTER(t, Thread::ActiveState); - return arrayLength(t, throwableTrace(t, *throwable)); + return objectArrayLength(t, throwableTrace(t, *throwable)); } extern "C" JNIEXPORT jobject JNICALL @@ -906,7 +1096,7 @@ JVM_GetStackTraceElement(Thread* t, jobject throwable, jint index) return makeLocalReference (t, makeStackTraceElement - (t, arrayBody(t, throwableTrace(t, *throwable), index))); + (t, objectArrayBody(t, throwableTrace(t, *throwable), index))); } extern "C" JNIEXPORT void JNICALL @@ -947,25 +1137,7 @@ JVM_IsThreadAlive(Thread* t, jobject thread) ENTER(t, Thread::ActiveState); Thread* p = reinterpret_cast(threadPeer(t, *thread)); - if (p) { - switch (p->state) { - case Thread::ActiveState: - case Thread::IdleState: - case Thread::ExclusiveState: - return true; - - case Thread::NoState: - case Thread::ZombieState: - case Thread::JoinedState: - case Thread::ExitState: - return false; - - default: - abort(t); - } - } else { - return false; - } + return p and (p->flags & Thread::ActiveFlag) != 0; } extern "C" JNIEXPORT void JNICALL @@ -1013,7 +1185,19 @@ extern "C" JNIEXPORT void JNICALL JVM_Interrupt(Thread*, jobject) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsInterrupted(Thread*, jobject, jboolean) { abort(); } +JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) +{ + ENTER(t, Thread::ActiveState); + + acquire(t, *thread); + bool v = threadInterrupted(t, *thread); + if (clear) { + threadInterrupted(t, *thread) = false; + } + release(t, *thread); + + return v; +} extern "C" JNIEXPORT jboolean JNICALL JVM_HoldsLock(Thread*, jclass, jobject) { abort(); } @@ -1042,13 +1226,12 @@ JVM_GetClassContext(Thread* t) PROTECT(t, trace); object context = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), - arrayLength(t, trace)); + (t, type(t, Machine::JclassType), objectArrayLength(t, trace)); PROTECT(t, context); - for (unsigned i = 0; i < arrayLength(t, trace); ++i) { + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { object c = getJClass - (t, methodClass(t, traceElementMethod(t, arrayBody(t, trace, i)))); + (t, methodClass(t, traceElementMethod(t, objectArrayBody(t, trace, i)))); set(t, context, ArrayBody + (i * BytesPerWord), c); } @@ -1084,16 +1267,31 @@ JVM_LoadClass0(Thread*, jobject, jclass, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetArrayLength(Thread*, jobject) { abort(); } +JVM_GetArrayLength(Thread* t, jobject array) +{ + ENTER(t, Thread::ActiveState); + + return cast(*array, BytesPerWord); +} extern "C" JNIEXPORT jobject JNICALL -JVM_GetArrayElement(Thread*, jobject, jint) { abort(); } +JVM_GetArrayElement(Thread* t, jobject array, jint index) +{ + ENTER(t, Thread::ActiveState); + + return makeLocalReference(t, objectArrayBody(t, *array, index)); +} extern "C" JNIEXPORT jvalue JNICALL JVM_GetPrimitiveArrayElement(Thread*, jobject, jint, jint) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_SetArrayElement(Thread*, jobject, jint, jobject) { abort(); } +JVM_SetArrayElement(Thread* t, jobject array, jint index, jobject value) +{ + ENTER(t, Thread::ActiveState); + + set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); +} extern "C" JNIEXPORT void JNICALL JVM_SetPrimitiveArrayElement(Thread*, jobject, jint, jvalue, @@ -1126,8 +1324,7 @@ JVM_NewArray(Thread* t, jclass elementClass, jint length) default: abort(t); } } else { - return makeLocalReference - (t, makeObjectArray(t, t->m->loader, c, length)); + return makeLocalReference(t, makeObjectArray(t, c, length)); } } @@ -1152,32 +1349,32 @@ JVM_FindPrimitiveClass(Thread* t, const char* name) case 'b': if (name[1] == 'o') { return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbooleanType))); + (t, getJClass(t, type(t, Machine::JbooleanType))); } else { return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JbyteType))); + (t, getJClass(t, type(t, Machine::JbyteType))); } case 'c': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JcharType))); + (t, getJClass(t, type(t, Machine::JcharType))); case 'd': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JdoubleType))); + (t, getJClass(t, type(t, Machine::JdoubleType))); case 'f': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JfloatType))); + (t, getJClass(t, type(t, Machine::JfloatType))); case 'i': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JintType))); + (t, getJClass(t, type(t, Machine::JintType))); case 'l': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JlongType))); + (t, getJClass(t, type(t, Machine::JlongType))); case 's': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JshortType))); + (t, getJClass(t, type(t, Machine::JshortType))); case 'v': return makeLocalReference - (t, getJClass(t, arrayBody(t, t->m->types, Machine::JvoidType))); + (t, getJClass(t, type(t, Machine::JvoidType))); default: t->exception = t->m->classpath->makeThrowable (t, Machine::IllegalArgumentExceptionType); @@ -1194,7 +1391,8 @@ JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, { ENTER(t, Thread::ActiveState); - object c = resolveClass(t, loader ? *loader : t->m->loader, name); + object c = resolveClass + (t, loader ? *loader : root(t, Machine::BootLoader), name); if (t->exception) { if (throwError) { t->exception = t->m->classpath->makeThrowable @@ -1224,25 +1422,13 @@ JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) { ENTER(t, Thread::ActiveState); - ACQUIRE(t, t->m->classLock); - object spec = makeByteArray(t, stringLength(t, *name) + 1); { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); stringChars(t, *name, s); replace('.', '/', s); } - object c; - if (loader == 0 or *loader == t->m->loader) { - c = findLoadedSystemClass(t, spec); - } else { - object map = classLoaderMap(t, *loader); - if (map) { - c = hashMapFind(t, map, spec, byteArrayHash, byteArrayEqual); - } else { - c = 0; - } - } + object c = findLoadedClass(t, *loader, spec); return c ? makeLocalReference(t, getJClass(t, c)) : 0; } @@ -1275,8 +1461,7 @@ JVM_GetClassInterfaces(Thread* t, jclass c) (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; object array = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), - arrayLength(t, table) / stride); + (t, type(t, Machine::JclassType), arrayLength(t, table) / stride); PROTECT(t, array); for (unsigned i = 0; i < objectArrayLength(t, array); ++i) { @@ -1287,9 +1472,7 @@ JVM_GetClassInterfaces(Thread* t, jclass c) return makeLocalReference(t, array); } else { return makeLocalReference - (t, makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JclassType), - 0)); + (t, makeObjectArray(t, type(t, Machine::JclassType), 0)); } } @@ -1299,7 +1482,8 @@ JVM_GetClassLoader(Thread* t, jclass c) ENTER(t, Thread::ActiveState); object loader = classLoader(t, jclassVmClass(t, *c)); - return loader == t->m->loader ? 0 : makeLocalReference(t, loader); + return loader == root(t, Machine::BootLoader) + ? 0 : makeLocalReference(t, loader); } extern "C" JNIEXPORT jboolean JNICALL @@ -1385,8 +1569,10 @@ JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { + PROTECT(t, table); + object array = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JmethodType), + (t, type(t, Machine::JmethodType), local::countMethods(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); @@ -1461,9 +1647,7 @@ JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) return makeLocalReference(t, array); } else { return makeLocalReference - (t, makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JmethodType), - 0)); + (t, makeObjectArray(t, type(t, Machine::JmethodType), 0)); } } @@ -1474,8 +1658,10 @@ JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) object table = classFieldTable(t, jclassVmClass(t, *c)); if (table) { + PROTECT(t, table); + object array = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JfieldType), + (t, type(t, Machine::JfieldType), local::countFields(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); @@ -1501,6 +1687,8 @@ JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) return 0; } + PROTECT(t, type); + type = getJClass(t, type); object signature = t->m->classpath->makeString @@ -1524,12 +1712,12 @@ JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) set(t, array, ArrayBody + ((ai++) * BytesPerWord), field); } } + assert(t, ai == objectArrayLength(t, array)); return makeLocalReference(t, array); } else { return makeLocalReference - (t, makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JfieldType), 0)); + (t, makeObjectArray(t, type(t, Machine::JfieldType), 0)); } } @@ -1540,8 +1728,10 @@ JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { + PROTECT(t, table); + object array = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JconstructorType), + (t, type(t, Machine::JconstructorType), local::countConstructors(t, jclassVmClass(t, *c), publicOnly)); PROTECT(t, array); @@ -1598,9 +1788,7 @@ JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) return makeLocalReference(t, array); } else { return makeLocalReference - (t, makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JconstructorType), - 0)); + (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0)); } } @@ -1739,8 +1927,11 @@ JVM_DoPrivileged { ENTER(t, Thread::ActiveState); + // todo: cache these class and method lookups in the t->m->classpath + // object: + object privilegedAction = resolveClass - (t, t->m->loader, "java/security/PrivilegedAction"); + (t, root(t, Machine::BootLoader), "java/security/PrivilegedAction"); if (UNLIKELY(t->exception)) { return 0; @@ -1752,7 +1943,8 @@ JVM_DoPrivileged (t, privilegedAction, "run", "()Ljava/lang/Object;"); } else { object privilegedExceptionAction = resolveClass - (t, t->m->loader, "java/security/PrivilegedExceptionAction"); + (t, root(t, Machine::BootLoader), + "java/security/PrivilegedExceptionAction"); if (UNLIKELY(t->exception)) { return 0; @@ -1769,10 +1961,8 @@ JVM_DoPrivileged return makeLocalReference(t, result); } else { if (wrapException and not - (instanceOf - (t, arrayBody(t, t->m->types, Machine::ErrorType), t->exception) - or instanceOf - (t, arrayBody(t, t->m->types, Machine::RuntimeExceptionType), + (instanceOf(t, type(t, Machine::ErrorType), t->exception) + or instanceOf(t, type(t, Machine::RuntimeExceptionType), t->exception))) { object cause = t->exception; @@ -1781,7 +1971,8 @@ JVM_DoPrivileged t->exception = 0; object paeClass = resolveClass - (t, t->m->loader, "java/security/PrivilegedActionException"); + (t, root(t, Machine::BootLoader), + "java/security/PrivilegedActionException"); if (LIKELY(t->exception == 0)) { PROTECT(t, paeClass); @@ -2003,37 +2194,83 @@ extern "C" JNIEXPORT jint JNICALL JVM_Sync(jint) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_InitializeSocketLibrary(void) { abort(); } +JVM_InitializeSocketLibrary() +{ +#ifdef PLATFORM_WINDOWS + static bool wsaInitialized = false; + if (not wsaInitialized) { + WSADATA data; + int r = WSAStartup(MAKEWORD(2, 2), &data); + if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) { + return -1; + } else { + wsaInitialized = true; + } + } +#endif + return 0; +} extern "C" JNIEXPORT jint JNICALL -JVM_Socket(jint, jint, jint) { abort(); } +JVM_Socket(jint domain, jint type, jint protocol) +{ + return socket(domain, type, protocol); +} extern "C" JNIEXPORT jint JNICALL -JVM_SocketClose(jint) { abort(); } +JVM_SocketClose(jint socket) +{ +#ifdef PLATFORM_WINDOWS + return closesocket(socket); +#else + return close(socket); +#endif +} extern "C" JNIEXPORT jint JNICALL -JVM_SocketShutdown(jint, jint) { abort(); } +JVM_SocketShutdown(jint socket, jint how) +{ + return shutdown(socket, how); +} extern "C" JNIEXPORT jint JNICALL -JVM_Recv(jint, char*, jint, jint) { abort(); } +JVM_Recv(jint socket, char* dst, jint count, jint flags) +{ + return recv(socket, dst, count, flags); +} extern "C" JNIEXPORT jint JNICALL -JVM_Send(jint, char*, jint, jint) { abort(); } +JVM_Send(jint socket, char* src, jint count, jint flags) +{ + return send(socket, src, count, flags); +} extern "C" JNIEXPORT jint JNICALL JVM_Timeout(int, long) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Listen(jint, jint) { abort(); } +JVM_Listen(jint socket, jint count) +{ + return listen(socket, count); +} extern "C" JNIEXPORT jint JNICALL -JVM_Connect(jint, struct sockaddr*, jint) { abort(); } +JVM_Connect(jint socket, sockaddr* address, jint addressLength) +{ + return connect(socket, address, addressLength); +} extern "C" JNIEXPORT jint JNICALL JVM_Bind(jint, struct sockaddr*, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Accept(jint, struct sockaddr*, jint*) { abort(); } +JVM_Accept(jint socket, struct sockaddr* address, jint* addressLength) +{ + socklen_t length = *addressLength; + int r = accept(socket, address, &length); + *addressLength = length; + return r; +} extern "C" JNIEXPORT jint JNICALL JVM_RecvFrom(jint, char*, int, @@ -2047,7 +2284,13 @@ extern "C" JNIEXPORT jint JNICALL JVM_SocketAvailable(jint, jint*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetSockName(jint, struct sockaddr*, int*) { abort(); } +JVM_GetSockName(jint socket, struct sockaddr* address, int* addressLength) +{ + socklen_t length = *addressLength; + int r = getsockname(socket, address, &length); + *addressLength = length; + return r; +} extern "C" JNIEXPORT jint JNICALL JVM_GetSockOpt(jint, int, int, char*, int*) { abort(); } diff --git a/src/compile-x86.S b/src/compile-x86.S index 9e86527444..7dd9349f40 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -22,7 +22,7 @@ #ifdef __x86_64__ -#define THREAD_STACK 2224 +#define THREAD_STACK 2216 #if defined __MINGW32__ || defined __CYGWIN32__ diff --git a/src/compile.cpp b/src/compile.cpp index 5619dd0769..ced35ebf15 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -40,7 +40,7 @@ namespace { namespace local { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -61,6 +61,20 @@ const unsigned InitialZoneCapacityInBytes = 64 * 1024; const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; +enum Root { + CallTable, + MethodTree, + MethodTreeSentinal, + ObjectPools, + StaticTableArray, + VirtualThunks, + ReceiveMethod, + WindMethod, + RewindMethod +}; + +const unsigned RootCount = RewindMethod + 1; + inline bool isVmInvokeUnsafeStack(void* ip) { @@ -169,7 +183,7 @@ class MyThread: public Thread { // in this function, we "atomically" update the thread context // fields in such a way to ensure that another thread may // interrupt us at any time and still get a consistent, accurate - // stack trace. See MyProcess::getStackTrace for details. + // stack trace. See MyProcessor::getStackTrace for details. assert(t, t->transition == 0); @@ -277,7 +291,7 @@ resolveTarget(MyThread* t, void* stack, object method) PROTECT(t, method); PROTECT(t, class_); - resolveSystemClass(t, className(t, class_)); + resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); if (UNLIKELY(t->exception)) return 0; } @@ -294,7 +308,7 @@ resolveTarget(MyThread* t, object class_, unsigned index) if (classVmFlags(t, class_) & BootstrapFlag) { PROTECT(t, class_); - resolveSystemClass(t, className(t, class_)); + resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); if (UNLIKELY(t->exception)) return 0; } @@ -302,10 +316,10 @@ resolveTarget(MyThread* t, object class_, unsigned index) } object& -methodTree(MyThread* t); +root(Thread* t, Root root); -object -methodTreeSentinal(MyThread* t); +void +setRoot(Thread* t, Root root, object value); unsigned compiledSize(intptr_t address) @@ -348,8 +362,8 @@ methodForIp(MyThread* t, void* ip) // compile(MyThread*, Allocator*, BootContext*, object)): loadMemoryBarrier(); - return treeQuery(t, methodTree(t), reinterpret_cast(ip), - methodTreeSentinal(t), compareIpToMethodBounds); + return treeQuery(t, root(t, MethodTree), reinterpret_cast(ip), + root(t, MethodTreeSentinal), compareIpToMethodBounds); } class MyStackWalker: public Processor::StackWalker { @@ -2067,18 +2081,6 @@ unwind(MyThread* t) vmJump(ip, base, stack, t, 0, 0); } -object& -objectPools(MyThread* t); - -object& -windMethod(MyThread* t); - -object& -rewindMethod(MyThread* t); - -object& -receiveMethod(MyThread* t); - uintptr_t defaultThunk(MyThread* t); @@ -2408,11 +2410,10 @@ longToFloat(int64_t a) } uint64_t -makeBlankObjectArray(MyThread* t, object loader, object class_, int32_t length) +makeBlankObjectArray(MyThread* t, object class_, int32_t length) { if (length >= 0) { - return reinterpret_cast - (makeObjectArray(t, loader, class_, length)); + return reinterpret_cast(makeObjectArray(t, class_, length)); } else { object message = makeString(t, "%d", length); t->exception = t->m->classpath->makeThrowable @@ -2595,14 +2596,14 @@ void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { - t->tracing = true; + atomicOr(&(t->flags), Thread::TracingFlag); t->exception = t->m->classpath->makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType); - t->tracing = false; + (t, Machine::ArrayIndexOutOfBoundsExceptionType); + atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { // not enough memory available for a new exception and stack trace // -- use a preallocated instance instead - t->exception = t->m->arrayIndexOutOfBoundsException; + t->exception = root(t, Machine::ArrayIndexOutOfBoundsException); } unwind(t); @@ -2658,7 +2659,7 @@ makeNew64(Thread* t, object class_) void gcIfNecessary(MyThread* t) { - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } } @@ -3411,9 +3412,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, frame->trace(0, 0), BytesPerWord, Compiler::ObjectType, - 4, c->register_(t->arch->thread()), - frame->append(classLoader(t, methodClass(t, context->method))), - frame->append(class_), length)); + 3, c->register_(t->arch->thread()), frame->append(class_), length)); } break; case areturn: { @@ -4374,16 +4373,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); - if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ReferenceType)) - { + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object class_ = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; frame->pushObject(frame->append(getJClass(t, class_))); - } else if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ClassType)) - { + } else if (objectClass(t, v) == type(t, Machine::ClassType)) { frame->pushObject(frame->append(getJClass(t, v))); } else { frame->pushObject(frame->append(v)); @@ -5723,8 +5718,8 @@ finish(MyThread* t, Allocator* allocator, Context* context) initArray(t, pool, context->objectPoolCount + 1); mark(t, pool, 0); - set(t, pool, ArrayBody, objectPools(t)); - objectPools(t) = pool; + set(t, pool, ArrayBody, root(t, ObjectPools)); + setRoot(t, ObjectPools, pool); unsigned i = 1; for (PoolElement* p = context->objectPool; p; p = p->next) { @@ -6009,14 +6004,6 @@ compileMethod2(MyThread* t, void* ip) t->trace->targetMethod = 0; } - if (false) { - compile(t, codeAllocator(t), 0, resolveMethod - (t, t->m->loader, - "org/eclipse/swt/widgets/TableItem", - "getBounds", - "(IIZZZZJ)Lorg/eclipse/swt/internal/win32/RECT;")); - } - if (UNLIKELY(t->exception)) { return 0; } else { @@ -6494,9 +6481,7 @@ findFrameMap(MyThread* t, void* stack, object method, int32_t offset, int32_t** map, unsigned* start) { object table = codePool(t, methodCode(t, method)); - if (objectClass(t, table) - == arrayBody(t, t->m->types, Machine::IntArrayType)) - { + if (objectClass(t, table) == type(t, Machine::IntArrayType)) { findFrameMapInSimpleTable(t, method, table, offset, map, start); } else { findFrameMapInGeneralTable(t, stack, method, table, offset, map, start); @@ -6813,16 +6798,16 @@ callContinuation(MyThread* t, object continuation, object result, nextContinuation = continuationContextContinuation(t, rewindContext); action = Rewind; - if (rewindMethod(t) == 0) { + if (root(t, RewindMethod) == 0) { PROTECT(t, nextContinuation); object method = resolveMethod - (t, t->m->loader, "avian/Continuations", "rewind", + (t, root(t, Machine::BootLoader), "avian/Continuations", "rewind", "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); if (method) { - rewindMethod(t) = method; + setRoot(t, RewindMethod, method); compile(t, local::codeAllocator(t), 0, method); @@ -6864,7 +6849,7 @@ callContinuation(MyThread* t, object continuation, object result, transition(t, 0, 0, 0, nextContinuation, t->trace); jumpAndInvoke - (t, rewindMethod(t), base, stack, + (t, root(t, RewindMethod), base, stack, continuationContextBefore(t, continuationContext(t, nextContinuation)), continuation, result, exception); } break; @@ -6890,26 +6875,27 @@ callWithCurrentContinuation(MyThread* t, object receiver) { PROTECT(t, receiver); - if (receiveMethod(t) == 0) { + if (root(t, ReceiveMethod) == 0) { object m = resolveMethod - (t, t->m->loader, "avian/CallbackReceiver", "receive", + (t, root(t, Machine::BootLoader), "avian/CallbackReceiver", "receive", "(Lavian/Callback;)Ljava/lang/Object;"); if (m) { - receiveMethod(t) = m; + setRoot(t, ReceiveMethod, m); - object continuationClass = arrayBody - (t, t->m->types, Machine::ContinuationType); + object continuationClass = type(t, Machine::ContinuationType); if (classVmFlags(t, continuationClass) & BootstrapFlag) { - resolveSystemClass(t, vm::className(t, continuationClass)); + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, continuationClass)); } } } if (LIKELY(t->exception == 0)) { method = findInterfaceMethod - (t, receiveMethod(t), objectClass(t, receiver)); + (t, root(t, ReceiveMethod), objectClass(t, receiver)); PROTECT(t, method); compile(t, local::codeAllocator(t), 0, method); @@ -6938,14 +6924,14 @@ dynamicWind(MyThread* t, object before, object thunk, object after) PROTECT(t, thunk); PROTECT(t, after); - if (windMethod(t) == 0) { + if (root(t, WindMethod) == 0) { object method = resolveMethod - (t, t->m->loader, "avian/Continuations", "wind", + (t, root(t, Machine::BootLoader), "avian/Continuations", "wind", "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); if (method) { - windMethod(t) = method; + setRoot(t, WindMethod, method); compile(t, local::codeAllocator(t), 0, method); } } @@ -6962,7 +6948,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) } if (LIKELY(t->exception == 0)) { - jumpAndInvoke(t, windMethod(t), base, stack, before, thunk, after); + jumpAndInvoke(t, root(t, WindMethod), base, stack, before, thunk, after); } else { unwind(t); } @@ -7117,7 +7103,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) } if (t->exception) { - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } return 0; @@ -7173,14 +7159,14 @@ class SegFaultHandler: public System::SignalHandler { *base, t->continuation, t->trace); if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { - t->tracing = true; + atomicOr(&(t->flags), Thread::TracingFlag); t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); - t->tracing = false; + atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { // not enough memory available for a new NPE and stack trace // -- use a preallocated instance instead - t->exception = t->m->nullPointerException; + t->exception = root(t, Machine::NullPointerException); } // printTrace(t, t->exception); @@ -7220,12 +7206,12 @@ boot(MyThread* t, BootImage* image); class MyProcessor; -void -compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p); - MyProcessor* processor(MyThread* t); +void +compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p); + class MyProcessor: public Processor { public: class Thunk { @@ -7255,15 +7241,7 @@ class MyProcessor: public Processor { MyProcessor(System* s, Allocator* allocator, bool useNativeFeatures): s(s), allocator(allocator), - callTable(0), - methodTree(0), - methodTreeSentinal(0), - objectPools(0), - staticTableArray(0), - virtualThunks(0), - receiveMethod(0), - windMethod(0), - rewindMethod(0), + roots(0), bootImage(0), codeAllocator(s, 0, 0), callTableSize(0), @@ -7365,15 +7343,7 @@ class MyProcessor: public Processor { MyThread* t = static_cast(vmt); if (t == t->m->rootThread) { - v->visit(&callTable); - v->visit(&methodTree); - v->visit(&methodTreeSentinal); - v->visit(&objectPools); - v->visit(&staticTableArray); - v->visit(&virtualThunks); - v->visit(&receiveMethod); - v->visit(&windMethod); - v->visit(&rewindMethod); + v->visit(&roots); } for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) { @@ -7499,16 +7469,6 @@ class MyProcessor: public Processor { PROTECT(t, method); - if (false) { - compile(static_cast(t), - local::codeAllocator(static_cast(t)), 0, - resolveMethod(t, t->m->loader, - "com/ecovate/nat/logic/Cache", - "findInCache", - "(Ljava/lang/String;Ljava/lang/String;JZ)Lcom/ecovate/shared/xmlrpc/Resource;")); - trap(); - } - compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); @@ -7636,9 +7596,9 @@ class MyProcessor: public Processor { } if (ensure(t, traceSize(target))) { - t->tracing = true; + atomicOr(&(t->flags), Thread::TracingFlag); trace = makeTrace(t, target); - t->tracing = false; + atomicAnd(&(t->flags), ~Thread::TracingFlag); } } @@ -7650,7 +7610,7 @@ class MyProcessor: public Processor { t->m->system->visit(t->systemThread, target->systemThread, &visitor); - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { PROTECT(t, visitor.trace); collect(t, Heap::MinorCollection); @@ -7679,10 +7639,10 @@ class MyProcessor: public Processor { *addresses = bootContext.addresses; } - virtual void visitRoots(HeapWalker* w) { - bootImage->methodTree = w->visitRoot(methodTree); - bootImage->methodTreeSentinal = w->visitRoot(methodTreeSentinal); - bootImage->virtualThunks = w->visitRoot(virtualThunks); + virtual void visitRoots(Thread* t, HeapWalker* w) { + bootImage->methodTree = w->visitRoot(root(t, MethodTree)); + bootImage->methodTreeSentinal = w->visitRoot(root(t, MethodTreeSentinal)); + bootImage->virtualThunks = w->visitRoot(root(t, VirtualThunks)); } virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) { @@ -7693,8 +7653,10 @@ class MyProcessor: public Processor { (t->m->heap->allocate(callTableSize * sizeof(unsigned) * 2)); unsigned index = 0; - for (unsigned i = 0; i < arrayLength(t, callTable); ++i) { - for (object p = arrayBody(t, callTable, i); p; p = callNodeNext(t, p)) { + for (unsigned i = 0; i < arrayLength(t, root(t, CallTable)); ++i) { + for (object p = arrayBody(t, root(t, CallTable), i); + p; p = callNodeNext(t, p)) + { table[index++] = callNodeAddress(t, p) - reinterpret_cast(codeAllocator.base); table[index++] = w->map()->find(callNodeTarget(t, p)) @@ -7712,14 +7674,19 @@ class MyProcessor: public Processor { codeAllocator.capacity = ExecutableAreaSizeInBytes; } + roots = makeArray(t, RootCount); + if (image) { local::boot(static_cast(t), image); } else { - callTable = makeArray(t, 128); - - methodTree = methodTreeSentinal = makeTreeNode(t, 0, 0, 0); - set(t, methodTree, TreeNodeLeft, methodTreeSentinal); - set(t, methodTree, TreeNodeRight, methodTreeSentinal); + setRoot(t, CallTable, makeArray(t, 128)); + + setRoot(t, MethodTreeSentinal, makeTreeNode(t, 0, 0, 0)); + setRoot(t, MethodTree, root(t, MethodTreeSentinal)); + set(t, root(t, MethodTree), TreeNodeLeft, + root(t, MethodTreeSentinal)); + set(t, root(t, MethodTree), TreeNodeRight, + root(t, MethodTreeSentinal)); } local::compileThunks(static_cast(t), &codeAllocator, this); @@ -7776,43 +7743,10 @@ class MyProcessor: public Processor { abort(t); } } - - virtual void registerNative(Thread* t, object method, void* function) { - PROTECT(t, method); - - expect(t, methodFlags(t, method) & ACC_NATIVE); - - object native = makeNative(t, function, false); - - // ensure other threads only see the methodCode field populated - // once the object it points do has been populated: - storeStoreMemoryBarrier(); - - set(t, method, MethodCode, native); - } - - virtual void unregisterNatives(Thread* t, object c) { - if (classMethodTable(t, c)) { - for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { - object method = arrayBody(t, classMethodTable(t, c), i); - if (methodFlags(t, method) & ACC_NATIVE) { - set(t, method, MethodCode, 0); - } - } - } - } System* s; Allocator* allocator; - object callTable; - object methodTree; - object methodTreeSentinal; - object objectPools; - object staticTableArray; - object virtualThunks; - object receiveMethod; - object windMethod; - object rewindMethod; + object roots; BootImage* bootImage; SegFaultHandler segFaultHandler; FixedAllocator codeAllocator; @@ -7883,11 +7817,10 @@ isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) bool isVirtualThunk(MyThread* t, void* ip) { - MyProcessor* p = processor(t); - - for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { - uintptr_t start = wordArrayBody(t, p->virtualThunks, i); - uintptr_t end = start + wordArrayBody(t, p->virtualThunks, i + 1); + for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) + { + uintptr_t start = wordArrayBody(t, root(t, VirtualThunks), i); + uintptr_t end = start + wordArrayBody(t, root(t, VirtualThunks), i + 1); if (reinterpret_cast(ip) >= start and reinterpret_cast(ip) < end) @@ -7921,8 +7854,7 @@ findCallNode(MyThread* t, void* address) // compile(MyThread*, Allocator*, BootContext*, object)): loadMemoryBarrier(); - MyProcessor* p = processor(t); - object table = p->callTable; + object table = root(t, CallTable); intptr_t key = reinterpret_cast(address); unsigned index = static_cast(key) & (arrayLength(t, table) - 1); @@ -8002,8 +7934,8 @@ insertCallNode(MyThread* t, object table, unsigned* size, object node) void insertCallNode(MyThread* t, object node) { - MyProcessor* p = processor(t); - p->callTable = insertCallNode(t, p->callTable, &(p->callTableSize), node); + setRoot(t, CallTable, insertCallNode + (t, root(t, CallTable), &(processor(t)->callTableSize), node)); } object @@ -8022,14 +7954,19 @@ makeClassMap(Thread* t, unsigned* table, unsigned count, uintptr_t* heap) } object -makeStaticTableArray(Thread* t, unsigned* table, unsigned count, - uintptr_t* heap) +makeStaticTableArray(Thread* t, unsigned* bootTable, unsigned bootCount, + unsigned* appTable, unsigned appCount, uintptr_t* heap) { - object array = makeArray(t, count); + object array = makeArray(t, bootCount + appCount); - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < bootCount; ++i) { set(t, array, ArrayBody + (i * BytesPerWord), - classStaticTable(t, bootObject(heap, table[i]))); + classStaticTable(t, bootObject(heap, bootTable[i]))); + } + + for (unsigned i = 0; i < appCount; ++i) { + set(t, array, ArrayBody + ((bootCount + i) * BytesPerWord), + classStaticTable(t, bootObject(heap, appTable[i]))); } return array; @@ -8134,9 +8071,9 @@ fixupCode(Thread* t, uintptr_t* map, unsigned size, uint8_t* code, } void -fixupMethods(Thread* t, BootImage* image, uint8_t* code) +fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) { - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { + for (HashMapIterator it(t, map); it.hasMore();) { object c = tripleSecond(t, it.next()); if (classMethodTable(t, c)) { @@ -8213,12 +8150,10 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) void fixupVirtualThunks(MyThread* t, BootImage* image, uint8_t* code) { - MyProcessor* p = processor(t); - - for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { - if (wordArrayBody(t, p->virtualThunks, i)) { - wordArrayBody(t, p->virtualThunks, i) - = (wordArrayBody(t, p->virtualThunks, i) - image->codeBase) + for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) { + if (wordArrayBody(t, root(t, VirtualThunks), i)) { + wordArrayBody(t, root(t, VirtualThunks), i) + = (wordArrayBody(t, root(t, VirtualThunks), i) - image->codeBase) + reinterpret_cast(code); } } @@ -8229,8 +8164,9 @@ boot(MyThread* t, BootImage* image) { assert(t, image->magic == BootImage::Magic); - unsigned* classTable = reinterpret_cast(image + 1); - unsigned* stringTable = classTable + image->classCount; + unsigned* bootClassTable = reinterpret_cast(image + 1); + unsigned* appClassTable = bootClassTable + image->bootClassCount; + unsigned* stringTable = appClassTable + image->appClassCount; unsigned* callTable = stringTable + image->stringCount; uintptr_t* heapMap = reinterpret_cast @@ -8254,39 +8190,48 @@ boot(MyThread* t, BootImage* image) t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); - t->m->loader = bootObject(heap, image->loader); + setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); + setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); t->m->types = bootObject(heap, image->types); MyProcessor* p = static_cast(t->m->processor); - p->methodTree = bootObject(heap, image->methodTree); - p->methodTreeSentinal = bootObject(heap, image->methodTreeSentinal); + setRoot(t, MethodTree, bootObject(heap, image->methodTree)); + setRoot(t, MethodTreeSentinal, bootObject(heap, image->methodTreeSentinal)); - p->virtualThunks = bootObject(heap, image->virtualThunks); + setRoot(t, VirtualThunks, bootObject(heap, image->virtualThunks)); fixupCode(t, codeMap, codeMapSizeInWords, code, heap); syncInstructionCache(code, image->codeSize); - t->m->classMap = makeClassMap(t, classTable, image->classCount, heap); + setRoot(t, Machine::ClassMap, makeClassMap + (t, bootClassTable, image->bootClassCount, heap)); - t->m->stringMap = makeStringMap(t, stringTable, image->stringCount, heap); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, makeClassMap + (t, appClassTable, image->appClassCount, heap)); + + setRoot(t, Machine::StringMap, makeStringMap + (t, stringTable, image->stringCount, heap)); p->callTableSize = image->callCount; - p->callTable = makeCallTable - (t, heap, callTable, image->callCount, - reinterpret_cast(code)); - p->staticTableArray = makeStaticTableArray - (t, classTable, image->classCount, heap); + setRoot(t, CallTable, makeCallTable + (t, heap, callTable, image->callCount, + reinterpret_cast(code))); + setRoot(t, StaticTableArray, makeStaticTableArray + (t, bootClassTable, image->bootClassCount, + appClassTable, image->appClassCount, heap)); + fixupThunks(t, image, code); fixupVirtualThunks(t, image, code); - fixupMethods(t, image, code); + fixupMethods(t, root(t, Machine::ClassMap), image, code); + fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); - t->m->bootstrapClassMap = makeHashMap(t, 0, 0); + setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); } intptr_t @@ -8539,30 +8484,6 @@ processor(MyThread* t) return static_cast(t->m->processor); } -object& -objectPools(MyThread* t) -{ - return processor(t)->objectPools; -} - -object& -windMethod(MyThread* t) -{ - return processor(t)->windMethod; -} - -object& -rewindMethod(MyThread* t) -{ - return processor(t)->rewindMethod; -} - -object& -receiveMethod(MyThread* t) -{ - return processor(t)->receiveMethod; -} - uintptr_t defaultThunk(MyThread* t) { @@ -8639,32 +8560,30 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) uintptr_t virtualThunk(MyThread* t, unsigned index) { - MyProcessor* p = processor(t); - - if (p->virtualThunks == 0 - or wordArrayLength(t, p->virtualThunks) <= index * 2) + if (root(t, VirtualThunks) == 0 + or wordArrayLength(t, root(t, VirtualThunks)) <= index * 2) { object newArray = makeWordArray(t, nextPowerOfTwo((index + 1) * 2)); - if (p->virtualThunks) { + if (root(t, VirtualThunks)) { memcpy(&wordArrayBody(t, newArray, 0), - &wordArrayBody(t, p->virtualThunks, 0), - wordArrayLength(t, p->virtualThunks) * BytesPerWord); + &wordArrayBody(t, root(t, VirtualThunks), 0), + wordArrayLength(t, root(t, VirtualThunks)) * BytesPerWord); } - p->virtualThunks = newArray; + setRoot(t, VirtualThunks, newArray); } - if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { + if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { ACQUIRE(t, t->m->classLock); - if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { + if (wordArrayBody(t, root(t, VirtualThunks), index * 2) == 0) { unsigned size; uintptr_t thunk = compileVirtualThunk(t, index, &size); - wordArrayBody(t, p->virtualThunks, index * 2) = thunk; - wordArrayBody(t, p->virtualThunks, (index * 2) + 1) = size; + wordArrayBody(t, root(t, VirtualThunks), index * 2) = thunk; + wordArrayBody(t, root(t, VirtualThunks), (index * 2) + 1) = size; } } - return wordArrayBody(t, p->virtualThunks, index * 2); + return wordArrayBody(t, root(t, VirtualThunks), index * 2); } void @@ -8717,10 +8636,12 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, methodCode(t, method), reinterpret_cast(compiled)); - methodTree(t) = treeInsert - (t, &(context.zone), methodTree(t), - reinterpret_cast(compiled), clone, methodTreeSentinal(t), - compareIpToMethodBounds); + setRoot + (t, MethodTree, treeInsert + (t, &(context.zone), root(t, MethodTree), + reinterpret_cast(compiled), clone, + root(t, MethodTreeSentinal), + compareIpToMethodBounds)); storeStoreMemoryBarrier(); @@ -8731,22 +8652,23 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, = compiled; } - treeUpdate(t, methodTree(t), reinterpret_cast(compiled), - method, methodTreeSentinal(t), compareIpToMethodBounds); + treeUpdate(t, root(t, MethodTree), reinterpret_cast(compiled), + method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } } } object& -methodTree(MyThread* t) +root(Thread* t, Root root) { - return processor(t)->methodTree; + return arrayBody(t, processor(static_cast(t))->roots, root); } -object -methodTreeSentinal(MyThread* t) +void +setRoot(Thread* t, Root root, object value) { - return processor(t)->methodTreeSentinal; + set(t, processor(static_cast(t))->roots, + ArrayBody + (root * BytesPerWord), value); } FixedAllocator* diff --git a/src/continuations-x86.S b/src/continuations-x86.S index 5dc0ba9e10..c55679d0ba 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 2232 +#define THREAD_CONTINUATION 2224 #define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2240 -#define THREAD_EXCEPTION_OFFSET 2248 -#define THREAD_EXCEPTION_HANDLER 2256 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232 +#define THREAD_EXCEPTION_OFFSET 2240 +#define THREAD_EXCEPTION_HANDLER 2248 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 diff --git a/src/gnu.cpp b/src/gnu.cpp deleted file mode 100644 index 84e7193ee6..0000000000 --- a/src/gnu.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* Copyright (c) 2009, 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. */ - -#include "machine.h" -#include "constants.h" -#include "processor.h" -#include "util.h" - -using namespace vm; - -namespace { - -void -setProperty(Thread* t, object method, object properties, - const char* name, const void* value, const char* format = "%s") -{ - PROTECT(t, method); - PROTECT(t, properties); - - object n = makeString(t, "%s", name); - PROTECT(t, n); - - object v = makeString(t, format, value); - - t->m->processor->invoke(t, method, properties, n, v); -} - -} // namespace - -namespace vm { - -jobject JNICALL -NewDirectByteBuffer(Thread* t, void* address, jlong capacity) -{ - const char* pointerClassName; - const char* initSpec; - if (BytesPerWord == 8) { - pointerClassName = "gnu/classpath/Pointer64"; - initSpec = "(J)V"; - } else { - pointerClassName = "gnu/classpath/Pointer32"; - initSpec = "(I)V"; - } - - object pointerClass = resolveClass(t, t->m->loader, pointerClassName); - if (UNLIKELY(pointerClass == 0)) return 0; - PROTECT(t, pointerClass); - - object pointerConstructor = resolveMethod - (t, pointerClass, "", initSpec); - if (UNLIKELY(pointerConstructor == 0)) return 0; - - object pointer = make(t, pointerClass); - PROTECT(t, pointer); - - t->m->processor->invoke(t, pointerConstructor, pointer, address); - if (UNLIKELY(t->exception)) return 0; - - object bufferClass = resolveClass - (t, t->m->loader, "java/nio/DirectByteBufferImpl$ReadWrite"); - if (UNLIKELY(bufferClass == 0)) return 0; - PROTECT(t, bufferClass); - - object bufferConstructor = resolveMethod - (t, bufferClass, "", "(Lgnu/classpath/Pointer;int)V"); - if (UNLIKELY(bufferConstructor == 0)) return 0; - - object buffer = make(t, bufferClass); - PROTECT(t, buffer); - - t->m->processor->invoke - (t, bufferConstructor, buffer, &pointer, static_cast(capacity)); - if (UNLIKELY(t->exception)) return 0; - - return makeLocalReference(t, buffer); -} - -void* JNICALL -GetDirectBufferAddress(Thread* t, jobject buffer) -{ - object addressField = resolveField - (t, objectClass(t, *buffer), "address", "Lgnu/classpath/Pointer;"); - if (UNLIKELY(addressField == 0)) return 0; - - object address = cast(*buffer, fieldOffset(t, addressField)); - if (address == 0) return 0; - - const char* dataSpec; - if (BytesPerWord == 8) { - dataSpec = "J"; - } else { - dataSpec = "I"; - } - - object dataField = resolveField - (t, objectClass(t, address), "data", dataSpec); - if (UNLIKELY(dataField == 0)) return 0; - - return cast(address, fieldOffset(t, dataField)); -} - -jlong JNICALL -GetDirectBufferCapacity(Thread* t, jobject buffer) -{ - object capField = resolveField(t, objectClass(t, *buffer), "cap", "I"); - if (UNLIKELY(capField == 0)) return 0; - - return cast(*buffer, fieldOffset(t, capField)); -} - -} // namespace vm - -extern "C" JNIEXPORT void JNICALL -Avian_gnu_classpath_VMSystemProperties_preInit -(Thread* t, object, uintptr_t* arguments) -{ - object properties = reinterpret_cast(arguments[0]); - PROTECT(t, properties); - - object method = resolveMethod - (t, t->m->loader, "java/util/Properties", "setProperty", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); - - if (UNLIKELY(t->exception)) { - return; - } - - PROTECT(t, method); - - setProperty(t, method, properties, "java.version", "1.5"); - setProperty(t, method, properties, "java.specification.version", "1.5"); - - setProperty(t, method, properties, "java.vm.name", "Avian"); - - setProperty(t, method, properties, "java.protocol.handler.pkgs", "avian"); - - setProperty(t, method, properties, "file.encoding", "ASCII"); - - // specify a bogus library path so we can do our own search in - // VMRuntime.nativeLoad: -#define LIBRARY_PATH_SENTINAL "*" - setProperty(t, method, properties, "java.library.path", - LIBRARY_PATH_SENTINAL); - -#ifdef PLATFORM_WINDOWS -# define FILE_SEPARATOR "\\" - - setProperty(t, method, properties, "line.separator", "\r\n"); - setProperty(t, method, properties, "file.separator", FILE_SEPARATOR); - setProperty(t, method, properties, "path.separator", ";"); - setProperty(t, method, properties, "os.name", "Windows"); - - TCHAR buffer[MAX_PATH]; - GetTempPath(MAX_PATH, buffer); - setProperty(t, method, properties, "java.io.tmpdir", buffer); - setProperty(t, method, properties, "java.home", buffer); - - setProperty(t, method, properties, "user.home", - _wgetenv(L"USERPROFILE"), "%ls"); - - GetCurrentDirectory(MAX_PATH, buffer); - setProperty(t, method, properties, "user.dir", buffer); -#else -# define FILE_SEPARATOR "/" - - setProperty(t, method, properties, "line.separator", "\n"); - setProperty(t, method, properties, "file.separator", FILE_SEPARATOR); - setProperty(t, method, properties, "path.separator", ":"); -# ifdef __APPLE__ - setProperty(t, method, properties, "os.name", "Mac OS X"); -# else - setProperty(t, method, properties, "os.name", "Linux"); -# endif - setProperty(t, method, properties, "java.io.tmpdir", "/tmp"); - setProperty(t, method, properties, "java.home", "/tmp"); - setProperty(t, method, properties, "user.home", getenv("HOME")); - setProperty(t, method, properties, "user.dir", getenv("PWD")); -#endif - -#ifdef ARCH_x86_32 - setProperty(t, method, properties, "gnu.cpu.endian", "little"); - setProperty(t, method, properties, "os.arch", "x86"); -#elif defined ARCH_x86_64 - setProperty(t, method, properties, "gnu.cpu.endian", "little"); - setProperty(t, method, properties, "os.arch", "x86_64"); -#elif defined ARCH_powerpc - setProperty(t, method, properties, "gnu.cpu.endian", "big"); - setProperty(t, method, properties, "os.arch", "ppc"); -#elif defined ARCH_arm - setProperty(t, method, properties, "os.arch", "arm"); -#else - setProperty(t, method, properties, "os.arch", "unknown"); -#endif -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_gnu_classpath_VMStackWalker_getClassContext -(Thread* t, object, uintptr_t*) -{ - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t): - t(t), skipCount(1), trace(0), index(0), protector(t, &trace) - { } - - virtual bool visit(Processor::StackWalker* walker) { - if (skipCount == 0) { - if (trace == 0) { - trace = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), - walker->count()); - } - - assert(t, index < objectArrayLength(t, trace)); - - set(t, trace, ArrayBody + (index * BytesPerWord), - methodClass(t, walker->method())); - - ++ index; - return true; - } else { - -- skipCount; - return true; - } - } - - Thread* t; - unsigned skipCount; - object trace; - unsigned index; - Thread::SingleProtector protector; - } v(t); - - t->m->processor->walkStack(t, &v); - - if (v.trace == 0) { - v.trace = makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::ClassType), 0); - } - - return reinterpret_cast(v.trace); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_gnu_classpath_VMStackWalker_getClassLoader -(Thread* t, object, uintptr_t* arguments) -{ - return reinterpret_cast - (classLoader(t, reinterpret_cast(arguments[0]))); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMRuntime_mapLibraryName -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - PROTECT(t, name); - - const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1; - const unsigned nameLength = stringLength(t, name); - const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1; - const unsigned total = soPrefixLength + nameLength + soSuffixLength; - - object s = makeByteArray(t, total + 1); - char* p = reinterpret_cast(&byteArrayBody(t, s, 0)); - - memcpy(p, SO_PREFIX, soPrefixLength); - stringChars(t, name, p + soPrefixLength); - memcpy(p + soPrefixLength + nameLength, SO_SUFFIX, soSuffixLength); - p[total] = 0; - - return reinterpret_cast(makeString(t, s, 0, total, 0)); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_System_arraycopy -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMSystem_arraycopy -(Thread* t, object, uintptr_t* arguments) -{ - Avian_java_lang_System_arraycopy(t, 0, arguments); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_load -(Thread* t, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMRuntime_nativeLoad -(Thread* t, object, uintptr_t* arguments) -{ - object name = reinterpret_cast(arguments[0]); - - // given that we set java.library.path to LIBRARY_PATH_SENTINAL, we - // can determine which names are filenames and which are library - // names by looking for the prefix LIBRARY_PATH_SENTINAL - // FILE_SEPARATOR - - unsigned length = stringLength(t, name); - char n[length + 1]; - stringChars(t, name, n); - - const unsigned pathPrefixLength - = sizeof(LIBRARY_PATH_SENTINAL) - 1 - + sizeof(FILE_SEPARATOR) - 1; - - bool mapName = (strncmp(n, LIBRARY_PATH_SENTINAL FILE_SEPARATOR, - pathPrefixLength) == 0); - if (mapName) { - // strip the path prefix, SO prefix, and SO suffix before passing - // the name to Runtime.load - - const unsigned soPrefixLength = sizeof(SO_PREFIX) - 1; - const unsigned soSuffixLength = sizeof(SO_SUFFIX) - 1; - const unsigned newOffset - = stringOffset(t, name) + pathPrefixLength + soPrefixLength; - const unsigned newLength - = length - pathPrefixLength - soPrefixLength - soSuffixLength; - - name = makeString(t, stringData(t, name), newOffset, newLength, 0); - } - - uintptr_t args[] = { reinterpret_cast(name), mapName }; - - Avian_java_lang_Runtime_load(t, 0, args); - - if (t->exception) { - t->exception = 0; - return 0; - } else { - return 1; - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_Class_primitiveClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_getPrimitiveClass -(Thread* t, object, uintptr_t* arguments) -{ - return Avian_java_lang_Class_primitiveClass(t, 0, arguments); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_defineClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_defineClass -(Thread* t, object, uintptr_t* arguments) -{ - uintptr_t args[] - = { arguments[0], arguments[2], arguments[3], arguments[4] }; - -// object name = reinterpret_cast(arguments[1]); -// char n[stringLength(t, name) + 1]; -// stringChars(t, name, n); -// fprintf(stderr, "define class %s in %p\n", n, -// reinterpret_cast(arguments[0])); - - return Avian_avian_SystemClassLoader_defineClass(t, 0, args); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_System_identityHashCode -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMSystem_identityHashCode -(Thread* t, object, uintptr_t* arguments) -{ - return Avian_java_lang_System_identityHashCode(t, 0, arguments); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Runtime_gc -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_gc -(Thread* t, object, uintptr_t*) -{ - Avian_java_lang_Runtime_gc(t, 0, 0); -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_runFinalizationForExit -(Thread*, object, uintptr_t*) -{ - // ignore -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMRuntime_exit -(Thread*, object, uintptr_t* arguments) -{ - exit(arguments[0]); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_avian_SystemClassLoader_findClass -(Thread*, object, uintptr_t*); - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_loadClass -(Thread* t, object, uintptr_t* arguments) -{ - uintptr_t args[] = { 0, arguments[0] }; - - // object name = reinterpret_cast(arguments[0]); - // char n[stringLength(t, name) + 1]; - // stringChars(t, name, n); - // fprintf(stderr, "load bootstrap class %s in %p\n", n, t->m->loader); - - int64_t result = Avian_avian_SystemClassLoader_findClass(t, 0, args); - - // fprintf(stderr, "result %p\n", reinterpret_cast(result)); - - return result; -} - -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_VMClassLoader_resolveClass -(Thread*, object, uintptr_t*) -{ - // ignore -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_lang_VMClassLoader_findLoadedClass -(Thread* t, object, uintptr_t* arguments) -{ - object loader = reinterpret_cast(arguments[0]); - - object map = getClassLoaderMap(t, loader); - if (map) { - PROTECT(t, loader); - - object name = reinterpret_cast(arguments[1]); - PROTECT(t, name); - - object n = makeByteArray(t, stringLength(t, name) + 1); - char* s = reinterpret_cast(&byteArrayBody(t, n, 0)); - stringChars(t, name, s); - - replace('.', '/', s); - - return reinterpret_cast - (hashMapFind - (t, getClassLoaderMap(t, loader), n, byteArrayHash, byteArrayEqual)); - } else { - return 0; - } -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_compareAndSwapInt -(Thread*, object, uintptr_t* arguments) -{ - object target = reinterpret_cast(arguments[1]); - int64_t offset; memcpy(&offset, arguments + 2, 8); - int32_t expect = arguments[4]; - int32_t update = arguments[5]; - - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_compareAndSwapLong -(Thread*, object, uintptr_t* arguments) -{ - object target = reinterpret_cast(arguments[1]); - int64_t offset; memcpy(&offset, arguments + 2, 8); - int64_t expect; memcpy(&expect, arguments + 4, 8); - int64_t update; memcpy(&update, arguments + 6, 8); - - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_objectFieldOffset -(Thread* t, object, uintptr_t* arguments) -{ - return fieldOffset(t, reinterpret_cast(arguments[1])); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8 -(Thread*, object, uintptr_t*) -{ - return 0; -} diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 41730b0fb6..100a3c7b3d 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -76,8 +76,7 @@ dumpHeap(Thread* t, FILE* out) local::write1(out, local::Size); local::write4(out, local::objectSize(t, p)); - if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) - { + if (objectClass(t, p) == type(t, Machine::ClassType)) { object name = className(t, p); if (name) { local::write1(out, local::ClassName); diff --git a/src/interpret.cpp b/src/interpret.cpp index 7d362c27d9..a228d6f696 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -429,80 +429,17 @@ class MyStackWalker: public Processor::StackWalker { int frame; }; -object -makeNativeMethodData(Thread* t, object method, void* function) -{ - PROTECT(t, method); - - unsigned count = methodParameterCount(t, method) + 2; - - object data = makeNativeMethodData(t, - function, - 0, // argument table size - count); - - unsigned argumentTableSize = BytesPerWord * 2; - unsigned index = 0; - - nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE; - nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE; - - const char* s = reinterpret_cast - (&byteArrayBody(t, methodSpec(t, method), 0)); - ++ s; // skip '(' - while (*s and *s != ')') { - unsigned code = fieldCode(t, *s); - nativeMethodDataParameterTypes(t, data, index++) = fieldType(t, code); - - switch (*s) { - case 'L': - argumentTableSize += BytesPerWord; - while (*s and *s != ';') ++ s; - ++ s; - break; - - case '[': - argumentTableSize += BytesPerWord; - while (*s == '[') ++ s; - switch (*s) { - case 'L': - while (*s and *s != ';') ++ s; - ++ s; - break; - - default: - ++ s; - break; - } - break; - - default: - argumentTableSize += pad(primitiveSize(t, code)); - ++ s; - break; - } - } - - nativeMethodDataArgumentTableSize(t, data) = argumentTableSize; - - return data; -} - inline void -resolveNativeMethodData(Thread* t, object method) +resolveNative(Thread* t, object method) { if (methodCode(t, method) == 0) { - void* p = resolveNativeMethod(t, method); - if (LIKELY(p)) { - PROTECT(t, method); - object data = makeNativeMethodData(t, method, p); - - // ensure other threads see updated methodVmFlags before - // methodCode, and that the native method data is initialized - // before it is visible to those threads: + object native = resolveNativeMethod(t, method); + if (LIKELY(native)) { + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: storeStoreMemoryBarrier(); - set(t, method, MethodCode, data); + set(t, method, MethodCode, native); } else { object message = makeString (t, "%s.%s%s", @@ -600,27 +537,35 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) } void -marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, - object data, bool indirect) +marshalArguments(Thread* t, uintptr_t* args, uint8_t* types, unsigned sp, + object method, bool indirect) { - unsigned offset = 0; - unsigned sp = frameBase(t, t->frame); - for (; i < count; ++i) { - unsigned type = nativeMethodDataParameterTypes(t, data, i + 1); + MethodSpecIterator it + (t, reinterpret_cast + (&byteArrayBody(t, methodSpec(t, method), 0))); + + unsigned argOffset = 0; + unsigned typeOffset = 0; + + while (it.hasNext()) { + unsigned type = fieldType(t, fieldCode(t, *it.next())); + if (types) { + types[typeOffset++] = type; + } switch (type) { case INT8_TYPE: case INT16_TYPE: case INT32_TYPE: case FLOAT_TYPE: - args[offset++] = peekInt(t, sp++); + args[argOffset++] = peekInt(t, sp++); break; case DOUBLE_TYPE: case INT64_TYPE: { uint64_t v = peekLong(t, sp); - memcpy(args + offset, &v, 8); - offset += (8 / BytesPerWord); + memcpy(args + argOffset, &v, 8); + argOffset += (8 / BytesPerWord); sp += 2; } break; @@ -630,9 +575,9 @@ marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, if (*v == 0) { v = 0; } - args[offset++] = reinterpret_cast(v); + args[argOffset++] = reinterpret_cast(v); } else { - args[offset++] = reinterpret_cast(peekObject(t, sp++)); + args[argOffset++] = reinterpret_cast(peekObject(t, sp++)); } } break; @@ -642,39 +587,51 @@ marshalArguments(Thread* t, uintptr_t* args, unsigned i, unsigned count, } unsigned -invokeNativeSlow(Thread* t, object method) +invokeNativeSlow(Thread* t, object method, void* function) { PROTECT(t, method); - object data = methodCode(t, method); - PROTECT(t, data); - pushFrame(t, method); - unsigned count = nativeMethodDataLength(t, data) - 1; - - unsigned size = nativeMethodDataArgumentTableSize(t, data); - uintptr_t args[size / BytesPerWord]; - unsigned offset = 0; - - args[offset++] = reinterpret_cast(t); - - unsigned i = 0; + unsigned footprint = methodParameterFootprint(t, method) + 1; if (methodFlags(t, method) & ACC_STATIC) { - ++ i; - args[offset++] = reinterpret_cast - (pushReference(t, methodClass(t, method))); + ++ footprint; } + unsigned count = methodParameterCount(t, method) + 2; - marshalArguments(t, args + offset, i, count, data, true); + RUNTIME_ARRAY(uintptr_t, args, footprint); + unsigned argOffset = 0; + RUNTIME_ARRAY(uint8_t, types, count); + unsigned typeOffset = 0; + + RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); + RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; + + object jclass = 0; + PROTECT(t, jclass); + + unsigned sp; + if (methodFlags(t, method) & ACC_STATIC) { + sp = frameBase(t, t->frame); + jclass = getJClass(t, methodClass(t, method)); + RUNTIME_ARRAY_BODY(args)[argOffset++] + = reinterpret_cast(&jclass); + } else { + sp = frameBase(t, t->frame); + object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); + if (*v == 0) { + v = 0; + } + RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(v); + } + RUNTIME_ARRAY_BODY(types)[typeOffset++] = POINTER_TYPE; + + marshalArguments + (t, RUNTIME_ARRAY_BODY(args) + argOffset, + RUNTIME_ARRAY_BODY(types) + typeOffset, sp, method, true); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); - void* function = nativeMethodDataFunction(t, data); - uint8_t types[nativeMethodDataLength(t, data)]; - memcpy(&types, - &nativeMethodDataParameterTypes(t, data, 0), - nativeMethodDataLength(t, data)); uint64_t result; if (DebugRun) { @@ -682,25 +639,15 @@ invokeNativeSlow(Thread* t, object method) &byteArrayBody(t, className(t, methodClass(t, method)), 0), &byteArrayBody(t, methodName(t, method), 0)); } - - // if (strcmp(reinterpret_cast - // (&byteArrayBody(t, className(t, methodClass(t, method)), 0)), - // "org/eclipse/swt/internal/C") == 0 - // and strcmp(reinterpret_cast - // (&byteArrayBody(t, methodName(t, method), 0)), - // "memmove") == 0) - // { - // asm("int3"); - // } - + { ENTER(t, Thread::IdleState); result = t->m->system->call (function, - args, - types, - count + 1, - size, + RUNTIME_ARRAY_BODY(args), + RUNTIME_ARRAY_BODY(types), + count, + footprint * BytesPerWord, returnType); } @@ -728,24 +675,32 @@ invokeNative(Thread* t, object method) { PROTECT(t, method); - resolveNativeMethodData(t, method); + resolveNative(t, method); if (UNLIKELY(t->exception)) { return VoidField; } - if (methodVmFlags(t, method) & FastNative) { + object native = methodCode(t, method); + if (nativeFast(t, native)) { pushFrame(t, method); - object data = methodCode(t, method); - uintptr_t arguments[methodParameterFootprint(t, method)]; + unsigned footprint = methodParameterFootprint(t, method) + 1; + RUNTIME_ARRAY(uintptr_t, args, footprint); + unsigned sp = frameBase(t, t->frame); + unsigned argOffset = 0; + if (methodFlags(t, method) & ACC_STATIC) { + ++ footprint; + } else { + RUNTIME_ARRAY_BODY(args)[argOffset++] + = reinterpret_cast(peekObject(t, sp++)); + } + marshalArguments - (t, arguments, (methodFlags(t, method) & ACC_STATIC) ? 1 : 0, - nativeMethodDataLength(t, data) - 1, data, false); + (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, false); uint64_t result = reinterpret_cast - (nativeMethodDataFunction(t, methodCode(t, method))) - (t, method, arguments); + (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); popFrame(t); @@ -757,7 +712,7 @@ invokeNative(Thread* t, object method) return methodReturnCode(t, method); } else { - return invokeNativeSlow(t, method); + return invokeNativeSlow(t, method, nativeFunction(t, native)); } } @@ -1004,9 +959,7 @@ interpret(Thread* t) object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); if (UNLIKELY(exception)) goto throw_; - pushObject(t, makeObjectArray - (t, classLoader(t, methodClass(t, frameMethod(t, frame))), - class_, count)); + pushObject(t, makeObjectArray(t, class_, count)); } else { object message = makeString(t, "%d", count); exception = t->m->classpath->makeThrowable @@ -1070,9 +1023,7 @@ interpret(Thread* t) object array = popObject(t); if (LIKELY(array)) { - if (objectClass(t, array) - == arrayBody(t, t->m->types, Machine::BooleanArrayType)) - { + if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) @@ -1113,9 +1064,7 @@ interpret(Thread* t) object array = popObject(t); if (LIKELY(array)) { - if (objectClass(t, array) - == arrayBody(t, t->m->types, Machine::BooleanArrayType)) - { + if (objectClass(t, array) == type(t, Machine::BooleanArrayType)) { if (LIKELY(index >= 0 and static_cast(index) < booleanArrayLength(t, array))) @@ -2259,17 +2208,13 @@ interpret(Thread* t) if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); - if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ReferenceType)) - { + if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object class_ = resolveClassInPool (t, frameMethod(t, frame), index - 1); if (UNLIKELY(exception)) goto throw_; pushObject(t, getJClass(t, class_)); - } else if (objectClass(t, v) - == arrayBody(t, t->m->types, Machine::ClassType)) - { + } else if (objectClass(t, v) == type(t, Machine::ClassType)) { pushObject(t, getJClass(t, v)); } else { pushObject(t, v); @@ -3031,7 +2976,7 @@ invoke(Thread* t, object method) class_ = objectClass(t, peekObject(t, t->sp - parameterFootprint)); if (classVmFlags(t, class_) & BootstrapFlag) { - resolveClass(t, t->m->loader, className(t, class_)); + resolveClass(t, root(t, Machine::BootLoader), className(t, class_)); } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { @@ -3333,7 +3278,7 @@ class MyProcessor: public Processor { abort(s); } - virtual void visitRoots(HeapWalker*) { + virtual void visitRoots(vm::Thread*, HeapWalker*) { abort(s); } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 02c7af652e..ed36e9451d 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -176,9 +176,7 @@ GetStringCritical(Thread* t, jstring s, jboolean* isCopy) } object data = stringData(t, *s); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return GetStringChars(t, s, isCopy); } else { return &charArrayBody(t, data, stringOffset(t, *s)); @@ -188,9 +186,7 @@ GetStringCritical(Thread* t, jstring s, jboolean* isCopy) void JNICALL ReleaseStringCritical(Thread* t, jstring s, const jchar* chars) { - if (objectClass(t, stringData(t, *s)) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, stringData(t, *s)) == type(t, Machine::ByteArrayType)) { ReleaseStringChars(t, s, chars); } @@ -294,7 +290,7 @@ DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, ENTER(t, Thread::ActiveState); object c = defineClass - (t, loader ? *loader : t->m->loader, + (t, loader ? *loader : root(t, Machine::BootLoader), reinterpret_cast(buffer), length); return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); @@ -308,7 +304,7 @@ FindClass(Thread* t, const char* name) object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); - object c = resolveClass(t, t->m->loader, n); + object c = resolveClass(t, root(t, Machine::AppLoader), n); return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); } @@ -430,8 +426,9 @@ methodID(Thread* t, object method) ACQUIRE(t, t->m->referenceLock); if (methodNativeID(t, method) == 0) { - t->m->jniMethodTable = vectorAppend(t, t->m->jniMethodTable, method); - methodNativeID(t, method) = vectorSize(t, t->m->jniMethodTable); + setRoot(t, Machine::JNIMethodTable, vectorAppend + (t, root(t, Machine::JNIMethodTable), method)); + methodNativeID(t, method) = vectorSize(t, root(t, Machine::JNIMethodTable)); } } @@ -470,7 +467,7 @@ GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) inline object getMethod(Thread* t, jmethodID m) { - object method = vectorBody(t, t->m->jniMethodTable, m - 1); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); @@ -733,7 +730,7 @@ CallVoidMethod(Thread* t, jobject o, jmethodID m, ...) inline object getStaticMethod(Thread* t, jmethodID m) { - object method = vectorBody(t, t->m->jniMethodTable, m - 1); + object method = vectorBody(t, root(t, Machine::JNIMethodTable), m - 1); assert(t, methodFlags(t, method) & ACC_STATIC); @@ -1342,9 +1339,7 @@ NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) { ENTER(t, Thread::ActiveState); - object a = makeObjectArray - (t, classLoader(t, jclassVmClass(t, *class_)), jclassVmClass(t, *class_), - length); + object a = makeObjectArray(t, jclassVmClass(t, *class_), length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); @@ -1934,7 +1929,7 @@ RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, object method = findMethod(t, c, methods[i].name, methods[i].signature); if (UNLIKELY(t->exception)) return -1; - t->m->processor->registerNative(t, method, methods[i].function); + registerNative(t, method, methods[i].function); } } @@ -1946,7 +1941,7 @@ UnregisterNatives(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - t->m->processor->unregisterNatives(t, *c); + unregisterNatives(t, *c); return 0; } @@ -2314,21 +2309,21 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); unsigned bcpal = strlen(bootClasspathAppend); - unsigned cpl = strlen(classpath); - - unsigned classpathBufferSize = bcppl + bcpl + bcpal + cpl + 4; - RUNTIME_ARRAY(char, classpathBuffer, classpathBufferSize); - char* classpathPointer = RUNTIME_ARRAY_BODY(classpathBuffer); + unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; + RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); + char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); local::append - (&classpathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); - local::append(&classpathPointer, bootClasspath, bcpl, PATH_SEPARATOR); - local::append(&classpathPointer, bootClasspathAppend, bcpal, PATH_SEPARATOR); - local::append(&classpathPointer, classpath, cpl, 0); + (&bootClasspathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); + local::append(&bootClasspathPointer, bootClasspath, bcpl, + bcpal ? PATH_SEPARATOR : 0); + local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); - Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary); + Finder* bf = makeFinder + (s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); + Finder* af = makeFinder(s, classpath, bootLibrary); Processor* p = makeProcessor(s, h, true); Classpath* c = makeClasspath(s, h); @@ -2342,15 +2337,9 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) } *m = new (h->allocate(sizeof(Machine))) - Machine(s, h, f, p, c, properties, propertyCount); + Machine(s, h, bf, af, p, c, properties, propertyCount); *t = p->makeThread(*m, 0, 0); - enter(*t, Thread::ActiveState); - - c->boot(*t); - - enter(*t, Thread::IdleState); - return 0; } diff --git a/src/machine.cpp b/src/machine.cpp index e1d2af8ec6..63ba9c60fa 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -167,25 +167,29 @@ turnOffTheLights(Thread* t) enter(t, Thread::ExitState); - for (object* p = &(t->m->finalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + { object p = 0; + PROTECT(t, p); - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); + for (p = t->m->finalizers; p;) { + object f = p; + p = finalizerNext(t, p); + + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } } - } - for (object* p = &(t->m->tenuredFinalizers); *p;) { - object f = *p; - *p = finalizerNext(t, *p); + for (p = t->m->tenuredFinalizers; p;) { + object f = p; + p = finalizerNext(t, p); - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } } } @@ -197,14 +201,16 @@ turnOffTheLights(Thread* t) Heap* h = m->heap; Processor* p = m->processor; Classpath* c = m->classpath; - Finder* f = m->finder; + Finder* bf = m->bootFinder; + Finder* af = m->appFinder; m->dispose(); h->disposeFixies(); c->dispose(); p->dispose(); h->dispose(); - f->dispose(); + bf->dispose(); + af->dispose(); s->dispose(); } @@ -554,10 +560,10 @@ postCollect(Thread* t) t->heapOffset = 0; t->heapIndex = 0; - if (t->useBackupHeap) { + if (t->flags & Thread::UseBackupHeapFlag) { memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); - t->useBackupHeap = false; + t->flags &= ~Thread::UseBackupHeapFlag; t->backupHeapIndex = 0; } @@ -711,7 +717,8 @@ parseUtf8(Thread* t, Stream& s, unsigned length) void removeByteArray(Thread* t, object o) { - hashMapRemove(t, t->m->byteArrayMap, o, byteArrayHash, objectEqual); + hashMapRemove + (t, root(t, Machine::ByteArrayMap), o, byteArrayHash, objectEqual); } object @@ -720,11 +727,11 @@ internByteArray(Thread* t, object array) PROTECT(t, array); object n = hashMapFindNode - (t, t->m->byteArrayMap, array, byteArrayHash, byteArrayEqual); + (t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual); if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { - hashMapInsert(t, t->m->byteArrayMap, array, 0, byteArrayHash); + hashMapInsert(t, root(t, Machine::ByteArrayMap), array, 0, byteArrayHash); addFinalizer(t, array, removeByteArray); return array; } @@ -752,9 +759,7 @@ parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i) case CONSTANT_Utf8: { if (singletonObject(t, pool, i) == 0) { object value = parseUtf8(t, s, s.read2()); - if (objectClass(t, value) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, value) == type(t, Machine::ByteArrayType)) { value = internByteArray(t, value); } set(t, pool, SingletonBody + (i * BytesPerWord), value); @@ -1698,8 +1703,19 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, object elementClass) { // todo: arrays should implement Cloneable and Serializable - object vtable = classVirtualTable - (t, arrayBody(t, t->m->types, Machine::JobjectType)); + + if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { + PROTECT(t, spec); + PROTECT(t, elementClass); + + resolveSystemClass + (t, root(t, Machine::BootLoader), + className(t, type(t, Machine::JobjectType))); + + if (UNLIKELY(t->exception)) return 0; + } + + object vtable = classVirtualTable(t, type(t, Machine::JobjectType)); object c = t->m->processor->makeClass (t, @@ -1708,10 +1724,10 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, 2 * BytesPerWord, BytesPerWord, dimensions, - classObjectMask(t, arrayBody(t, t->m->types, Machine::ArrayType)), + classObjectMask(t, type(t, Machine::ArrayType)), spec, 0, - arrayBody(t, t->m->types, Machine::JobjectType), + type(t, Machine::JobjectType), 0, vtable, 0, @@ -1727,7 +1743,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, } object -makeArrayClass(Thread* t, object loader, object spec) +makeArrayClass(Thread* t, object loader, object spec, bool throw_) { PROTECT(t, loader); PROTECT(t, spec); @@ -1765,30 +1781,31 @@ makeArrayClass(Thread* t, object loader, object spec) } object elementClass = hashMapFind - (t, t->m->bootstrapClassMap, elementSpec, byteArrayHash, byteArrayEqual); + (t, root(t, Machine::BootstrapClassMap), elementSpec, byteArrayHash, + byteArrayEqual); if (elementClass == 0) { - elementClass = resolveClass(t, loader, elementSpec); - if (UNLIKELY(t->exception)) return 0; + elementClass = resolveClass(t, loader, elementSpec, throw_); + if (elementClass == 0) return 0; } return makeArrayClass(t, loader, dimensions, spec, elementClass); } object -resolveArrayClass(Thread* t, object loader, object spec) +resolveArrayClass(Thread* t, object loader, object spec, bool throw_) { object c = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual); + (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, + byteArrayEqual); if (c) { set(t, c, ClassVirtualTable, - classVirtualTable - (t, arrayBody(t, t->m->types, Machine::JobjectType))); + classVirtualTable(t, type(t, Machine::JobjectType))); return c; } else { - return makeArrayClass(t, loader, spec); + return makeArrayClass(t, loader, spec, throw_); } } @@ -1803,7 +1820,8 @@ removeMonitor(Thread* t, object o) hash = objectHash(t, o); } - object m = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapRemove + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); expect(t, m); @@ -1815,14 +1833,15 @@ removeMonitor(Thread* t, object o) void removeString(Thread* t, object o) { - hashMapRemove(t, t->m->stringMap, o, stringHash, objectEqual); + hashMapRemove(t, root(t, Machine::StringMap), o, stringHash, objectEqual); } void bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength) { - object super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0); + object super = (superType >= 0 + ? vm::type(t, static_cast(superType)) : 0); object mask; if (objectMask) { @@ -1831,7 +1850,8 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, and intArrayBody(t, classObjectMask(t, super), 0) == static_cast(objectMask)) { - mask = classObjectMask(t, arrayBody(t, t->m->types, superType)); + mask = classObjectMask + (t, vm::type(t, static_cast(superType))); } else { mask = makeIntArray(t, 1); intArrayBody(t, mask, 0) = objectMask; @@ -1840,14 +1860,15 @@ bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask, mask = 0; } - super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0); + super = (superType >= 0 + ? vm::type(t, static_cast(superType)) : 0); object class_ = t->m->processor->makeClass (t, 0, BootstrapFlag, fixedSize, arrayElementSize, arrayElementSize ? 1 : 0, mask, 0, 0, super, 0, 0, 0, 0, 0, 0, - t->m->loader, vtableLength); + root(t, Machine::BootLoader), vtableLength); - set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_); + setType(t, type, class_); } void @@ -1857,7 +1878,7 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, PROTECT(t, bootMethod); object n = makeByteArray(t, name); - object class_ = arrayBody(t, t->m->types, type); + object class_ = vm::type(t, type); set(t, class_, ClassName, n); @@ -1870,14 +1891,16 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, arrayBody(t, vtable, i) = bootMethod; } } else { - vtable = classVirtualTable(t, arrayBody(t, t->m->types, superType)); + vtable = classVirtualTable + (t, vm::type(t, static_cast(superType))); } set(t, class_, ClassVirtualTable, vtable); t->m->processor->initVtable(t, class_); - hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash); + hashMapInsert + (t, root(t, Machine::BootstrapClassMap), n, class_, byteArrayHash); } void @@ -1887,92 +1910,103 @@ boot(Thread* t) m->unsafe = true; - m->loader = allocate(t, FixedSizeOfSystemClassLoader, true); + m->roots = allocate(t, pad((Machine::RootCount + 2) * BytesPerWord), true); + arrayLength(t, m->roots) = Machine::RootCount; + + setRoot(t, Machine::BootLoader, + allocate(t, FixedSizeOfSystemClassLoader, true)); + + setRoot(t, Machine::AppLoader, + allocate(t, FixedSizeOfSystemClassLoader, true)); m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true); arrayLength(t, m->types) = TypeCount; #include "type-initializations.cpp" - object arrayClass = arrayBody(t, m->types, Machine::ArrayType); + object arrayClass = type(t, Machine::ArrayType); set(t, m->types, 0, arrayClass); + set(t, m->roots, 0, arrayClass); - object loaderClass = arrayBody - (t, m->types, Machine::SystemClassLoaderType); - set(t, m->loader, 0, loaderClass); + object loaderClass = type(t, Machine::SystemClassLoaderType); + set(t, root(t, Machine::BootLoader), 0, loaderClass); + set(t, root(t, Machine::AppLoader), 0, loaderClass); -#ifdef AVIAN_GNU - classLoaderInitialized(t, m->loader) = true; -#endif + object objectClass = type(t, Machine::JobjectType); - object objectClass = arrayBody(t, m->types, Machine::JobjectType); - - object classClass = arrayBody(t, m->types, Machine::ClassType); + object classClass = type(t, Machine::ClassType); set(t, classClass, 0, classClass); set(t, classClass, ClassSuper, objectClass); - object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType); + object intArrayClass = type(t, Machine::IntArrayType); set(t, intArrayClass, 0, classClass); set(t, intArrayClass, ClassSuper, objectClass); m->unsafe = false; - classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType)) + classVmFlags(t, type(t, Machine::SingletonType)) |= SingletonFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::ContinuationType)) + classVmFlags(t, type(t, Machine::ContinuationType)) |= ContinuationFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType)) + classVmFlags(t, type(t, Machine::JreferenceType)) |= ReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType)) + classVmFlags(t, type(t, Machine::WeakReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::SoftReferenceType)) + classVmFlags(t, type(t, Machine::SoftReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType)) + classVmFlags(t, type(t, Machine::PhantomReferenceType)) |= ReferenceFlag | WeakReferenceFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType)) + classVmFlags(t, type(t, Machine::JbooleanType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType)) + classVmFlags(t, type(t, Machine::JbyteType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JcharType)) + classVmFlags(t, type(t, Machine::JcharType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JshortType)) + classVmFlags(t, type(t, Machine::JshortType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JintType)) + classVmFlags(t, type(t, Machine::JintType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JlongType)) + classVmFlags(t, type(t, Machine::JlongType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType)) + classVmFlags(t, type(t, Machine::JfloatType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType)) + classVmFlags(t, type(t, Machine::JdoubleType)) |= PrimitiveFlag; - classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType)) + classVmFlags(t, type(t, Machine::JvoidType)) |= PrimitiveFlag; - set(t, arrayBody(t, m->types, Machine::BooleanArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JbooleanType)); - set(t, arrayBody(t, m->types, Machine::ByteArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JbyteType)); - set(t, arrayBody(t, m->types, Machine::CharArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JcharType)); - set(t, arrayBody(t, m->types, Machine::ShortArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JshortType)); - set(t, arrayBody(t, m->types, Machine::IntArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JintType)); - set(t, arrayBody(t, m->types, Machine::LongArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JlongType)); - set(t, arrayBody(t, m->types, Machine::FloatArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JfloatType)); - set(t, arrayBody(t, m->types, Machine::DoubleArrayType), ClassStaticTable, - arrayBody(t, m->types, Machine::JdoubleType)); + set(t, type(t, Machine::BooleanArrayType), ClassStaticTable, + type(t, Machine::JbooleanType)); + set(t, type(t, Machine::ByteArrayType), ClassStaticTable, + type(t, Machine::JbyteType)); + set(t, type(t, Machine::CharArrayType), ClassStaticTable, + type(t, Machine::JcharType)); + set(t, type(t, Machine::ShortArrayType), ClassStaticTable, + type(t, Machine::JshortType)); + set(t, type(t, Machine::IntArrayType), ClassStaticTable, + type(t, Machine::JintType)); + set(t, type(t, Machine::LongArrayType), ClassStaticTable, + type(t, Machine::JlongType)); + set(t, type(t, Machine::FloatArrayType), ClassStaticTable, + type(t, Machine::JfloatType)); + set(t, type(t, Machine::DoubleArrayType), ClassStaticTable, + type(t, Machine::JdoubleType)); - m->classMap = makeHashMap(t, 0, 0); + setRoot(t, Machine::ClassMap, makeHashMap(t, 0, 0)); - m->bootstrapClassMap = makeHashMap(t, 0, 0); + { object map = makeHashMap(t, 0, 0); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); + } - m->stringMap = makeWeakHashMap(t, 0, 0); + set(t, root(t, Machine::AppLoader), ClassLoaderParent, + root(t, Machine::BootLoader)); + + setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); + + setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); m->processor->boot(t, 0); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1); @@ -2074,15 +2108,16 @@ class HeapClient: public Heap::Client { namespace vm { -Machine::Machine(System* system, Heap* heap, Finder* finder, - Processor* processor, Classpath* classpath, +Machine::Machine(System* system, Heap* heap, Finder* bootFinder, + Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount): vtable(&javaVMVTable), system(system), heapClient(new (heap->allocate(sizeof(HeapClient))) HeapClient(this)), heap(heap), - finder(finder), + bootFinder(bootFinder), + appFinder(appFinder), processor(processor), classpath(classpath), rootThread(0), @@ -2102,24 +2137,13 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, referenceLock(0), shutdownLock(0), libraries(0), - loader(0), - classMap(0), - loadClassMethod(0), - bootstrapClassMap(0), - monitorMap(0), - stringMap(0), - byteArrayMap(0), types(0), - jniMethodTable(0), + roots(0), finalizers(0), tenuredFinalizers(0), finalizeQueue(0), weakReferences(0), tenuredWeakReferences(0), - shutdownHooks(0), - objectsToFinalize(0), - nullPointerException(0), - arrayIndexOutOfBoundsException(0), unsafe(false), triedBuiltinOnLoad(false), heapPoolIndex(0) @@ -2194,13 +2218,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): (m->heap->allocate(ThreadHeapSizeInBytes))), heap(defaultHeap), backupHeapIndex(0), - useBackupHeap(false), - waiting(false), - tracing(false), - daemon(false) -#ifdef VM_STRESS - , stress(false) -#endif // VM_STRESS + flags(ActiveFlag) { } void @@ -2241,16 +2259,10 @@ Thread::init() boot(this); } - m->byteArrayMap = makeWeakHashMap(this, 0, 0); - m->monitorMap = makeWeakHashMap(this, 0, 0); + setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0)); + setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0)); - m->jniMethodTable = makeVector(this, 0, 0); - - m->nullPointerException = m->classpath->makeThrowable - (this, Machine::NullPointerExceptionType); - - m->arrayIndexOutOfBoundsException = m->classpath->makeThrowable - (this, Machine::IndexOutOfBoundsExceptionType); + setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); m->localThread->set(this); } else { @@ -2265,6 +2277,21 @@ Thread::init() } threadPeer(this, javaThread) = reinterpret_cast(this); + + if (parent == 0) { + enter(this, Thread::ActiveState); + + m->classpath->boot(this); + + setRoot(this, Machine::NullPointerException, m->classpath->makeThrowable + (this, Machine::NullPointerExceptionType)); + + setRoot(this, Machine::ArrayIndexOutOfBoundsException, + m->classpath->makeThrowable + (this, Machine::IndexOutOfBoundsExceptionType)); + + enter(this, Thread::IdleState); + } } void @@ -2303,10 +2330,10 @@ shutDown(Thread* t) { ACQUIRE(t, t->m->shutdownLock); - object hooks = t->m->shutdownHooks; + object hooks = root(t, Machine::ShutdownHooks); PROTECT(t, hooks); - t->m->shutdownHooks = 0; + setRoot(t, Machine::ShutdownHooks, 0); object h = hooks; PROTECT(t, h); @@ -2364,7 +2391,6 @@ enter(Thread* t, Thread::State s) return; } - #ifdef USE_ATOMIC_OPERATIONS # define INCREMENT atomicIncrement # define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock) @@ -2411,12 +2437,24 @@ enter(Thread* t, Thread::State s) // The java.lang.Thread implementation may or may not notify the // VM when the daemon field in the Java object changes, so we sync // up the native field whenever the thread transitions to idle: - if (t->daemon != threadDaemon(t, t->javaThread)) { + + // todo: this won't always help if some other thread sets the + // daemon field. The thread trying to shut down the VM really + // just needs to count from scratch every time any thread makes a + // transition. + + if (UNLIKELY(((t->flags & Thread::DaemonFlag) != 0) + != threadDaemon(t, t->javaThread))) + { ACQUIRE_LOCK; - t->daemon = threadDaemon(t, t->javaThread); + if (threadDaemon(t, t->javaThread)) { + atomicOr(&(t->flags), Thread::DaemonFlag); + } else { + atomicAnd(&(t->flags), ~Thread::DaemonFlag); + } - if (t->daemon) { + if (t->flags & Thread::DaemonFlag) { ++ t->m->daemonCount; } else { expect(t, t->m->daemonCount); @@ -2426,7 +2464,7 @@ enter(Thread* t, Thread::State s) t->m->stateLock->notifyAll(t->systemThread); } - if (t->state == Thread::ActiveState) { + if (LIKELY(t->state == Thread::ActiveState)) { // fast path assert(t, t->m->activeCount > 0); INCREMENT(&(t->m->activeCount), -1); @@ -2475,7 +2513,7 @@ enter(Thread* t, Thread::State s) } break; case Thread::ActiveState: - if (t->state == Thread::IdleState and t->m->exclusive == 0) { + if (LIKELY(t->state == Thread::IdleState and t->m->exclusive == 0)) { // fast path INCREMENT(&(t->m->activeCount), 1); @@ -2563,7 +2601,7 @@ object allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, unsigned sizeInBytes, bool objectMask) { - if (UNLIKELY(t->useBackupHeap)) { + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord) <= ThreadBackupHeapSizeInWords); @@ -2571,7 +2609,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord); cast(o, 0) = 0; return o; - } else if (UNLIKELY(t->tracing)) { + } else if (UNLIKELY(t->flags & Thread::TracingFlag)) { expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord) <= ThreadHeapSizeInWords); return allocateSmall(t, sizeInBytes); @@ -2721,9 +2759,7 @@ stringUTFLength(Thread* t, object string, unsigned start, unsigned length) if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { result = length; } else { for (unsigned i = 0; i < length; ++i) { @@ -2746,9 +2782,7 @@ stringChars(Thread* t, object string, unsigned start, unsigned length, { if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, &byteArrayBody(t, data, stringOffset(t, string) + start), length); @@ -2767,9 +2801,7 @@ stringChars(Thread* t, object string, unsigned start, unsigned length, { if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { for (unsigned i = 0; i < length; ++i) { chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i); } @@ -2791,9 +2823,7 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length, if (length) { object data = stringData(t, string); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { memcpy(chars, &byteArrayBody(t, data, stringOffset(t, string) + start), length); @@ -2824,11 +2854,14 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length, bool isAssignableFrom(Thread* t, object a, object b) { + assert(t, a); + assert(t, b); + if (a == b) return true; if (classFlags(t, a) & ACC_INTERFACE) { if (classVmFlags(t, b) & BootstrapFlag) { - resolveSystemClass(t, className(t, b)); + resolveSystemClass(t, root(t, Machine::BootLoader), className(t, b)); if (UNLIKELY(t->exception)) { t->exception = 0; return false; @@ -2966,15 +2999,6 @@ primitiveSize(Thread* t, unsigned code) } } -object -findLoadedSystemClass(Thread* t, object spec) -{ - PROTECT(t, spec); - ACQUIRE(t, t->m->classLock); - - return hashMapFind(t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); -} - object parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) { @@ -3084,18 +3108,27 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) } object -resolveSystemClass(Thread* t, object spec) +resolveSystemClass(Thread* t, object loader, object spec, bool throw_) { + PROTECT(t, loader); PROTECT(t, spec); ACQUIRE(t, t->m->classLock); object class_ = hashMapFind - (t, t->m->classMap, spec, byteArrayHash, byteArrayEqual); + (t, getClassLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { + if (classLoaderParent(t, loader)) { + class_ = resolveSystemClass + (t, classLoaderParent(t, loader), spec, false); + if (class_) { + return class_; + } + } + if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, t->m->loader, spec); + class_ = resolveArrayClass(t, loader, spec, throw_); } else { RUNTIME_ARRAY(char, file, byteArrayLength(t, spec) + 6); memcpy(RUNTIME_ARRAY_BODY(file), @@ -3105,7 +3138,8 @@ resolveSystemClass(Thread* t, object spec) ".class", 7); - System::Region* region = t->m->finder->find(RUNTIME_ARRAY_BODY(file)); + System::Region* region = getFinder(t, loader)->find + (RUNTIME_ARRAY_BODY(file)); if (region) { if (Verbose) { @@ -3113,8 +3147,7 @@ resolveSystemClass(Thread* t, object spec) } // parse class file - class_ = parseClass - (t, t->m->loader, region->start(), region->length()); + class_ = parseClass(t, loader, region->start(), region->length()); region->dispose(); if (LIKELY(t->exception == 0)) { @@ -3125,7 +3158,7 @@ resolveSystemClass(Thread* t, object spec) } object bootstrapClass = hashMapFind - (t, t->m->bootstrapClassMap, spec, byteArrayHash, + (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, byteArrayEqual); if (bootstrapClass) { @@ -3141,8 +3174,9 @@ resolveSystemClass(Thread* t, object spec) if (class_) { PROTECT(t, class_); - hashMapInsert(t, t->m->classMap, spec, class_, byteArrayHash); - } else if (t->exception == 0) { + hashMapInsert + (t, getClassLoaderMap(t, loader), spec, class_, byteArrayHash); + } else if (throw_ and t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); t->exception = t->m->classpath->makeThrowable (t, Machine::ClassNotFoundExceptionType, message); @@ -3153,10 +3187,26 @@ resolveSystemClass(Thread* t, object spec) } object -resolveClass(Thread* t, object loader, object spec) +findLoadedClass(Thread* t, object loader, object spec) { - if (loader == t->m->loader) { - return resolveSystemClass(t, spec); + PROTECT(t, spec); + ACQUIRE(t, t->m->classLock); + + object map = getClassLoaderMap(t, loader); + if (map) { + return hashMapFind(t, map, spec, byteArrayHash, byteArrayEqual); + } else { + return 0; + } +} + +object +resolveClass(Thread* t, object loader, object spec, bool throw_) +{ + if (loader == root(t, Machine::BootLoader) + or loader == root(t, Machine::AppLoader)) + { + return resolveSystemClass(t, loader, spec, throw_); } else { PROTECT(t, loader); PROTECT(t, spec); @@ -3173,39 +3223,44 @@ resolveClass(Thread* t, object loader, object spec) if (class_ == 0) { if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec); + class_ = resolveArrayClass(t, loader, spec, throw_); } else { - if (t->m->loadClassMethod == 0) { + if (root(t, Machine::LoadClassMethod) == 0) { object m = resolveMethod - (t, t->m->loader, "java/lang/ClassLoader", "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", + "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); if (m) { - t->m->loadClassMethod = m; + setRoot(t, Machine::LoadClassMethod, m); - object classLoaderClass = arrayBody - (t, t->m->types, Machine::ClassLoaderType); + object classLoaderClass = type(t, Machine::ClassLoaderType); if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { - resolveSystemClass(t, vm::className(t, classLoaderClass)); + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, classLoaderClass)); } } } if (LIKELY(t->exception == 0)) { object method = findVirtualMethod - (t, t->m->loadClassMethod, objectClass(t, loader)); + (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); if (LIKELY(t->exception == 0)) { PROTECT(t, method); - object specString = makeString - (t, "%s", &byteArrayBody(t, spec, 0)); + RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast + (&byteArrayBody(t, spec, 0))); - replace('/', '.', reinterpret_cast - (&byteArrayBody(t, stringData(t, specString), 0))); + object specString = makeString(t, "%s", s); class_ = t->m->processor->invoke(t, method, loader, specString); + + if (LIKELY(class_ and t->exception == 0)) { + class_ = jclassVmClass(t, class_); + } } } } @@ -3216,7 +3271,7 @@ resolveClass(Thread* t, object loader, object spec) hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); - } else if (t->exception == 0) { + } else if (throw_ and t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); t->exception = t->m->classpath->makeThrowable (t, Machine::ClassNotFoundExceptionType, message); @@ -3399,10 +3454,10 @@ initClass(Thread* t, object c) } object -makeObjectArray(Thread* t, object loader, object elementClass, unsigned count) +makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass - (t, loader, className(t, elementClass)); + (t, classLoader(t, elementClass), className(t, elementClass)); PROTECT(t, arrayClass); object array = makeArray(t, count); @@ -3524,7 +3579,8 @@ objectMonitor(Thread* t, object o, bool createNew) { assert(t, t->state == Thread::ActiveState); - object m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + object m = hashMapFind + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); if (m) { if (DebugMonitors) { @@ -3538,7 +3594,9 @@ objectMonitor(Thread* t, object o, bool createNew) { ENTER(t, Thread::ExclusiveState); - m = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual); + m = hashMapFind + (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); + if (m) { if (DebugMonitors) { fprintf(stderr, "found monitor %p for object %x\n", @@ -3556,7 +3614,7 @@ objectMonitor(Thread* t, object o, bool createNew) objectHash(t, o)); } - hashMapInsert(t, t->m->monitorMap, o, m, objectHash); + hashMapInsert(t, root(t, Machine::MonitorMap), o, m, objectHash); addFinalizer(t, o, removeMonitor); } @@ -3574,11 +3632,13 @@ intern(Thread* t, object s) ACQUIRE(t, t->m->referenceLock); - object n = hashMapFindNode(t, t->m->stringMap, s, stringHash, stringEqual); + object n = hashMapFindNode + (t, root(t, Machine::StringMap), s, stringHash, stringEqual); + if (n) { return jreferenceTarget(t, tripleFirst(t, n)); } else { - hashMapInsert(t, t->m->stringMap, s, 0, stringHash); + hashMapInsert(t, root(t, Machine::StringMap), s, 0, stringHash); addFinalizer(t, s, removeString); return s; } @@ -3615,20 +3675,20 @@ collect(Thread* t, Heap::CollectionType type) if (not stress) t->stress = false; #endif - object f = m->finalizeQueue; - m->finalizeQueue = 0; + object f = t->m->finalizeQueue; + t->m->finalizeQueue = 0; for (; f; f = finalizerNext(t, f)) { void (*function)(Thread*, object); memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); if (function) { function(t, finalizerTarget(t, f)); } else { - m->objectsToFinalize = makePair - (t, finalizerTarget(t, f), m->objectsToFinalize); + setRoot(t, Machine::ObjectsToFinalize, makePair + (t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize))); } } - if (m->objectsToFinalize and m->finalizeThread == 0) { + if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { m->finalizeThread = m->processor->makeThread (m, t->m->classpath->makeThread(t, m->rootThread), m->rootThread); @@ -3702,19 +3762,8 @@ walkNext(Thread* t, object o, int previous) void visitRoots(Machine* m, Heap::Visitor* v) { - v->visit(&(m->loader)); - v->visit(&(m->classMap)); - v->visit(&(m->loadClassMethod)); - v->visit(&(m->bootstrapClassMap)); - v->visit(&(m->monitorMap)); - v->visit(&(m->stringMap)); - v->visit(&(m->byteArrayMap)); v->visit(&(m->types)); - v->visit(&(m->jniMethodTable)); - v->visit(&(m->shutdownHooks)); - v->visit(&(m->objectsToFinalize)); - v->visit(&(m->nullPointerException)); - v->visit(&(m->arrayIndexOutOfBoundsException)); + v->visit(&(m->roots)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); @@ -3751,8 +3800,8 @@ printTrace(Thread* t, object exception) } object trace = throwableTrace(t, e); - for (unsigned i = 0; i < arrayLength(t, trace); ++i) { - object e = arrayBody(t, trace, i); + for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) { + object e = objectArrayBody(t, trace, i); const int8_t* class_ = &byteArrayBody (t, className(t, methodClass(t, traceElementMethod(t, e))), 0); const int8_t* method = &byteArrayBody @@ -3789,11 +3838,11 @@ makeTrace(Thread* t, Processor::StackWalker* walker) virtual bool visit(Processor::StackWalker* walker) { if (trace == 0) { - trace = makeArray(t, walker->count()); + trace = makeObjectArray(t, walker->count()); } object e = makeTraceElement(t, walker->method(), walker->ip()); - vm_assert(t, index < arrayLength(t, trace)); + vm_assert(t, index < objectArrayLength(t, trace)); set(t, trace, ArrayBody + (index * BytesPerWord), e); ++ index; return true; @@ -3807,7 +3856,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker) walker->walk(&v); - return v.trace ? v.trace : makeArray(t, 0); + return v.trace ? v.trace : makeObjectArray(t, 0); } object @@ -3828,7 +3877,7 @@ makeTrace(Thread* t, Thread* target) t->m->processor->walkStack(target, &v); - return v.trace ? v.trace : makeArray(t, 0); + return v.trace ? v.trace : makeObjectArray(t, 0); } void @@ -3842,7 +3891,9 @@ runFinalizeThread(Thread* t) while (true) { { ACQUIRE(t, t->m->stateLock); - while (t->m->finalizeThread and t->m->objectsToFinalize == 0) { + while (t->m->finalizeThread + and root(t, Machine::ObjectsToFinalize) == 0) + { ENTER(t, Thread::IdleState); t->m->stateLock->wait(t->systemThread, 0); } @@ -3850,8 +3901,8 @@ runFinalizeThread(Thread* t) if (t->m->finalizeThread == 0) { return; } else { - list = t->m->objectsToFinalize; - t->m->objectsToFinalize = 0; + list = root(t, Machine::ObjectsToFinalize); + setRoot(t, Machine::ObjectsToFinalize, 0); } } @@ -3926,7 +3977,7 @@ vmPrintTrace(Thread* t) int line = t->m->processor->lineNumber (t, walker->method(), walker->ip()); - fprintf(stderr, " at %s.%s (%x) ", class_, method, walker->ip()); + fprintf(stderr, " at %s.%s ", class_, method); switch (line) { case NativeLine: diff --git a/src/machine.h b/src/machine.h index cc2394a757..ec2677109e 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1120,6 +1120,24 @@ struct JNIEnvVTable { #endif }; +inline void +atomicOr(uint32_t* p, int v) +{ + for (uint32_t old = *p; + not atomicCompareAndSwap32(p, old, old | v); + old = *p) + { } +} + +inline void +atomicAnd(uint32_t* p, int v) +{ + for (uint32_t old = *p; + not atomicCompareAndSwap32(p, old, old & v); + old = *p) + { } +} + inline int strcmp(const int8_t* a, const int8_t* b) { @@ -1164,8 +1182,26 @@ class Machine { ImmortalAllocation }; - Machine(System* system, Heap* heap, Finder* finder, Processor* processor, - Classpath* classpath, const char** properties, + enum Root { + BootLoader, + AppLoader, + ClassMap, + LoadClassMethod, + BootstrapClassMap, + MonitorMap, + StringMap, + ByteArrayMap, + JNIMethodTable, + ShutdownHooks, + ObjectsToFinalize, + NullPointerException, + ArrayIndexOutOfBoundsException + }; + + static const unsigned RootCount = ArrayIndexOutOfBoundsException + 1; + + Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, + Processor* processor, Classpath* classpath, const char** properties, unsigned propertyCount); ~Machine() { @@ -1178,7 +1214,8 @@ class Machine { System* system; Heap::Client* heapClient; Heap* heap; - Finder* finder; + Finder* bootFinder; + Finder* appFinder; Processor* processor; Classpath* classpath; Thread* rootThread; @@ -1198,24 +1235,13 @@ class Machine { System::Monitor* referenceLock; System::Monitor* shutdownLock; System::Library* libraries; - object loader; - object classMap; - object loadClassMethod; - object bootstrapClassMap; - object monitorMap; - object stringMap; - object byteArrayMap; object types; - object jniMethodTable; + object roots; object finalizers; object tenuredFinalizers; object finalizeQueue; object weakReferences; object tenuredWeakReferences; - object shutdownHooks; - object objectsToFinalize; - object nullPointerException; - object arrayIndexOutOfBoundsException; bool unsafe; bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; @@ -1261,6 +1287,13 @@ class Thread { ExitState }; + static const unsigned UseBackupHeapFlag = 1 << 0; + static const unsigned WaitingFlag = 1 << 1; + static const unsigned TracingFlag = 1 << 2; + static const unsigned DaemonFlag = 1 << 3; + static const unsigned StressFlag = 1 << 4; + static const unsigned ActiveFlag = 1 << 5; + class Protector { public: Protector(Thread* t): t(t), next(t->protector) { @@ -1371,11 +1404,7 @@ class Thread { uintptr_t* heap; uintptr_t backupHeap[ThreadBackupHeapSizeInWords]; unsigned backupHeapIndex; - bool useBackupHeap; - bool waiting; - bool tracing; - bool daemon; - bool stress; + unsigned flags; }; class Classpath { @@ -1600,9 +1629,9 @@ ensure(Thread* t, unsigned sizeInBytes) > ThreadHeapSizeInWords) { if (sizeInBytes <= ThreadBackupHeapSizeInBytes) { - expect(t, not t->useBackupHeap); + expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0); - t->useBackupHeap = true; + atomicOr(&(t->flags), Thread::UseBackupHeapFlag); return true; } else { @@ -1719,16 +1748,52 @@ instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" +inline object& +root(Thread* t, Machine::Root root) +{ + return arrayBody(t, t->m->roots, root); +} + +inline void +setRoot(Thread* t, Machine::Root root, object value) +{ + set(t, t->m->roots, ArrayBody + (root * BytesPerWord), value); +} + +inline object +type(Thread* t, Machine::Type type) +{ + return arrayBody(t, t->m->types, type); +} + +inline void +setType(Thread* t, Machine::Type type, object value) +{ + set(t, t->m->types, ArrayBody + (type * BytesPerWord), value); +} + inline object getClassLoaderMap(Thread* t, object loader) { - if (loader == t->m->loader) { - return t->m->classMap; + if (loader == root(t, Machine::BootLoader)) { + return root(t, Machine::ClassMap); } else { return classLoaderMap(t, loader); } } +inline Finder* +getFinder(Thread* t, object loader) +{ + if (loader == root(t, Machine::BootLoader)) { + return t->m->bootFinder; + } else if (loader == root(t, Machine::AppLoader)) { + return t->m->appFinder; + } else { + abort(t); + } +} + inline bool objectFixed(Thread*, object o) { @@ -1927,9 +1992,7 @@ stringHash(Thread* t, object s) { if (stringHashCode(t, s) == 0 and stringLength(t, s)) { object data = stringData(t, s); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { stringHashCode(t, s) = hash (&byteArrayBody(t, data, stringOffset(t, s)), stringLength(t, s)); } else { @@ -1944,9 +2007,7 @@ inline uint16_t stringCharAt(Thread* t, object s, int i) { object data = stringData(t, s); - if (objectClass(t, data) - == arrayBody(t, t->m->types, Machine::ByteArrayType)) - { + if (objectClass(t, data) == type(t, Machine::ByteArrayType)) { return byteArrayBody(t, data, stringOffset(t, s) + i); } else { return charArrayBody(t, data, stringOffset(t, s) + i); @@ -2063,7 +2124,7 @@ fieldSize(Thread* t, object field) } object -findLoadedSystemClass(Thread* t, object spec); +findLoadedClass(Thread* t, object loader, object spec); inline bool emptyMethod(Thread* t, object method) @@ -2080,7 +2141,7 @@ object parseClass(Thread* t, object loader, const uint8_t* data, unsigned length); object -resolveClass(Thread* t, object loader, object name); +resolveClass(Thread* t, object loader, object name, bool throw_ = true); inline object resolveClass(Thread* t, object loader, const char* name) @@ -2091,12 +2152,12 @@ resolveClass(Thread* t, object loader, const char* name) } object -resolveSystemClass(Thread* t, object name); +resolveSystemClass(Thread* t, object loader, object name, bool throw_ = true); inline object -resolveSystemClass(Thread* t, const char* name) +resolveSystemClass(Thread* t, object loader, const char* name) { - return resolveSystemClass(t, makeByteArray(t, "%s", name)); + return resolveSystemClass(t, loader, makeByteArray(t, "%s", name)); } void @@ -2150,13 +2211,12 @@ void initClass(Thread* t, object c); object -makeObjectArray(Thread* t, object loader, object elementClass, unsigned count); +makeObjectArray(Thread* t, object elementClass, unsigned count); inline object makeObjectArray(Thread* t, unsigned count) { - return makeObjectArray - (t, t->m->loader, arrayBody(t, t->m->types, Machine::JobjectType), count); + return makeObjectArray(t, type(t, Machine::JobjectType), count); } object @@ -2398,10 +2458,10 @@ monitorAppendWait(Thread* t, object monitor) { assert(t, monitorOwner(t, monitor) == t); - expect(t, not t->waiting); + expect(t, (t->flags & Thread::WaitingFlag) == 0); expect(t, t->waitNext == 0); - t->waiting = true; + atomicOr(&(t->flags), Thread::WaitingFlag); if (monitorWaitTail(t, monitor)) { static_cast(monitorWaitTail(t, monitor))->waitNext = t; @@ -2434,7 +2494,7 @@ monitorRemoveWait(Thread* t, object monitor) } t->waitNext = 0; - t->waiting = false; + atomicAnd(&(t->flags), ~Thread::WaitingFlag); return; } else { @@ -2489,7 +2549,7 @@ monitorWait(Thread* t, object monitor, int64_t time) monitorDepth(t, monitor) = depth; - if (t->waiting) { + if (t->flags & Thread::WaitingFlag) { monitorRemoveWait(t, monitor); } else { expect(t, not monitorFindWait(t, monitor)); @@ -2509,7 +2569,7 @@ monitorPollWait(Thread* t, object monitor) if (next) { monitorWaitHead(t, monitor) = next->waitNext; - next->waiting = false; + atomicAnd(&(next->flags), ~Thread::WaitingFlag); next->waitNext = 0; if (next == monitorWaitTail(t, monitor)) { monitorWaitTail(t, monitor) = 0; @@ -2677,7 +2737,13 @@ setDaemon(Thread* t, object thread, bool daemon) if ((threadDaemon(t, thread) != 0) != daemon) { threadDaemon(t, thread) = daemon; - t->daemon = daemon; + + Thread* p = reinterpret_cast(threadPeer(t, thread)); + if (daemon) { + atomicOr(&(p->flags), Thread::DaemonFlag); + } else { + atomicAnd(&(p->flags), ~Thread::DaemonFlag); + } if (daemon) { ++ t->m->daemonCount; @@ -2832,7 +2898,7 @@ resolveClassInObject(Thread* t, object loader, object container, unsigned classOffset) { object o = cast(container, classOffset); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ByteArrayType)) { + if (objectClass(t, o) == type(t, Machine::ByteArrayType)) { PROTECT(t, container); o = resolveClass(t, loader, o); @@ -2847,7 +2913,7 @@ inline object resolveClassInPool(Thread* t, object loader, object method, unsigned index) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) { + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); o = resolveClass(t, loader, referenceName(t, o)); @@ -2872,7 +2938,7 @@ resolve(Thread* t, object loader, object method, unsigned index, Machine::Type errorType) { object o = singletonObject(t, codePool(t, methodCode(t, method)), index); - if (objectClass(t, o) == arrayBody(t, t->m->types, Machine::ReferenceType)) + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { PROTECT(t, method); @@ -2953,21 +3019,49 @@ inline object primitiveClass(Thread* t, char name) { switch (name) { - case 'B': return arrayBody(t, t->m->types, Machine::JbyteType); - case 'C': return arrayBody(t, t->m->types, Machine::JcharType); - case 'D': return arrayBody(t, t->m->types, Machine::JdoubleType); - case 'F': return arrayBody(t, t->m->types, Machine::JfloatType); - case 'I': return arrayBody(t, t->m->types, Machine::JintType); - case 'J': return arrayBody(t, t->m->types, Machine::JlongType); - case 'S': return arrayBody(t, t->m->types, Machine::JshortType); - case 'V': return arrayBody(t, t->m->types, Machine::JvoidType); - case 'Z': return arrayBody(t, t->m->types, Machine::JbooleanType); + case 'B': return type(t, Machine::JbyteType); + case 'C': return type(t, Machine::JcharType); + case 'D': return type(t, Machine::JdoubleType); + case 'F': return type(t, Machine::JfloatType); + case 'I': return type(t, Machine::JintType); + case 'J': return type(t, Machine::JlongType); + case 'S': return type(t, Machine::JshortType); + case 'V': return type(t, Machine::JvoidType); + case 'Z': return type(t, Machine::JbooleanType); default: t->exception = t->m->classpath->makeThrowable (t, Machine::IllegalArgumentExceptionType); return 0; } } + +inline void +registerNative(Thread* t, object method, void* function) +{ + PROTECT(t, method); + + expect(t, methodFlags(t, method) & ACC_NATIVE); + + object native = makeNative(t, function, false); + + // ensure other threads only see the methodCode field populated + // once the object it points to has been populated: + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, native); +} + +inline void +unregisterNatives(Thread* t, object c) { + if (classMethodTable(t, c)) { + for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { + object method = arrayBody(t, classMethodTable(t, c), i); + if (methodFlags(t, method) & ACC_NATIVE) { + set(t, method, MethodCode, 0); + } + } + } +} object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); diff --git a/src/process.h b/src/process.h index ae1f2831fa..0b4ead129e 100644 --- a/src/process.h +++ b/src/process.h @@ -77,7 +77,8 @@ populateMultiArray(Thread* t, object array, int32_t* counts, &byteArrayBody(t, spec, 1), byteArrayLength(t, spec) - 1); - object class_ = resolveSystemClass(t, elementSpec); + object class_ = resolveClass + (t, classLoader(t, objectClass(t, array)), elementSpec); PROTECT(t, class_); for (int32_t i = 0; i < counts[index]; ++i) { diff --git a/src/processor.h b/src/processor.h index 8cff2b0782..ee3983f01c 100644 --- a/src/processor.h +++ b/src/processor.h @@ -128,7 +128,7 @@ class Processor { DelayedPromise** addresses, object method) = 0; virtual void - visitRoots(HeapWalker* w) = 0; + visitRoots(Thread* t, HeapWalker* w) = 0; virtual unsigned* makeCallTable(Thread* t, HeapWalker* w) = 0; @@ -153,10 +153,6 @@ class Processor { walkContinuationBody(Thread* t, Heap::Walker* w, object o, unsigned start) = 0; - virtual void registerNative(Thread* t, object method, void* function) = 0; - - virtual void unregisterNatives(Thread* t, object c) = 0; - object invoke(Thread* t, object method, object this_, ...) { diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 0e8a6bc758..bec29c7e69 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -1137,7 +1137,7 @@ parseMember(Object* t, Object* p, Object* declarations) bool isNew; Object* member = parseMember(t, cdr(cdr(p)), declarations, &isNew); memberName(member) = string(car(cdr(p))); - return isNew ? member : 0; + return 0; } else { return Scalar::make(t, declaration(spec, declarations), spec, string(car(cdr(p))), diff --git a/src/types.def b/src/types.def index bdf13bf0fb..0ddeb92a3c 100644 --- a/src/types.def +++ b/src/types.def @@ -37,11 +37,6 @@ (type fieldAddendum avian/FieldAddendum) -(type nativeMethodData - (void* function) - (uint16_t argumentTableSize) - (array uint8_t parameterTypes)) - (type pointer (void* value)) diff --git a/src/util.cpp b/src/util.cpp index a15b57d77b..0745f98f72 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -318,8 +318,7 @@ hashMapFindNode(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); if (array) { @@ -367,9 +366,7 @@ hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), } if (oldArray) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); - + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) { object next; for (object p = arrayBody(t, oldArray, i); p; p = next) { @@ -407,8 +404,7 @@ hashMapInsert(Thread* t, object map, object key, object value, uint32_t h = hash(t, key); - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); @@ -432,7 +428,8 @@ hashMapInsert(Thread* t, object map, object key, object value, object r = makeWeakReference(t, 0, 0, 0, 0); jreferenceTarget(t, r) = key; jreferenceVmNext(t, r) = t->m->weakReferences; - k = t->m->weakReferences = r; + t->m->weakReferences = r; + k = r; array = hashMapArray(t, map); } @@ -465,8 +462,7 @@ hashMapRemove(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { - bool weak = objectClass(t, map) - == arrayBody(t, t->m->types, Machine::WeakHashMapType); + bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); object o = 0; From f485016637570518f1d91f39ad5537227f3df291 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 14 Sep 2010 18:52:57 -0600 Subject: [PATCH 040/274] implement more JVM_* methods and avoid duplicate array class loading --- classpath/avian/OpenJDK.java | 23 ++++++ makefile | 5 ++ src/classpath-openjdk.cpp | 138 +++++++++++++++++++++++++++++++---- src/machine.cpp | 27 ++++--- 4 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 classpath/avian/OpenJDK.java diff --git a/classpath/avian/OpenJDK.java b/classpath/avian/OpenJDK.java new file mode 100644 index 0000000000..877a7c2289 --- /dev/null +++ b/classpath/avian/OpenJDK.java @@ -0,0 +1,23 @@ +/* Copyright (c) 2010, 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 avian; + +import java.security.AllPermission; +import java.security.Permissions; +import java.security.ProtectionDomain; + +public class OpenJDK { + public static ProtectionDomain getProtectionDomain() { + Permissions p = new Permissions(); + p.add(new AllPermission()); + return new ProtectionDomain(null, p); + } +} diff --git a/makefile b/makefile index e1af555cb4..35b66a591f 100644 --- a/makefile +++ b/makefile @@ -444,6 +444,11 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMMethod.java \ $(classpath-src)/avian/resource/Handler.java + + ifdef openjdk + classpath-sources := $(classpath-sources) \ + $(classpath-src)/avian/OpenJDK.java + endif else classpath-sources := $(shell find $(classpath-src) -name '*.java') endif diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 6871a3a9e6..61d54d6eed 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -251,6 +251,22 @@ class MyClasspath : public Classpath { t->m->processor->invoke (t, constructor, root(t, Machine::AppLoader), root(t, Machine::BootLoader)); + if (UNLIKELY(t->exception)) return; + + object scl = resolveField + (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); + if (UNLIKELY(t->exception)) return; + PROTECT(t, scl); + + object sclSet = resolveField + (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); + if (UNLIKELY(t->exception)) return; + + set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, scl), root(t, Machine::AppLoader)); + + cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), + fieldOffset(t, sclSet)) = true; } virtual void @@ -593,6 +609,38 @@ Avian_sun_misc_Unsafe_staticFieldOffset (t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield))); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_arrayBaseOffset +(Thread*, object, uintptr_t*) +{ + return BytesPerWord * 2; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_arrayIndexScale +(Thread* t, object, uintptr_t* arguments) +{ + object c = jclassVmClass(t, reinterpret_cast(arguments[1])); + + if (classVmFlags(t, c) & PrimitiveFlag) { + const char* name = reinterpret_cast + (&byteArrayBody(t, local::getClassName(t, c), 0)); + + switch (*name) { + case 'b': return 1; + case 's': + case 'c': return 2; + case 'l': + case 'd': return 8; + case 'i': + case 'f': return 4; + default: abort(t); + } + } else { + return BytesPerWord; + } +} + extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_staticFieldBase (Thread* t, object, uintptr_t* arguments) @@ -645,6 +693,18 @@ Avian_sun_misc_Unsafe_getInt__Ljava_lang_Object_2J return cast(o, offset); } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getIntVolatile +(Thread*, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + int32_t result = cast(o, offset); + loadMemoryBarrier(); + return result; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) @@ -1026,13 +1086,22 @@ extern "C" JNIEXPORT void JNICALL JVM_TraceMethodCalls(jboolean) { abort(); } extern "C" JNIEXPORT jlong JNICALL -JVM_TotalMemory(void) { abort(); } +JVM_TotalMemory() +{ + return 0; +} extern "C" JNIEXPORT jlong JNICALL -JVM_FreeMemory(void) { abort(); } +JVM_FreeMemory() +{ + return 0; +} extern "C" JNIEXPORT jlong JNICALL -JVM_MaxMemory(void) { abort(); } +JVM_MaxMemory() +{ + return 0; +} extern "C" JNIEXPORT jint JNICALL JVM_ActiveProcessorCount(void) { abort(); } @@ -1182,7 +1251,15 @@ extern "C" JNIEXPORT jint JNICALL JVM_CountStackFrames(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_Interrupt(Thread*, jobject) { abort(); } +JVM_Interrupt(Thread* t, jobject thread) +{ + ENTER(t, Thread::ActiveState); + + Thread* p = reinterpret_cast(threadPeer(t, *thread)); + if (p) { + interrupt(t, p); + } +} extern "C" JNIEXPORT jboolean JNICALL JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) @@ -1246,7 +1323,10 @@ extern "C" JNIEXPORT jint JNICALL JVM_ClassLoaderDepth(Thread*) { abort(); } extern "C" JNIEXPORT jstring JNICALL -JVM_GetSystemPackage(Thread*, jstring) { abort(); } +JVM_GetSystemPackage(Thread*, jstring) +{ + return 0; +} extern "C" JNIEXPORT jobjectArray JNICALL JVM_GetSystemPackages(Thread*) { abort(); } @@ -1434,13 +1514,23 @@ JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) } extern "C" JNIEXPORT jclass JNICALL -JVM_DefineClass(Thread*, const char*, jobject, const jbyte*, - jsize, jobject) { abort(); } +JVM_DefineClass(Thread* t, const char*, jobject loader, const uint8_t* data, + jsize length, jobject) +{ + ENTER(t, Thread::ActiveState); + + object c = defineClass(t, *loader, data, length); + + return c ? makeLocalReference(t, getJClass(t, c)) : 0; +} extern "C" JNIEXPORT jclass JNICALL -JVM_DefineClassWithSource(Thread*, const char*, jobject, - const jbyte*, jsize, jobject, - const char*) { abort(); } +JVM_DefineClassWithSource(Thread* t, const char*, jobject loader, + const uint8_t* data, jsize length, jobject, + const char*) +{ + return JVM_DefineClass(t, 0, loader, data, length, 0); +} extern "C" JNIEXPORT jstring JNICALL JVM_GetClassName(Thread* t, jclass c) @@ -1501,7 +1591,20 @@ extern "C" JNIEXPORT void JNICALL JVM_SetClassSigners(Thread*, jclass, jobjectArray) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_GetProtectionDomain(Thread*, jclass) { abort(); } +JVM_GetProtectionDomain(Thread* t, jclass) +{ + ENTER(t, Thread::ActiveState); + + object openJDK = resolveClass + (t, root(t, Machine::BootLoader), "avian/OpenJDK"); + if (UNLIKELY(t->exception)) return 0; + + object method = resolveMethod + (t, openJDK, "getProtectionDomain", "()Ljava/security/ProtectionDomain;"); + if (UNLIKELY(t->exception)) return 0; + + return makeLocalReference(t, t->m->processor->invoke(t, method, 0)); +} extern "C" JNIEXPORT void JNICALL JVM_SetProtectionDomain(Thread*, jclass, jobject) { abort(); } @@ -1625,10 +1728,6 @@ JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { - fprintf(stderr, "method %s.%s has annotations\n", - &byteArrayBody(t, className(t, jclassVmClass(t, *c)), 0), - &byteArrayBody(t, methodName(t, vmMethod), 0)); - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, addendumPool(t, methodAddendum(t, vmMethod))); } @@ -1809,6 +1908,10 @@ JVM_InvokeMethod(Thread* t, jobject method, jobject instance, (t, jclassVmClass(t, jmethodClazz(t, *method))), jmethodSlot(t, *method)); + if (methodFlags(t, vmMethod) & ACC_STATIC) { + instance = 0; + } + object result; if (arguments) { result = t->m->processor->invokeArray @@ -2191,7 +2294,10 @@ extern "C" JNIEXPORT jint JNICALL JVM_SetLength(jint, jlong) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Sync(jint) { abort(); } +JVM_Sync(jint fd) +{ + return fsync(fd); +} extern "C" JNIEXPORT jint JNICALL JVM_InitializeSocketLibrary() diff --git a/src/machine.cpp b/src/machine.cpp index 63ba9c60fa..243ef6be9c 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1789,7 +1789,12 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_) if (elementClass == 0) return 0; } - return makeArrayClass(t, loader, dimensions, spec, elementClass); + object class_ = hashMapFind + (t, getClassLoaderMap(t, classLoader(t, elementClass)), spec, + byteArrayHash, byteArrayEqual); + + return class_ ? class_ : makeArrayClass + (t, classLoader(t, elementClass), dimensions, spec, elementClass); } object @@ -2281,15 +2286,19 @@ Thread::init() if (parent == 0) { enter(this, Thread::ActiveState); + if (exception == 0) { + setRoot(this, Machine::NullPointerException, m->classpath->makeThrowable + (this, Machine::NullPointerExceptionType)); + + if (exception == 0) { + setRoot(this, Machine::ArrayIndexOutOfBoundsException, + m->classpath->makeThrowable + (this, Machine::IndexOutOfBoundsExceptionType)); + } + } + m->classpath->boot(this); - setRoot(this, Machine::NullPointerException, m->classpath->makeThrowable - (this, Machine::NullPointerExceptionType)); - - setRoot(this, Machine::ArrayIndexOutOfBoundsException, - m->classpath->makeThrowable - (this, Machine::IndexOutOfBoundsExceptionType)); - enter(this, Thread::IdleState); } } @@ -2441,7 +2450,7 @@ enter(Thread* t, Thread::State s) // todo: this won't always help if some other thread sets the // daemon field. The thread trying to shut down the VM really // just needs to count from scratch every time any thread makes a - // transition. + // transition (i.e. eliminate Machine::daemonCount). if (UNLIKELY(((t->flags & Thread::DaemonFlag) != 0) != threadDaemon(t, t->javaThread))) From d0d53e2e10b70a5fa467b4446af988286c28cca4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 16 Sep 2010 19:43:27 -0600 Subject: [PATCH 041/274] fix custom-classloader-related concurrency problems and other bugs The main changes in this commit ensure that we don't hold the global class lock when doing class resolution using application-defined classloaders. Such classloaders may do their own locking (in fact, it's almost certain), making deadlock likely when mixed with VM-level locking in various orders. Other changes include a fix to avoid overflow when waiting for extremely long intervals and a GC root stack mapping bug. --- classpath/java/lang/Thread.java | 22 +-- makefile | 4 - src/builtin.cpp | 21 ++- src/classpath-avian.cpp | 3 +- src/classpath-openjdk.cpp | 33 +++- src/compile.cpp | 284 ++++++++++++++++++-------------- src/jnienv.cpp | 4 +- src/machine.cpp | 140 +++++++++------- src/machine.h | 35 ++-- src/posix.cpp | 6 +- src/types.def | 5 +- test/GC.java | 12 ++ 12 files changed, 337 insertions(+), 232 deletions(-) diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index fec432b34e..64d0eab00a 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -15,7 +15,7 @@ import java.util.WeakHashMap; public class Thread implements Runnable { private long peer; - private boolean interrupted; + private volatile boolean interrupted; private boolean daemon; private byte state; private byte priority; @@ -141,25 +141,9 @@ public class Thread implements Runnable { public static native Thread currentThread(); - private static native void interrupt(long peer); + public native void interrupt(); - public synchronized void interrupt() { - if (peer != 0) { - interrupt(peer); - } else { - interrupted = true; - } - } - - public static boolean interrupted() { - Thread t = currentThread(); - - synchronized (t) { - boolean v = t.interrupted; - t.interrupted = false; - return v; - } - } + public native boolean interrupted(); public static boolean isInterrupted() { return currentThread().interrupted; diff --git a/makefile b/makefile index 35b66a591f..1146998f08 100644 --- a/makefile +++ b/makefile @@ -340,10 +340,6 @@ vm-sources = \ vm-asm-sources = $(src)/$(asm).S ifeq ($(process),compile) - vm-depends += \ - $(src)/compiler.h \ - $(src)/vector.h - vm-sources += \ $(src)/compiler.cpp \ $(src)/$(asm).cpp diff --git a/src/builtin.cpp b/src/builtin.cpp index c1dc0f5c29..cb45cacd04 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -84,7 +84,12 @@ Avian_avian_SystemClassLoader_resourceExists if (LIKELY(name)) { RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - return getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); + + bool r = getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); + + fprintf(stderr, "resource %s exists? %d\n", n, r); + + return r; } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); @@ -144,7 +149,11 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - System::Region* r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + if (r) { jint rSize = r->length(); r->dispose(); @@ -164,8 +173,12 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - return reinterpret_cast - (t->m->appFinder->find(RUNTIME_ARRAY_BODY(p))); + System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); + if (r == 0) { + r = t->m->appFinder->find(RUNTIME_ARRAY_BODY(p)); + } + + return reinterpret_cast(r); } else { t->exception = t->m->classpath->makeThrowable (t, Machine::NullPointerExceptionType); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 6d64767ed7..9ee25aa8cc 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -50,7 +50,7 @@ class MyClasspath : public Classpath { return vm::makeThread (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, - root(t, Machine::BootLoader), 0, 0, group); + root(t, Machine::BootLoader), 0, 0, group, 0); } virtual void @@ -70,6 +70,7 @@ class MyClasspath : public Classpath { (Thread* t, Machine::Type type, object message, object trace, object cause) { PROTECT(t, message); + PROTECT(t, trace); PROTECT(t, cause); if (trace == 0) { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 61d54d6eed..1c3a5f1bab 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -186,7 +186,7 @@ class MyClasspath : public Classpath { return vm::makeThread (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, root(t, Machine::BootLoader), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, - 0, false); + 0, 0, false); } virtual void @@ -210,6 +210,7 @@ class MyClasspath : public Classpath { (Thread* t, Machine::Type type, object message, object trace, object cause) { PROTECT(t, message); + PROTECT(t, trace); PROTECT(t, cause); if (trace == 0) { @@ -534,6 +535,23 @@ setProperty(Thread* t, object method, object properties, t->m->processor->invoke(t, method, properties, n, v); } +object +interruptLock(Thread* t, object thread) +{ + if (threadInterruptLock(t, thread) == 0) { + PROTECT(t, thread); + ACQUIRE(t, t->m->referenceLock); + + if (threadInterruptLock(t, thread) == 0) { + object head = makeMonitorNode(t, 0, 0); + object lock = makeMonitor(t, 0, 0, 0, head, head, 0); + set(t, thread, ThreadInterruptLock, lock); + } + } + + return threadInterruptLock(t, thread); +} + } // namespace local } // namespace @@ -1255,10 +1273,14 @@ JVM_Interrupt(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); + monitorAcquire(t, local::interruptLock(t, *thread)); Thread* p = reinterpret_cast(threadPeer(t, *thread)); if (p) { interrupt(t, p); + } else { + threadInterrupted(t, *thread) = true; } + monitorRelease(t, local::interruptLock(t, *thread)); } extern "C" JNIEXPORT jboolean JNICALL @@ -1266,12 +1288,12 @@ JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) { ENTER(t, Thread::ActiveState); - acquire(t, *thread); + monitorAcquire(t, local::interruptLock(t, *thread)); bool v = threadInterrupted(t, *thread); if (clear) { threadInterrupted(t, *thread) = false; } - release(t, *thread); + monitorRelease(t, local::interruptLock(t, *thread)); return v; } @@ -2414,7 +2436,10 @@ extern "C" JNIEXPORT struct hostent* JNICALL JVM_GetHostByName(char*) { abort(); } extern "C" JNIEXPORT int JNICALL -JVM_GetHostName(char*, int) { abort(); } +JVM_GetHostName(char* name, int length) +{ + return gethostname(name, length); +} extern "C" JNIEXPORT void* JNICALL JVM_RawMonitorCreate(void) diff --git a/src/compile.cpp b/src/compile.cpp index ced35ebf15..f3a0090c27 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -327,6 +327,12 @@ compiledSize(intptr_t address) return reinterpret_cast(address)[-1]; } +intptr_t +methodCompiled(Thread* t, object method) +{ + return codeCompiled(t, methodCode(t, method)); +} + intptr_t compareIpToMethodBounds(Thread* t, intptr_t ip, object method) { @@ -2619,7 +2625,7 @@ throw_(MyThread* t, object o) (t, Machine::NullPointerExceptionType); } -// printTrace(t, t->exception); + printTrace(t, t->exception); unwind(t); } @@ -2659,6 +2665,8 @@ makeNew64(Thread* t, object class_) void gcIfNecessary(MyThread* t) { + stress(t); + if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } @@ -3219,6 +3227,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3311,6 +3320,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 1)) { c->saveLocals(); + frame->trace(0, 0); } if (CheckArrayBounds) { @@ -3741,6 +3751,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -4709,6 +4720,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (inTryBlock(t, code, ip - 3)) { c->saveLocals(); + frame->trace(0, 0); } } @@ -5006,7 +5018,7 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, } } -void +object translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, intptr_t start) { @@ -5043,7 +5055,7 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool (t, method, exceptionHandlerCatchType(oldHandler) - 1); - if (UNLIKELY(t->exception)) return; + if (UNLIKELY(t->exception)) return 0; } else { type = 0; } @@ -5051,11 +5063,13 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type); } - set(t, methodCode(t, method), CodeExceptionHandlerTable, newTable); + return newTable; + } else { + return 0; } } -void +object translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) { object oldTable = codeLineNumberTable(t, code); @@ -5075,7 +5089,9 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) lineNumberLine(newLine) = lineNumberLine(oldLine); } - set(t, code, CodeLineNumberTable, newTable); + return newTable; + } else { + return 0; } } @@ -5527,23 +5543,23 @@ compareSubroutineTracePointers(const void* va, const void* vb) object makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements, unsigned pathFootprint, - unsigned mapCount) + TraceElement** elements, unsigned elementCount, + unsigned pathFootprint, unsigned mapCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); unsigned indexOffset = sizeof(FrameMapTableHeader); unsigned mapsOffset = indexOffset - + (context->traceLogCount * sizeof(FrameMapTableIndexElement)); + + (elementCount * sizeof(FrameMapTableIndexElement)); unsigned pathsOffset = mapsOffset + (ceiling(mapCount * mapSize, 32) * 4); object table = makeByteArray(t, pathsOffset + pathFootprint); int8_t* body = &byteArrayBody(t, table, 0); - new (body) FrameMapTableHeader(context->traceLogCount); + new (body) FrameMapTableHeader(elementCount); unsigned nextTableIndex = pathsOffset; unsigned nextMapIndex = 0; - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; unsigned mapBase = nextMapIndex; @@ -5645,27 +5661,26 @@ makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, object makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, - TraceElement** elements) + TraceElement** elements, unsigned elementCount) { unsigned mapSize = frameMapSizeInBits(t, context->method); object table = makeIntArray - (t, context->traceLogCount - + ceiling(context->traceLogCount * mapSize, 32)); + (t, elementCount + ceiling(elementCount * mapSize, 32)); - assert(t, intArrayLength(t, table) == context->traceLogCount + assert(t, intArrayLength(t, table) == elementCount + simpleFrameMapTableSize(t, context->method, table)); - for (unsigned i = 0; i < context->traceLogCount; ++i) { + for (unsigned i = 0; i < elementCount; ++i) { TraceElement* p = elements[i]; intArrayBody(t, table, i) = static_cast(p->address->value()) - reinterpret_cast(start); - assert(t, context->traceLogCount + ceiling((i + 1) * mapSize, 32) + assert(t, elementCount + ceiling((i + 1) * mapSize, 32) <= intArrayLength(t, table)); if (mapSize) { - copyFrameMap(&intArrayBody(t, table, context->traceLogCount), p->map, + copyFrameMap(&intArrayBody(t, table, elementCount), p->map, mapSize, i * mapSize, p, 0); } } @@ -5673,7 +5688,7 @@ makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, return table; } -uint8_t* +void finish(MyThread* t, Allocator* allocator, Context* context) { Compiler* c = context->compiler; @@ -5703,7 +5718,13 @@ finish(MyThread* t, Allocator* allocator, Context* context) trap(); } + // todo: this is a CPU-intensive operation, so consider doing it + // earlier before we've acquired the global class lock to improve + // parallelism (the downside being that it may end up being a waste + // of cycles if another thread compiles the same method in parallel, + // which might be mitigated by fine-grained, per-method locking): unsigned codeSize = c->compile(); + uintptr_t* code = static_cast (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); code[0] = codeSize; @@ -5744,21 +5765,20 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - translateExceptionHandlerTable + object newExceptionHandlerTable = translateExceptionHandlerTable (t, c, context->method, reinterpret_cast(start)); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; + PROTECT(t, newExceptionHandlerTable); - translateLineNumberTable(t, c, methodCode(t, context->method), - reinterpret_cast(start)); + object newLineNumberTable = translateLineNumberTable + (t, c, methodCode(t, context->method), reinterpret_cast(start)); { object code = methodCode(t, context->method); - code = makeCode(t, 0, - codeExceptionHandlerTable(t, code), - codeLineNumberTable(t, code), - codeMaxStack(t, code), - codeMaxLocals(t, code), - 0); + code = makeCode + (t, 0, newExceptionHandlerTable, newLineNumberTable, + reinterpret_cast(start), codeMaxStack(t, code), + codeMaxLocals(t, code), 0); set(t, context->method, MethodCode, code); } @@ -5771,44 +5791,46 @@ finish(MyThread* t, Allocator* allocator, Context* context) for (TraceElement* p = context->traceLog; p; p = p->next) { assert(t, index < context->traceLogCount); - SubroutineTrace* trace = p->subroutineTrace; - unsigned myMapCount = 1; - if (trace) { - for (Subroutine* s = trace->path->call->subroutine; - s; s = s->stackNext) - { - unsigned callCount = s->callCount; - myMapCount *= callCount; - if (not s->visited) { - s->visited = true; - pathFootprint += sizeof(FrameMapTablePath) - + (sizeof(int32_t) * callCount); + if (p->address) { + SubroutineTrace* trace = p->subroutineTrace; + unsigned myMapCount = 1; + if (trace) { + for (Subroutine* s = trace->path->call->subroutine; + s; s = s->stackNext) + { + unsigned callCount = s->callCount; + myMapCount *= callCount; + if (not s->visited) { + s->visited = true; + pathFootprint += sizeof(FrameMapTablePath) + + (sizeof(int32_t) * callCount); + } } } - } - mapCount += myMapCount; + mapCount += myMapCount; - RUNTIME_ARRAY_BODY(elements)[index++] = p; + RUNTIME_ARRAY_BODY(elements)[index++] = p; - if (p->target) { - insertCallNode - (t, makeCallNode - (t, p->address->value(), p->target, p->flags, 0)); + if (p->target) { + insertCallNode + (t, makeCallNode + (t, p->address->value(), p->target, p->flags, 0)); + } } } - qsort(RUNTIME_ARRAY_BODY(elements), context->traceLogCount, + qsort(RUNTIME_ARRAY_BODY(elements), index, sizeof(TraceElement*), compareTraceElementPointers); object map; if (pathFootprint) { map = makeGeneralFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements), pathFootprint, + (t, context, start, RUNTIME_ARRAY_BODY(elements), index, pathFootprint, mapCount); } else { map = makeSimpleFrameMapTable - (t, context, start, RUNTIME_ARRAY_BODY(elements)); + (t, context, start, RUNTIME_ARRAY_BODY(elements), index); } set(t, methodCode(t, context->method), CodePool, map); @@ -5838,12 +5860,10 @@ finish(MyThread* t, Allocator* allocator, Context* context) } syncInstructionCache(start, codeSize); - - return start; } -uint8_t* -compile(MyThread* t, Allocator* allocator, Context* context) +void +compile(MyThread* t, Context* context) { Compiler* c = context->compiler; @@ -5908,7 +5928,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) Compiler::State* state = c->saveState(); compile(t, &frame, 0); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; context->dirtyRoots = false; unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); @@ -5961,7 +5981,7 @@ compile(MyThread* t, Allocator* allocator, Context* context) } compile(t, &frame2, exceptionHandlerIp(eh), start); - if (UNLIKELY(t->exception)) return 0; + if (UNLIKELY(t->exception)) return; context->eventLog.append(PopContextEvent); @@ -5977,8 +5997,6 @@ compile(MyThread* t, Allocator* allocator, Context* context) context->dirtyRoots = false; calculateFrameMaps(t, context, 0, 0); } - - return finish(t, allocator, context); } void @@ -7169,7 +7187,7 @@ class SegFaultHandler: public System::SignalHandler { t->exception = root(t, Machine::NullPointerException); } -// printTrace(t, t->exception); + printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, base, stack, &continuation); @@ -7283,10 +7301,13 @@ class MyProcessor: public Processor { object class_, object code) { + if (code) { + codeCompiled(t, code) = local::defaultThunk(static_cast(t)); + } + return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code, - local::defaultThunk(static_cast(t))); + offset, 0, name, spec, addendum, class_, code); } virtual object @@ -8083,7 +8104,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); - methodCompiled(t, method) + codeCompiled(t, methodCode(t, method)) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); @@ -8597,65 +8618,86 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (UNLIKELY(t->exception)) return; } - if (methodAddress(t, method) == defaultThunk(t)) { - ACQUIRE(t, t->m->classLock); - - if (methodAddress(t, method) == defaultThunk(t)) { - assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); - - Context context(t, bootContext, method); - uint8_t* compiled = compile(t, allocator, &context); - if (UNLIKELY(t->exception)) return; - - if (DebugMethodTree) { - fprintf(stderr, "insert method at %p\n", compiled); - } - - // We can't set the MethodCompiled field on the original method - // before it is placed into the method tree, since another - // thread might call the method, from which stack unwinding - // would fail (since there is not yet an entry in the method - // tree). However, we can't insert the original method into the - // tree before setting the MethodCompiled field on it since we - // rely on that field to determine its position in the tree. - // Therefore, we insert a clone in its place. Later, we'll - // replace the clone with the original to save memory. - - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodAddendum(t, method), - methodClass(t, method), - methodCode(t, method), - reinterpret_cast(compiled)); - - setRoot - (t, MethodTree, treeInsert - (t, &(context.zone), root(t, MethodTree), - reinterpret_cast(compiled), clone, - root(t, MethodTreeSentinal), - compareIpToMethodBounds)); - - storeStoreMemoryBarrier(); - - methodCompiled(t, method) = reinterpret_cast(compiled); - - if (methodVirtual(t, method)) { - classVtable(t, methodClass(t, method), methodOffset(t, method)) - = compiled; - } - - treeUpdate(t, root(t, MethodTree), reinterpret_cast(compiled), - method, root(t, MethodTreeSentinal), compareIpToMethodBounds); - } + if (methodAddress(t, method) != defaultThunk(t)) { + return; } + + assert(t, (methodFlags(t, method) & ACC_NATIVE) == 0); + + // We must avoid acquiring any locks until after the first pass of + // compilation, since this pass may trigger classloading operations + // involving application classloaders and thus the potential for + // deadlock. To make this safe, we use a private clone of the + // method so that we won't be confused if another thread updates the + // original while we're working. + + object clone = makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodName(t, method), + methodSpec(t, method), + methodAddendum(t, method), + methodClass(t, method), + methodCode(t, method)); + + loadMemoryBarrier(); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + PROTECT(t, clone); + + Context context(t, bootContext, clone); + compile(t, &context); + if (UNLIKELY(t->exception)) return; + + ACQUIRE(t, t->m->classLock); + + if (methodAddress(t, method) != defaultThunk(t)) { + return; + } + + finish(t, allocator, &context); + if (UNLIKELY(t->exception)) return; + + if (DebugMethodTree) { + fprintf(stderr, "insert method at %p\n", + reinterpret_cast(methodCompiled(t, clone))); + } + + // We can't update the MethodCode field on the original method + // before it is placed into the method tree, since another thread + // might call the method, from which stack unwinding would fail + // (since there is not yet an entry in the method tree). However, + // we can't insert the original method into the tree before updating + // the MethodCode field on it since we rely on that field to + // determine its position in the tree. Therefore, we insert the + // clone in its place. Later, we'll replace the clone with the + // original to save memory. + + setRoot + (t, MethodTree, treeInsert + (t, &(context.zone), root(t, MethodTree), + methodCompiled(t, clone), clone, root(t, MethodTreeSentinal), + compareIpToMethodBounds)); + + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, methodCode(t, clone)); + + if (methodVirtual(t, method)) { + classVtable(t, methodClass(t, method), methodOffset(t, method)) + = reinterpret_cast(methodCompiled(t, clone)); + } + + treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone), + method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } object& diff --git a/src/jnienv.cpp b/src/jnienv.cpp index ed36e9451d..b09c0815c8 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2007,11 +2007,11 @@ parseSize(const char* s) return 0; } else if (s[length - 1] == 'k') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024; } else if (s[length - 1] == 'm') { memcpy(RUNTIME_ARRAY_BODY(buffer), s, length - 1); - RUNTIME_ARRAY_BODY(buffer)[length] = 0; + RUNTIME_ARRAY_BODY(buffer)[length - 1] = 0; return atoi(RUNTIME_ARRAY_BODY(buffer)) * 1024 * 1024; } else { return atoi(s); diff --git a/src/machine.cpp b/src/machine.cpp index 243ef6be9c..0542a5c216 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -726,6 +726,8 @@ internByteArray(Thread* t, object array) { PROTECT(t, array); + ACQUIRE(t, t->m->referenceLock); + object n = hashMapFindNode (t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual); if (n) { @@ -1199,7 +1201,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -1297,7 +1299,6 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap, methodSpec(t, method), 0, class_, - 0, 0); hashMapInsert(t, virtualMap, method, method, methodHash); @@ -1705,6 +1706,7 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, // todo: arrays should implement Cloneable and Serializable if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) { + PROTECT(t, loader); PROTECT(t, spec); PROTECT(t, elementClass); @@ -2014,10 +2016,10 @@ boot(Thread* t) setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); m->processor->boot(t, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod - (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0); + (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" @@ -3217,59 +3219,65 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) { return resolveSystemClass(t, loader, spec, throw_); } else { + expect(t, throw_); + PROTECT(t, loader); PROTECT(t, spec); - ACQUIRE(t, t->m->classLock); + { ACQUIRE(t, t->m->classLock); - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + object class_ = hashMapFind + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + + if (class_) { + return class_; + } } - object class_ = hashMapFind - (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + object class_; + if (byteArrayBody(t, spec, 0) == '[') { + class_ = resolveArrayClass(t, loader, spec, throw_); + } else { + if (root(t, Machine::LoadClassMethod) == 0) { + object m = resolveMethod + (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", + "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - if (class_ == 0) { - if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec, throw_); - } else { - if (root(t, Machine::LoadClassMethod) == 0) { - object m = resolveMethod - (t, root(t, Machine::BootLoader), "java/lang/ClassLoader", - "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + if (m) { + setRoot(t, Machine::LoadClassMethod, m); - if (m) { - setRoot(t, Machine::LoadClassMethod, m); - - object classLoaderClass = type(t, Machine::ClassLoaderType); + object classLoaderClass = type(t, Machine::ClassLoaderType); - if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { - resolveSystemClass - (t, root(t, Machine::BootLoader), - vm::className(t, classLoaderClass)); - } - } - } + if (classVmFlags(t, classLoaderClass) & BootstrapFlag) { + resolveSystemClass + (t, root(t, Machine::BootLoader), + vm::className(t, classLoaderClass)); + } + } + } + + if (LIKELY(t->exception == 0)) { + object method = findVirtualMethod + (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); if (LIKELY(t->exception == 0)) { - object method = findVirtualMethod - (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); + PROTECT(t, method); - if (LIKELY(t->exception == 0)) { - PROTECT(t, method); + RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast + (&byteArrayBody(t, spec, 0))); - RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); - replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast - (&byteArrayBody(t, spec, 0))); + object specString = makeString(t, "%s", s); - object specString = makeString(t, "%s", s); + class_ = t->m->processor->invoke(t, method, loader, specString); - class_ = t->m->processor->invoke(t, method, loader, specString); - - if (LIKELY(class_ and t->exception == 0)) { - class_ = jclassVmClass(t, class_); - } + if (LIKELY(class_ and t->exception == 0)) { + class_ = jclassVmClass(t, class_); } } } @@ -3278,6 +3286,8 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) if (class_) { PROTECT(t, class_); + ACQUIRE(t, t->m->classLock); + hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_ and t->exception == 0) { @@ -3659,8 +3669,8 @@ collect(Thread* t, Heap::CollectionType type) ENTER(t, Thread::ExclusiveState); #ifdef VM_STRESS - bool stress = t->stress; - if (not stress) t->stress = true; + bool stress = (t->flags |= Thread::StressFlag); + if (not stress) atomicOr(&(t->flags), Thread::StressFlag); #endif Machine* m = t->m; @@ -3681,7 +3691,7 @@ collect(Thread* t, Heap::CollectionType type) m->fixedFootprint = 0; #ifdef VM_STRESS - if (not stress) t->stress = false; + if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); #endif object f = t->m->finalizeQueue; @@ -4005,6 +4015,8 @@ vmPrintTrace(Thread* t) Thread* t; } v(t); + fprintf(stderr, "debug trace for thread %p\n", t); + t->m->processor->walkStack(t, &v); } @@ -4012,24 +4024,24 @@ vmPrintTrace(Thread* t) void* vmAddressFromLine(Thread* t, object m, unsigned line) { - object code = methodCode(t, m); - printf("code: %p\n", code); - object lnt = codeLineNumberTable(t, code); - printf("lnt: %p\n", lnt); + object code = methodCode(t, m); + printf("code: %p\n", code); + object lnt = codeLineNumberTable(t, code); + printf("lnt: %p\n", lnt); - if (lnt) { - unsigned last = 0; - unsigned bottom = 0; - unsigned top = lineNumberTableLength(t, lnt); - for(unsigned i = bottom; i < top; i++) - { - LineNumber* ln = lineNumberTableBody(t, lnt, i); - if(lineNumberLine(ln) == line) - return reinterpret_cast(lineNumberIp(ln)); - else if(lineNumberLine(ln) > line) - return reinterpret_cast(last); - last = lineNumberIp(ln); - } - } - return 0; + if (lnt) { + unsigned last = 0; + unsigned bottom = 0; + unsigned top = lineNumberTableLength(t, lnt); + for(unsigned i = bottom; i < top; i++) + { + LineNumber* ln = lineNumberTableBody(t, lnt, i); + if(lineNumberLine(ln) == line) + return reinterpret_cast(lineNumberIp(ln)); + else if(lineNumberLine(ln) > line) + return reinterpret_cast(last); + last = lineNumberIp(ln); + } + } + return 0; } diff --git a/src/machine.h b/src/machine.h index ec2677109e..b7b154ffa2 100644 --- a/src/machine.h +++ b/src/machine.h @@ -30,6 +30,9 @@ #define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x) +#define ACQUIRE_OBJECT(t, x) \ + ObjectMonitorResource MAKE_NAME(monitorResource_) (t, x) + #define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x) #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) @@ -1507,20 +1510,19 @@ shutDown(Thread* t); inline void stress(Thread* t) { - if ((not t->stress) - and (not t->tracing) + if ((t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and t->state != Thread::NoState and t->state != Thread::IdleState) { - t->stress = true; + atomicOr(&(t->flags), Thread::StressFlag); # ifdef VM_STRESS_MAJOR - collect(t, Heap::MajorCollection); + collect(t, Heap::MajorCollection); # else // not VM_STRESS_MAJOR - collect(t, Heap::MinorCollection); + collect(t, Heap::MinorCollection); # endif // not VM_STRESS_MAJOR - t->stress = false; + atomicAnd(&(t->flags), ~Thread::StressFlag); } } @@ -2607,6 +2609,21 @@ monitorNotifyAll(Thread* t, object monitor) while (monitorNotify(t, monitor)) { } } +class ObjectMonitorResource { + public: + ObjectMonitorResource(Thread* t, object o): o(o), protector(t, &(this->o)) { + monitorAcquire(protector.t, o); + } + + ~ObjectMonitorResource() { + monitorRelease(protector.t, o); + } + + private: + object o; + Thread::SingleProtector protector; +}; + object objectMonitor(Thread* t, object o, bool createNew); @@ -2621,8 +2638,7 @@ acquire(Thread* t, object o) object m = objectMonitor(t, o, true); if (DebugMonitors) { - fprintf(stderr, "thread %p acquires %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p acquires %p for %x\n", t, m, hash); } monitorAcquire(t, m); @@ -2639,8 +2655,7 @@ release(Thread* t, object o) object m = objectMonitor(t, o, false); if (DebugMonitors) { - fprintf(stderr, "thread %p releases %p for %x\n", - t, m, hash); + fprintf(stderr, "thread %p releases %p for %x\n", t, m, hash); } monitorRelease(t, m); diff --git a/src/posix.cpp b/src/posix.cpp index a40d555334..0a96f70f29 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,6 +14,8 @@ # define _XOPEN_SOURCE #endif +#define __STDC_CONSTANT_MACROS + #include "sys/mman.h" #include "sys/types.h" #include "sys/stat.h" @@ -287,7 +289,9 @@ class MySystem: public System { owner_ = 0; pthread_mutex_unlock(&mutex); - if (time) { + // pretend anything greater than one million years (in + // milliseconds) is infinity so as to avoid overflow: + if (time and time < INT64_C(31536000000000000)) { int64_t then = s->now() + time; timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 }; int rv UNUSED = pthread_cond_timedwait diff --git a/src/types.def b/src/types.def index 0ddeb92a3c..854798c84e 100644 --- a/src/types.def +++ b/src/types.def @@ -26,8 +26,7 @@ (type field avian/VMField) -(type method avian/VMMethod - (intptr_t compiled)) +(type method avian/VMMethod) (type addendum avian/Addendum) @@ -64,6 +63,7 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) + (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) (array uint8_t body)) @@ -163,6 +163,7 @@ (type thread java/lang/Thread (require object sleepLock) + (require object interruptLock) (require uint8_t interrupted) (alias peer uint64_t eetop)) diff --git a/test/GC.java b/test/GC.java index d04c577fc8..9fabee0cc9 100644 --- a/test/GC.java +++ b/test/GC.java @@ -1,4 +1,14 @@ public class GC { + private static final Integer cache[] = new Integer[100]; + private static final Integer MAX_INT_OBJ = new Integer(Integer.MAX_VALUE); + + private static Integer valueOf(int i) { + try { + return cache[i]; + } catch (ArrayIndexOutOfBoundsException e) { + return (i == Integer.MAX_VALUE) ? MAX_INT_OBJ : new Integer(i); + } + } private static void small() { for (int i = 0; i < 1024; ++i) { @@ -145,6 +155,8 @@ public class GC { } public static void main(String[] args) { + valueOf(1000); + Object[] array = new Object[1024 * 1024]; array[0] = new Object(); From 20990950bbadff11c6686926f6fe1325bbbf17ec Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Sep 2010 16:03:37 -0600 Subject: [PATCH 042/274] build everything (including classes) in options-specific directory Previously, we only built platform specific code in an options-specific directory (e.g. build/linux-x86_64-debug), but built the Java classes in the shared, top-level build directory. This minimized duplication when building with different sets of options, but now that we're supporting the option of selecting a third-party class library, we need to put the classes in the options-specific directory as well. --- makefile | 119 +++++++++++++++++++++++++---------------------------- readme.txt | 2 +- 2 files changed, 57 insertions(+), 64 deletions(-) diff --git a/makefile b/makefile index 1146998f08..a48d4dbf9f 100644 --- a/makefile +++ b/makefile @@ -69,13 +69,12 @@ ifdef openjdk openjdk-lib-dir = $(openjdk)/jre/lib endif classpath-jar = $(openjdk)/jre/lib/rt.jar - test-library-path = $(openjdk-lib-dir):$(native-build) + test-library-path = $(openjdk-lib-dir):$(build) test-executable = $(executable-dynamic) endif root := $(shell (cd .. && pwd)) -build = build -native-build = $(build)/$(platform)-$(arch)$(options) +build = build/$(platform)-$(arch)$(options) classpath-build = $(build)/classpath test-build = $(build)/test src = src @@ -87,8 +86,7 @@ ifneq ($(classpath),avian) classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") else jni-sources := $(shell find $(classpath-src) -name '*.cpp') - jni-objects = \ - $(call cpp-objects,$(jni-sources),$(classpath-src),$(native-build)) + jni-objects = $(call cpp-objects,$(jni-sources),$(classpath-src),$(build)) endif input = List @@ -129,7 +127,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ - "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(native-build) \ + "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -DUSE_ATOMIC_OPERATIONS $(classpath-cflags) @@ -286,9 +284,8 @@ ifdef msvc mt = "mt.exe" cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ -DUSE_ATOMIC_OPERATIONS \ - -Fd$(native-build)/$(name).pdb -I"$(zlib)/include" -I$(src) \ - -I"$(native-build)" -I"$(windows-java-home)/include" \ - -I"$(windows-java-home)/include/win32" + -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ + -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" shared = -dll lflags = -nologo -LIBPATH:"$(zlib)/lib" -DEFAULTLIB:ws2_32 \ -DEFAULTLIB:zlib -MANIFEST -debug @@ -317,11 +314,11 @@ asm-objects = $(foreach x,$(1),$(patsubst $(2)/%.S,$(3)/%-asm.o,$(x))) java-classes = $(foreach x,$(1),$(patsubst $(2)/%.java,$(3)/%.class,$(x))) generated-code = \ - $(native-build)/type-enums.cpp \ - $(native-build)/type-declarations.cpp \ - $(native-build)/type-constructors.cpp \ - $(native-build)/type-initializations.cpp \ - $(native-build)/type-java-initializations.cpp + $(build)/type-enums.cpp \ + $(build)/type-declarations.cpp \ + $(build)/type-constructors.cpp \ + $(build)/type-initializations.cpp \ + $(build)/type-java-initializations.cpp vm-depends := $(generated-code) $(wildcard $(src)/*.h) @@ -347,13 +344,13 @@ ifeq ($(process),compile) vm-asm-sources += $(src)/compile-$(asm).S endif -vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(native-build)) -vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(native-build)) +vm-cpp-objects = $(call cpp-objects,$(vm-sources),$(src),$(build)) +vm-asm-objects = $(call asm-objects,$(vm-asm-sources),$(src),$(build)) vm-objects = $(vm-cpp-objects) $(vm-asm-objects) heapwalk-sources = $(src)/heapwalk.cpp heapwalk-objects = \ - $(call cpp-objects,$(heapwalk-sources),$(src),$(native-build)) + $(call cpp-objects,$(heapwalk-sources),$(src),$(build)) ifeq ($(heapdump),true) vm-sources += $(src)/heapdump.cpp @@ -372,12 +369,12 @@ endif bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ - $(call cpp-objects,$(bootimage-generator-sources),$(src),$(native-build)) + $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) bootimage-generator = \ $(build)/$(bootimage-platform)-$(build-arch)$(options)/bootimage-generator -bootimage-bin = $(native-build)/bootimage.bin -bootimage-object = $(native-build)/bootimage-bin.o +bootimage-bin = $(build)/bootimage.bin +bootimage-object = $(build)/bootimage-bin.o ifeq ($(bootimage),true) ifneq ($(build-arch),$(arch)) @@ -398,31 +395,31 @@ else endif driver-source = $(src)/main.cpp -driver-object = $(native-build)/main.o -driver-dynamic-object = $(native-build)/main-dynamic.o +driver-object = $(build)/main.o +driver-dynamic-object = $(build)/main-dynamic.o boot-source = $(src)/boot.cpp -boot-object = $(native-build)/boot.o +boot-object = $(build)/boot.o generator-headers = $(src)/constants.h generator-sources = $(src)/type-generator.cpp generator-objects = \ - $(call cpp-objects,$(generator-sources),$(src),$(native-build)) -generator = $(native-build)/generator + $(call cpp-objects,$(generator-sources),$(src),$(build)) +generator = $(build)/generator converter-objects = \ - $(native-build)/binaryToObject-main.o \ - $(native-build)/binaryToObject-elf64.o \ - $(native-build)/binaryToObject-elf32.o \ - $(native-build)/binaryToObject-mach-o64.o \ - $(native-build)/binaryToObject-mach-o32.o \ - $(native-build)/binaryToObject-pe.o -converter = $(native-build)/binaryToObject + $(build)/binaryToObject-main.o \ + $(build)/binaryToObject-elf64.o \ + $(build)/binaryToObject-elf32.o \ + $(build)/binaryToObject-mach-o64.o \ + $(build)/binaryToObject-mach-o32.o \ + $(build)/binaryToObject-pe.o +converter = $(build)/binaryToObject -static-library = $(native-build)/lib$(name).a -executable = $(native-build)/$(name)${exe-suffix} -dynamic-library = $(native-build)/$(so-prefix)jvm$(so-suffix) -executable-dynamic = $(native-build)/$(name)-dynamic${exe-suffix} +static-library = $(build)/lib$(name).a +executable = $(build)/$(name)${exe-suffix} +dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) +executable-dynamic = $(build)/$(name)-dynamic${exe-suffix} ifneq ($(classpath),avian) classpath-sources := \ @@ -451,7 +448,7 @@ endif classpath-classes = \ $(call java-classes,$(classpath-sources),$(classpath-src),$(classpath-build)) -classpath-object = $(native-build)/classpath-jar.o +classpath-object = $(build)/classpath-jar.o classpath-dep = $(classpath-build).dep vm-classes = \ @@ -520,20 +517,15 @@ clean: @echo "removing build" rm -rf build -.PHONY: clean-native -clean-native: - @echo "removing $(native-build)" - rm -rf $(native-build) +$(build)/compile-x86-asm.o: $(src)/continuations-x86.S -$(native-build)/compile-x86-asm.o: $(src)/continuations-x86.S - -gen-arg = $(shell echo $(1) | sed -e 's:$(native-build)/type-\(.*\)\.cpp:\1:') +gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) $(generator) $(classpath-build) $(call gen-arg,$(@)) < $(<) > $(@) -$(native-build)/type-generator.o: \ +$(build)/type-generator.o: \ $(generator-headers) $(classpath-build)/%.class: $(classpath-src)/%.java @@ -549,7 +541,8 @@ ifneq ($(classpath),avian) endif $(javac) -d $(classpath-build) \ -bootclasspath $(classpath-build) \ - $(shell $(MAKE) -s --no-print-directory $(classpath-classes)) + $(shell $(MAKE) -s --no-print-directory build=$(build) \ + $(classpath-classes)) @touch $(@) $(test-build)/%.class: $(test)/%.java @@ -558,7 +551,7 @@ $(test-build)/%.class: $(test)/%.java $(test-dep): $(test-sources) @echo "compiling test classes" @mkdir -p $(test-build) - files="$(shell $(MAKE) -s --no-print-directory $(test-classes))"; \ + files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ fi @@ -569,7 +562,7 @@ $(test-dep): $(test-sources) $(test-extra-dep): $(test-extra-sources) @echo "compiling extra test classes" @mkdir -p $(test-build) - files="$(shell $(MAKE) -s --no-print-directory $(test-extra-classes))"; \ + files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-extra-classes))"; \ if test -n "$${files}"; then \ $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ fi @@ -587,16 +580,16 @@ define compile-asm-object $(as) -I$(src) $(asmflags) -c $(<) -o $(@) endef -$(vm-cpp-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) -$(vm-asm-objects): $(native-build)/%-asm.o: $(src)/%.S +$(vm-asm-objects): $(build)/%-asm.o: $(src)/%.S $(compile-asm-object) -$(bootimage-generator-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(bootimage-generator-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) -$(heapwalk-objects): $(native-build)/%.o: $(src)/%.cpp $(vm-depends) +$(heapwalk-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) $(driver-object): $(driver-source) @@ -616,22 +609,22 @@ $(build)/classpath.jar: $(classpath-dep) cd $(classpath-build) && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) -$(native-build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp +$(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build-cxx) -c $(^) -o $(@) -$(native-build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp +$(build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) -$(native-build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp +$(build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) -$(native-build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp +$(build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) -$(native-build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp +$(build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) -$(native-build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp +$(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp $(build-cxx) -c $(^) -o $(@) $(converter): $(converter-objects) @@ -642,13 +635,13 @@ $(classpath-object): $(build)/classpath.jar $(converter) $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) -$(generator-objects): $(native-build)/%.o: $(src)/%.cpp +$(generator-objects): $(build)/%.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ -c $(<) -o $(@) -$(jni-objects): $(native-build)/%.o: $(classpath-src)/%.cpp +$(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) $(static-library): $(classpath-object-dep) @@ -727,7 +720,7 @@ $(dynamic-library): \ @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(native-build)/$(name).lib -MANIFESTFILE:$(@).manifest + -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else $(ld) $(^) -Wl,--version-script=openjdk.ld \ @@ -738,11 +731,11 @@ endif $(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) @echo "linking $(@)" ifdef msvc - $(ld) $(lflags) -LIBPATH:$(native-build) -DEFAULTLIB:$(name) \ + $(ld) $(lflags) -LIBPATH:$(build) -DEFAULTLIB:$(name) \ -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(<) -L$(native-build) -ljvm $(lflags) -o $(@) + $(ld) $(<) -L$(build) -ljvm $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/readme.txt b/readme.txt index 7ccd3d5cd4..93e658dada 100644 --- a/readme.txt +++ b/readme.txt @@ -246,7 +246,7 @@ VM object files and bootstrap classpath jar. $ mkdir hello $ cd hello $ ar x ../build/${platform}-${arch}/libavian.a - $ cp ../build/classpath.jar boot.jar + $ cp ../build/${platform}-${arch}/classpath.jar boot.jar Step 2: Build the Java code and add it to the jar. From 7fffba29e62e8d01f09aba2e8d374d269a2c6476 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Sep 2010 16:08:42 -0600 Subject: [PATCH 043/274] Keep reading in BufferedInputStream.read until in.available() <= 0 This corresponds to the documented behavior of OpenJDK's version. --- classpath/java/io/BufferedInputStream.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index b1bdec24a0..6d1c69b0ce 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -58,14 +58,19 @@ public class BufferedInputStream extends InputStream { length -= remaining; } - if (length > 0) { + while (length > 0) { int c = in.read(b, offset, length); if (c == -1) { if (count == 0) { count = -1; } + break; } else { count += c; + + if (in.available() <= 0) { + break; + } } } From a0a23b469271176c8df25de8a32e6947264be714 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Sep 2010 16:10:01 -0600 Subject: [PATCH 044/274] implement JVM_Yield --- src/classpath-openjdk.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 1c3a5f1bab..c762209189 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -43,6 +43,7 @@ # include # include # include +# include # define OPEN open # define CLOSE close @@ -1240,7 +1241,10 @@ JVM_SetThreadPriority(Thread*, jobject, jint) } extern "C" JNIEXPORT void JNICALL -JVM_Yield(Thread*, jclass) { abort(); } +JVM_Yield(Thread*, jclass) +{ + sched_yield(); +} extern "C" JNIEXPORT void JNICALL JVM_Sleep(Thread* t, jclass, jlong milliseconds) From 93c9395f1de324fa78a62492fe2e75095176e559 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Sep 2010 16:10:26 -0600 Subject: [PATCH 045/274] comment-out debug logging --- src/compile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index f3a0090c27..e0f1bbe00c 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2625,7 +2625,7 @@ throw_(MyThread* t, object o) (t, Machine::NullPointerExceptionType); } - printTrace(t, t->exception); +// printTrace(t, t->exception); unwind(t); } @@ -7187,7 +7187,7 @@ class SegFaultHandler: public System::SignalHandler { t->exception = root(t, Machine::NullPointerException); } - printTrace(t, t->exception); +// printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, base, stack, &continuation); From 64e42da348fb91f22a5537faf6ef860869bfff21 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 17 Sep 2010 16:11:04 -0600 Subject: [PATCH 046/274] implement avian.Handler.ResourceInputStream.available --- classpath/avian/resource/Handler.java | 6 ++++++ src/builtin.cpp | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/resource/Handler.java index 38d0312ff4..00068e0795 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/resource/Handler.java @@ -63,6 +63,12 @@ public class Handler extends URLStreamHandler { public static native void close(long peer) throws IOException; + public static native int available(long peer, int position); + + public int available() { + return available(peer, position); + } + public int read() throws IOException { if (peer != 0) { int c = read(peer, position); diff --git a/src/builtin.cpp b/src/builtin.cpp index cb45cacd04..f3ad3c6ec5 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -87,7 +87,7 @@ Avian_avian_SystemClassLoader_resourceExists bool r = getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); - fprintf(stderr, "resource %s exists? %d\n", n, r); +// fprintf(stderr, "resource %s exists? %d\n", n, r); return r; } else { @@ -186,6 +186,17 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open } } +extern "C" JNIEXPORT int64_t JNICALL +Avian_avian_resource_Handler_00024ResourceInputStream_available +(Thread*, object, uintptr_t* arguments) +{ + int64_t peer; memcpy(&peer, arguments, 8); + int32_t position = arguments[2]; + + System::Region* region = reinterpret_cast(peer); + return static_cast(region->length()) - position; +} + extern "C" JNIEXPORT int64_t JNICALL Avian_avian_resource_Handler_00024ResourceInputStream_read__JI (Thread*, object, uintptr_t* arguments) From 0456a9fd49907e9f1111c5e6cabe06de2763a8b5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Sep 2010 17:28:42 -0600 Subject: [PATCH 047/274] define user.dir property in Java_java_lang_System_getProperty --- classpath/java-lang.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 720b364729..15df10b680 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -389,6 +389,10 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, TCHAR buffer[MAX_PATH]; GetTempPath(MAX_PATH, buffer); r = e->NewStringUTF(buffer); + } else if (strcmp(chars, "user.dir") == 0) { + TCHAR buffer[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, buffer); + r = e->NewStringUTF(buffer); } else if (strcmp(chars, "user.home") == 0) { # ifdef _MSC_VER WCHAR buffer[MAX_PATH]; @@ -447,6 +451,8 @@ Java_java_lang_System_getProperty(JNIEnv* e, jclass, jstring name, #endif } else if (strcmp(chars, "java.io.tmpdir") == 0) { r = e->NewStringUTF("/tmp"); + } else if (strcmp(chars, "user.dir") == 0) { + r = e->NewStringUTF(getenv("PWD")); } else if (strcmp(chars, "user.home") == 0) { r = e->NewStringUTF(getenv("HOME")); } From 88942a96728566a0bd0d6a05ca7b0ba342cd4a5b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Sep 2010 17:30:39 -0600 Subject: [PATCH 048/274] search for jar file in Zip.java instead of trying to load by hard-coded name --- test/Zip.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/Zip.java b/test/Zip.java index 2aea1760f1..665086ea68 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -1,12 +1,31 @@ import java.io.InputStream; +import java.io.File; import java.util.Enumeration; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; public class Zip { + + private static String findJar(File directory) { + File[] files = directory.listFiles(); + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().endsWith(".jar")) { + return file.getAbsolutePath(); + } + } else if (file.isDirectory()) { + String result = findJar(file); + if (result != null) { + return result; + } + } + } + return null; + } public static void main(String[] args) throws Exception { - ZipFile file = new ZipFile("build/classpath.jar"); + ZipFile file = new ZipFile + (findJar(new File(System.getProperty("user.dir")))); byte[] buffer = new byte[4096]; for (Enumeration e = file.entries(); From 17f495eb270bee5cddf1e449aad3d6abd53c5f05 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Sep 2010 17:31:23 -0600 Subject: [PATCH 049/274] rework OpenJDK build to derive classpath and library path from environment We now consult the JAVA_HOME environment variable to determine where to find the system library JARs and SOs. Ultimately, we'll want to support self-contained build, but this allows Avian to behave like a conventional libjvm.so. --- makefile | 86 +++++++---------- src/classpath-avian.cpp | 8 +- src/classpath-common.h | 119 ++++++++++++++++------- src/classpath-openjdk.cpp | 102 +++++++++++++++++--- src/finder.cpp | 44 +++------ src/jnienv.cpp | 17 ++-- src/machine.cpp | 2 +- src/machine.h | 3 + src/posix.cpp | 52 +++++----- src/system.h | 6 +- src/tokenizer.h | 45 +++++++++ src/type-generator.cpp | 196 +++++++++++++++++--------------------- 12 files changed, 403 insertions(+), 277 deletions(-) create mode 100644 src/tokenizer.h diff --git a/makefile b/makefile index a48d4dbf9f..2c48a069a5 100644 --- a/makefile +++ b/makefile @@ -40,26 +40,20 @@ ifeq ($(continuations),true) options := $(options)-continuations endif +root := $(shell (cd .. && pwd)) +build = build/$(platform)-$(arch)$(options) +classpath-build = $(build)/classpath +test-build = $(build)/test +src = src +classpath-src = classpath +test = test + classpath = avian -test-library-path = . test-executable = $(executable) +generator-classpath = $(classpath-build) +boot-classpath = $(classpath-build) -ifdef gnu - classpath = gnu - options := $(options)-gnu - classapth-jar = $(gnu)/share/classpath/glibj.zip - classpath-libraries = \ - $(gnu)/lib/classpath/libjavaio.a \ - $(gnu)/lib/classpath/libjavalang.a \ - $(gnu)/lib/classpath/libjavalangreflect.a \ - $(gnu)/lib/classpath/libjavamath.a \ - $(gnu)/lib/classpath/libjavanet.a \ - $(gnu)/lib/classpath/libjavanio.a \ - $(gnu)/lib/classpath/libjavautil.a - classpath-cflags = -DBOOT_BUILTINS=\"javaio,javalang,javalangreflect,javamath,javanet,javanio,javautil\" -DAVIAN_GNU - classpath-lflags = -lgmp -endif ifdef openjdk classpath = openjdk options := $(options)-openjdk @@ -68,19 +62,12 @@ ifdef openjdk else openjdk-lib-dir = $(openjdk)/jre/lib endif - classpath-jar = $(openjdk)/jre/lib/rt.jar - test-library-path = $(openjdk-lib-dir):$(build) + classpath-cflags = -DAVIAN_OPENJDK_JAVA_HOME=\"$(openjdk)\" test-executable = $(executable-dynamic) + generator-classpath := $(generator-classpath):$(openjdk)/jre/lib/rt.jar + boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar endif -root := $(shell (cd .. && pwd)) -build = build/$(platform)-$(arch)$(options) -classpath-build = $(build)/classpath -test-build = $(build)/test -src = src -classpath-src = classpath -test = test - ifneq ($(classpath),avian) classpath-object-dep = $(build)/classpath-object.dep classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") @@ -138,7 +125,7 @@ cflags = $(build-cflags) common-lflags = -lm -lz $(classpath-lflags) -build-lflags = +build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl @@ -401,10 +388,15 @@ driver-dynamic-object = $(build)/main-dynamic.o boot-source = $(src)/boot.cpp boot-object = $(build)/boot.o -generator-headers = $(src)/constants.h -generator-sources = $(src)/type-generator.cpp +generator-depends := $(wildcard $(src)/*.h) +generator-sources = \ + $(src)/type-generator.cpp \ + $(src)/$(system).cpp \ + $(src)/finder.cpp +generator-cpp-objects = \ + $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%-build.o,$(x))) generator-objects = \ - $(call cpp-objects,$(generator-sources),$(src),$(build)) + $(call generator-cpp-objects,$(generator-sources),$(src),$(build)) generator = $(build)/generator converter-objects = \ @@ -467,9 +459,9 @@ test-extra-dep = $(test-build)-extra.dep class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) -flags = -cp $(test-build) +test-flags = -cp $(build)/test -args = $(flags) $(input) +test-args = $(test-flags) $(input) .PHONY: build build: $(static-library) $(executable) $(dynamic-library) \ @@ -481,20 +473,20 @@ $(test-extra-dep): $(classpath-dep) .PHONY: run run: build - $(executable) $(args) + LD_LIBRARY_PATH=$(build) $(test-executable) $(test-args) .PHONY: debug debug: build - gdb --args $(executable) $(args) + LD_LIBRARY_PATH=$(build) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build - $(vg) $(executable) $(args) + LD_LIBRARY_PATH=$(build) $(vg) $(test-executable) $(test-args) .PHONY: test test: build /bin/sh $(test)/test.sh 2>/dev/null \ - $(test-library-path) $(test-executable) $(mode) "$(flags)" \ + $(build) $(test-executable) $(mode) "$(test-flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: tarball @@ -523,24 +515,15 @@ gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) - $(generator) $(classpath-build) $(call gen-arg,$(@)) < $(<) > $(@) - -$(build)/type-generator.o: \ - $(generator-headers) + $(generator) $(generator-classpath) $(<) $(@) $(call gen-arg,$(@)) $(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) -$(classpath-dep): $(classpath-sources) $(classpath-jar) +$(classpath-dep): $(classpath-sources) @echo "compiling classpath classes" @mkdir -p $(classpath-build) -ifneq ($(classpath),avian) - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) xf $(classpath-jar)) -endif - $(javac) -d $(classpath-build) \ - -bootclasspath $(classpath-build) \ + $(javac) -d $(classpath-build) -bootclasspath $(boot-classpath) \ $(shell $(MAKE) -s --no-print-directory build=$(build) \ $(classpath-classes)) @touch $(@) @@ -553,7 +536,7 @@ $(test-dep): $(test-sources) @mkdir -p $(test-build) files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \ if test -n "$${files}"; then \ - $(javac) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ test/Subroutine.java @@ -564,7 +547,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) -d $(test-build) -bootclasspath $(classpath-build) $${files}; \ + $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi @touch $(@) @@ -635,7 +618,8 @@ $(classpath-object): $(build)/classpath.jar $(converter) $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) -$(generator-objects): $(build)/%.o: $(src)/%.cpp +$(generator-objects): $(generator-depends) +$(generator-objects): $(build)/%-build.o: $(src)/%.cpp @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(build-cxx) -DPOINTER_SIZE=$(pointer-size) -O0 -g3 $(build-cflags) \ diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 9ee25aa8cc..e3bbd602fe 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -92,6 +92,12 @@ class MyClasspath : public Classpath { // ignore } + virtual const char* + bootClasspath() + { + return ""; + } + virtual void dispose() { @@ -473,7 +479,7 @@ Avian_java_lang_Runtime_load RUNTIME_ARRAY(char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - loadLibrary(t, RUNTIME_ARRAY_BODY(n), mapName, true); + loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true); } extern "C" JNIEXPORT void JNICALL diff --git a/src/classpath-common.h b/src/classpath-common.h index b9f1ef69b0..3c65301de4 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -11,9 +11,11 @@ #ifndef CLASSPATH_COMMON_H #define CLASSPATH_COMMON_H +#include "tokenizer.h" + namespace vm { -inline object +object getCaller(Thread* t, unsigned target) { class Visitor: public Processor::StackVisitor { @@ -43,7 +45,7 @@ getCaller(Thread* t, unsigned target) return v.method; } -inline object +object getTrace(Thread* t, unsigned skipCount) { class Visitor: public Processor::StackVisitor { @@ -84,7 +86,7 @@ getTrace(Thread* t, unsigned skipCount) return v.trace; } -inline bool +bool compatibleArrayTypes(Thread* t, object a, object b) { return classArrayElementSize(t, a) @@ -94,7 +96,7 @@ compatibleArrayTypes(Thread* t, object a, object b) or (classVmFlags(t, b) & PrimitiveFlag)))); } -inline void +void arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, int32_t dstOffset, int32_t length) { @@ -160,37 +162,13 @@ runOnLoadIfFound(Thread* t, System::Library* library) } System::Library* -loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) +loadLibrary(Thread* t, const char* name) { ACQUIRE(t, t->m->classLock); - const char* builtins = findProperty(t, "avian.builtins"); - if (mapName and builtins) { - const char* s = builtins; - while (*s) { - unsigned length = strlen(name); - if (::strncmp(s, name, length) == 0 - and (s[length] == ',' or s[length] == 0)) - { - // library is built in to this executable - if (runOnLoad and not t->m->triedBuiltinOnLoad) { - t->m->triedBuiltinOnLoad = true; - runOnLoadIfFound(t, t->m->libraries); - } - return t->m->libraries; - } else { - while (*s and *s != ',') ++ s; - if (*s) ++ s; - } - } - } - System::Library* last = t->m->libraries; for (System::Library* lib = t->m->libraries; lib; lib = lib->next()) { - if (lib->name() - and ::strcmp(lib->name(), name) == 0 - and lib->mapName() == mapName) - { + if (lib->name() and ::strcmp(lib->name(), name) == 0) { // already loaded return lib; } @@ -198,18 +176,91 @@ loadLibrary(Thread* t, const char* name, bool mapName, bool runOnLoad) } System::Library* lib; - if (LIKELY(t->m->system->success(t->m->system->load(&lib, name, mapName)))) { + if (LIKELY(t->m->system->success(t->m->system->load(&lib, name)))) { last->setNext(lib); + return lib; + } else { + return 0; + } +} + +System::Library* +loadLibrary(Thread* t, const char* path, const char* name, bool mapName, + bool runOnLoad) +{ + ACQUIRE(t, t->m->classLock); + + unsigned nameLength = strlen(name); + if (mapName) { + const char* builtins = findProperty(t, "avian.builtins"); + if (builtins) { + const char* s = builtins; + while (*s) { + if (::strncmp(s, name, nameLength) == 0 + and (s[nameLength] == ',' or s[nameLength] == 0)) + { + // library is built in to this executable + if (runOnLoad and not t->m->triedBuiltinOnLoad) { + t->m->triedBuiltinOnLoad = true; + runOnLoadIfFound(t, t->m->libraries); + } + return t->m->libraries; + } else { + while (*s and *s != ',') ++ s; + if (*s) ++ s; + } + } + } + + const char* prefix = t->m->system->libraryPrefix(); + const char* suffix = t->m->system->librarySuffix(); + unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix); + + char* mappedName = static_cast + (t->m->heap->allocate(mappedNameLength + 1)); + + snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix); + + name = mappedName; + nameLength = mappedNameLength; + } + + System::Library* lib = 0; + for (Tokenizer tokenizer(path, t->m->system->pathSeparator()); + tokenizer.hasMore();) + { + Tokenizer::Token token(tokenizer.next()); + + unsigned fullNameLength = token.length + 1 + nameLength; + RUNTIME_ARRAY(char, fullName, fullNameLength + 1); + + snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, + "%*s%c%s", token.length, token.s, t->m->system->fileSeparator(), + name); + + lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName)); + if (lib) break; + } + + if (lib == 0) { + lib = loadLibrary(t, name); + } + + if (lib) { if (runOnLoad) { runOnLoadIfFound(t, lib); } - return lib; - } else { + } else { object message = makeString(t, "library not found: %s", name); t->exception = t->m->classpath->makeThrowable (t, Machine::UnsatisfiedLinkErrorType, message); - return 0; } + + if (mapName) { + t->m->heap->free(name, nameLength + 1); + } + + return lib; } object diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c762209189..13eed26e33 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -139,9 +139,73 @@ makeClassNameString(Thread* t, object name) class MyClasspath : public Classpath { public: - MyClasspath(Allocator* allocator): + static const unsigned BufferSize = 256; + + MyClasspath(System* s, Allocator* allocator): allocator(allocator) - { } + { + const char* javaHome = getenv("JAVA_HOME"); + if (javaHome == 0) { + javaHome = AVIAN_OPENJDK_JAVA_HOME; + } + + class StringBuilder { + public: + StringBuilder(System* s, char* pointer, unsigned remaining): + s(s), pointer(pointer), remaining(remaining) + { } + + void append(const char* append) { + unsigned length = strlen(append); + assert(s, remaining > length); + + strncpy(pointer, append, remaining); + + remaining -= length; + pointer += length; + } + + void append(char c) { + assert(s, remaining > 1); + + pointer[0] = c; + pointer[1] = 0; + + -- remaining; + ++ pointer; + } + + System* s; + char* pointer; + unsigned remaining; + } sb(s, buffer, BufferSize); + + this->javaHome = sb.pointer; + sb.append(javaHome); + sb.append('\0'); + + this->classpath = sb.pointer; + sb.append(javaHome); + sb.append("/jre/lib/rt.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/jsse.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/jce.jar"); + sb.append(s->pathSeparator()); + sb.append(javaHome); + sb.append("/jre/lib/resources.jar"); + sb.append('\0'); + + this->libraryPath = sb.pointer; + sb.append(javaHome); +#ifdef ARCH_x86_64 + sb.append("/jre/lib/amd64"); +#else + sb.append("/jre/lib"); +#endif + } virtual object makeJclass(Thread* t, object class_) @@ -232,7 +296,7 @@ class MyClasspath : public Classpath { { globalMachine = t->m; - if (loadLibrary(t, "java", true, true) == 0) { + if (loadLibrary(t, libraryPath, "java", true, true) == 0) { abort(t); } @@ -271,6 +335,12 @@ class MyClasspath : public Classpath { fieldOffset(t, sclSet)) = true; } + virtual const char* + bootClasspath() + { + return classpath; + } + virtual void dispose() { @@ -278,6 +348,10 @@ class MyClasspath : public Classpath { } Allocator* allocator; + const char* javaHome; + const char* classpath; + const char* libraryPath; + char buffer[BufferSize]; }; struct JVM_ExceptionTableEntryType{ @@ -560,10 +634,10 @@ interruptLock(Thread* t, object thread) namespace vm { Classpath* -makeClasspath(System*, Allocator* allocator) +makeClasspath(System* s, Allocator* allocator) { return new (allocator->allocate(sizeof(local::MyClasspath))) - local::MyClasspath(allocator); + local::MyClasspath(s, allocator); } } // namespace vm @@ -1028,18 +1102,20 @@ JVM_InitProperties(Thread* t, jobject properties) local::setProperty(t, method, *properties, "os.name", "Linux"); # endif local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); - local::setProperty(t, method, *properties, "java.home", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); - - // todo: set this to something sane: - local::setProperty(t, method, *properties, "sun.boot.library.path", - getenv("LD_LIBRARY_PATH")); - local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); #endif + local::setProperty + (t, method, *properties, "java.home", + static_cast(t->m->classpath)->javaHome); + + local::setProperty + (t, method, *properties, "sun.boot.library.path", + static_cast(t->m->classpath)->libraryPath); + local::setProperty(t, method, *properties, "file.encoding", "ASCII"); #ifdef ARCH_x86_32 local::setProperty(t, method, *properties, "os.arch", "x86"); @@ -1132,7 +1208,9 @@ JVM_LoadLibrary(const char* name) ENTER(t, Thread::ActiveState); - return loadLibrary(t, name, false, false); + return loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, name, + false, false); } extern "C" JNIEXPORT void JNICALL diff --git a/src/finder.cpp b/src/finder.cpp index 7ad3245c7a..4e0fa64166 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -10,6 +10,7 @@ #include "zlib-custom.h" #include "system.h" +#include "tokenizer.h" #include "finder.h" using namespace vm; @@ -19,8 +20,7 @@ namespace { const bool DebugFind = false; const char* -append(System* s, const char* a, const char* b, - const char* c) +append(System* s, const char* a, const char* b, const char* c) { unsigned al = strlen(a); unsigned bl = strlen(b); @@ -148,6 +148,9 @@ class DirectoryElement: public Element { } return region; } else { + if (DebugFind) { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } return 0; } } @@ -493,8 +496,12 @@ class JarElement: public Element { while (*name == '/') name++; System::Region* r = (index ? index->find(name, region->start()) : 0); - if (DebugFind and r) { - fprintf(stderr, "found %s in %s\n", name, this->name); + if (DebugFind) { + if (r) { + fprintf(stderr, "found %s in %s\n", name, this->name); + } else { + fprintf(stderr, "%s not found in %s\n", name, this->name); + } } return r; } @@ -533,7 +540,7 @@ class BuiltinElement: public JarElement { virtual void init() { if (index == 0) { - if (s->success(s->load(&library, libraryName, false))) { + if (s->success(s->load(&library, libraryName))) { void* p = library->resolve(name); if (p) { uint8_t* (*function)(unsigned*); @@ -564,33 +571,6 @@ class BuiltinElement: public JarElement { Element* parsePath(System* s, const char* path, const char* bootLibrary) { - class Tokenizer { - public: - class Token { - public: - Token(const char* s, unsigned length): s(s), length(length) { } - - const char* s; - unsigned length; - }; - - Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } - - bool hasMore() { - while (*s == delimiter) ++s; - return *s; - } - - Token next() { - const char* p = s; - while (*s and *s != delimiter) ++s; - return Token(p, s - p); - } - - const char* s; - char delimiter; - }; - Element* first = 0; Element* prev = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index b09c0815c8..549bdc92f4 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2306,26 +2306,31 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) if (classpath == 0) classpath = "."; + System* s = makeSystem(crashDumpDirectory); + Heap* h = makeHeap(s, heapLimit); + Classpath* c = makeClasspath(s, h); + const char* classpathBootClasspath = c->bootClasspath(); + unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); + unsigned cbcpl = strlen(classpathBootClasspath); unsigned bcpal = strlen(bootClasspathAppend); - unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; + unsigned bootClasspathBufferSize = bcppl + bcpl + cbcpl + bcpal + 3; RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); - local::append - (&bootClasspathPointer, bootClasspathPrepend, bcppl, PATH_SEPARATOR); + local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl, + bcpl + cbcpl + bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspath, bcpl, + cbcpl + bcpal ? PATH_SEPARATOR : 0); + local::append(&bootClasspathPointer, classpathBootClasspath, cbcpl, bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); - System* s = makeSystem(crashDumpDirectory); - Heap* h = makeHeap(s, heapLimit); Finder* bf = makeFinder (s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); Finder* af = makeFinder(s, classpath, bootLibrary); Processor* p = makeProcessor(s, h, true); - Classpath* c = makeClasspath(s, h); const char** properties = static_cast (h->allocate(sizeof(const char*) * propertyCount)); diff --git a/src/machine.cpp b/src/machine.cpp index 0542a5c216..d23c5ee1dd 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2166,7 +2166,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, not system->success(system->make(&referenceLock)) or not system->success(system->make(&shutdownLock)) or not system->success - (system->load(&libraries, findProperty(this, "avian.bootstrap"), false))) + (system->load(&libraries, findProperty(this, "avian.bootstrap")))) { system->abort(); } diff --git a/src/machine.h b/src/machine.h index b7b154ffa2..17348e8e88 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1432,6 +1432,9 @@ class Classpath { virtual void boot(Thread* t) = 0; + virtual const char* + bootClasspath() = 0; + virtual void dispose() = 0; }; diff --git a/src/posix.cpp b/src/posix.cpp index 0a96f70f29..7507beb28e 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -469,13 +469,12 @@ class MySystem: public System { class Library: public System::Library { public: Library(System* s, void* p, const char* name, unsigned nameLength, - bool mapName, bool isMain): + bool isMain): s(s), p(p), mainExecutable(isMain), name_(name), nameLength(nameLength), - mapName_(mapName), next_(0) { } @@ -487,10 +486,6 @@ class MySystem: public System { return name_; } - virtual bool mapName() { - return mapName_; - } - virtual System::Library* next() { return next_; } @@ -504,7 +499,7 @@ class MySystem: public System { fprintf(stderr, "close %p\n", p); } - if (!mainExecutable) dlclose(p); + if (not mainExecutable) dlclose(p); if (next_) { next_->disposeAll(); @@ -522,7 +517,6 @@ class MySystem: public System { bool mainExecutable; const char* name_; unsigned nameLength; - bool mapName_; System::Library* next_; }; @@ -716,27 +710,23 @@ class MySystem: public System { } } + virtual const char* libraryPrefix() { + return "lib"; + } + + virtual const char* librarySuffix() { + return SO_SUFFIX; + } + virtual Status load(System::Library** lib, - const char* name, - bool mapName) + const char* name) { - void* p; - bool alreadyAllocated = false; - bool isMain = false; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName and name) { - unsigned size = nameLength + 3 + sizeof(SO_SUFFIX); - char buffer[size]; - vm::snprintf(buffer, size, "lib%s" SO_SUFFIX, name); - p = dlopen(buffer, RTLD_LAZY | RTLD_LOCAL); - } else { - if (!name) { - pathOfExecutable(this, &name, &nameLength); - alreadyAllocated = true; - isMain = true; - } - p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); + bool isMain = name == 0; + if (isMain) { + pathOfExecutable(this, &name, &nameLength); } + void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL); if (p) { if (Verbose) { @@ -747,7 +737,7 @@ class MySystem: public System { if (name) { n = static_cast(allocate(this, nameLength + 1)); memcpy(n, name, nameLength + 1); - if (alreadyAllocated) { + if (isMain) { free(name); } } else { @@ -755,11 +745,13 @@ class MySystem: public System { } *lib = new (allocate(this, sizeof(Library))) - Library(this, p, n, nameLength, mapName, isMain); + Library(this, p, n, nameLength, isMain); return 0; } else { - fprintf(stderr, "dlerror: %s\n", dlerror()); + if (Verbose) { + fprintf(stderr, "dlerror: %s\n", dlerror()); + } return 1; } } @@ -768,6 +760,10 @@ class MySystem: public System { return ':'; } + virtual char fileSeparator() { + return '/'; + } + virtual int64_t now() { timeval tv = { 0, 0 }; gettimeofday(&tv, 0); diff --git a/src/system.h b/src/system.h index a58d3bba73..1cdddb3afe 100644 --- a/src/system.h +++ b/src/system.h @@ -89,7 +89,6 @@ class System { public: virtual void* resolve(const char* symbol) = 0; virtual const char* name() = 0; - virtual bool mapName() = 0; virtual Library* next() = 0; virtual void setNext(Library* lib) = 0; virtual void disposeAll() = 0; @@ -135,8 +134,11 @@ class System { virtual Status map(Region**, const char* name) = 0; virtual FileType identify(const char* name) = 0; virtual Status open(Directory**, const char* name) = 0; - virtual Status load(Library**, const char* name, bool mapName) = 0; + virtual const char* libraryPrefix() = 0; + virtual const char* librarySuffix() = 0; + virtual Status load(Library**, const char* name) = 0; virtual char pathSeparator() = 0; + virtual char fileSeparator() = 0; virtual int64_t now() = 0; virtual void exit(int code) = 0; virtual void abort() = 0; diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000000..4036e7d197 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef TOKENIZER_H +#define TOKENIZER_H + +namespace vm { + +class Tokenizer { + public: + class Token { + public: + Token(const char* s, unsigned length): s(s), length(length) { } + + const char* s; + unsigned length; + }; + + Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } + + bool hasMore() { + while (*s == delimiter) ++s; + return *s != 0; + } + + Token next() { + const char* p = s; + while (*s and *s != delimiter) ++s; + return Token(p, s - p); + } + + const char* s; + char delimiter; +}; + +} // namespace + +#endif//TOKENIZER_H diff --git a/src/type-generator.cpp b/src/type-generator.cpp index bec29c7e69..b8d63a9572 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -12,9 +12,13 @@ #include "stdio.h" #include "stdint.h" #include "string.h" -#include "assert.h" +#include "errno.h" #include "constants.h" +#include "finder.h" +#include "stream.h" + +#include "assert.h" #define UNREACHABLE abort() @@ -28,6 +32,8 @@ using namespace vm; namespace { +namespace local { + #ifndef POINTER_SIZE # define POINTER_SIZE sizeof(void*) #endif @@ -177,7 +183,7 @@ class Output { void write(int i) { static const int Size = 32; char s[Size]; - int c UNUSED = snprintf(s, Size, "%d", i); + int c UNUSED = ::snprintf(s, Size, "%d", i); assert(c > 0 and c < Size); write(s); } @@ -213,63 +219,6 @@ class FileOutput : public Output { } }; -class Stream { - public: - Stream(FILE* stream, bool close): - stream(stream), close(close) - { - assert(stream); - } - - ~Stream() { - if (close) fclose(stream); - } - - void skip(unsigned size) { - fseek(stream, size, SEEK_CUR); - } - - void read(uint8_t* data, unsigned size) { - fread(data, 1, size, stream); - } - - uint8_t read1() { - uint8_t v; - read(&v, 1); - return v; - } - - uint16_t read2() { - uint16_t a = read1(); - uint16_t b = read1(); - return (a << 8) | b; - } - - uint32_t read4() { - uint32_t a = read2(); - uint32_t b = read2(); - return (a << 16) | b; - } - - uint64_t read8() { - uint64_t a = read4(); - uint64_t b = read4(); - return (a << 32) | b; - } - - uint32_t readFloat() { - return read4(); - } - - uint64_t readDouble() { - return read8(); - } - - private: - FILE* stream; - bool close; -}; - class Object { public: typedef enum { @@ -1384,8 +1333,8 @@ parseJavaClass(Object* type, Stream* s, Object* declarations) } Object* -parseType(Object::ObjectType type, Object* p, Object* declarations, - const char* javaClassDirectory) +parseType(Finder* finder, Object::ObjectType type, Object* p, + Object* declarations) { const char* name = string(car(p)); @@ -1400,9 +1349,16 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, bool isJavaType = javaName and *javaName != '['; if (isJavaType) { - const char* file = append(javaClassDirectory, "/", javaName, ".class"); - Stream s(fopen(file, "rb"), true); + class Client: public Stream::Client { + public: + virtual void NO_RETURN handleError() { + abort(); + } + } client; + System::Region* region = finder->find(append(javaName, ".class")); + Stream s(&client, region->start(), region->length()); parseJavaClass(t, &s, declarations); + region->dispose(); } for (p = cdr(p); p; p = cdr(p)) { @@ -1429,14 +1385,13 @@ parseType(Object::ObjectType type, Object* p, Object* declarations, } Object* -parseDeclaration(Object* p, Object* declarations, - const char* javaClassDirectory) +parseDeclaration(Finder* finder, Object* p, Object* declarations) { const char* spec = string(car(p)); if (equal(spec, "type")) { - return parseType(Object::Type, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Type, cdr(p), declarations); } else if (equal(spec, "pod")) { - return parseType(Object::Pod, cdr(p), declarations, javaClassDirectory); + return parseType(finder, Object::Pod, cdr(p), declarations); } else { fprintf(stderr, "unexpected declaration spec: %s\n", spec); abort(); @@ -1444,7 +1399,7 @@ parseDeclaration(Object* p, Object* declarations, } Object* -parse(Input* in, const char* javaClassDirectory) +parse(Finder* finder, Input* in) { Object* eos = Singleton::make(Object::Eos); List declarations; @@ -1452,7 +1407,7 @@ parse(Input* in, const char* javaClassDirectory) Object* o; while ((o = read(in, eos, 0)) != eos) { declarations.append - (parseDeclaration(o, declarations.first, javaClassDirectory)); + (parseDeclaration(finder, o, declarations.first)); } return declarations.first; @@ -1522,7 +1477,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) if (not unsafe) { out->write("const unsigned "); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); out->write(" = "); writeOffset(out, offset); @@ -1547,7 +1502,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) writeAccessorName(out, member, unsafe); if (memberOwner(member)->type == Object::Pod) { out->write("("); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("*"); } else { out->write("(Thread* t UNUSED, object"); @@ -1563,13 +1518,13 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write(" assert(t, t->m->unsafe or "); out->write("instanceOf(t, arrayBodyUnsafe"); out->write("(t, t->m->types, Machine::"); - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write("Type)"); out->write(", o));\n"); if (member->type != Object::Scalar) { out->write(" assert(t, i < "); - out->write(::typeName(memberOwner(member))); + out->write(local::typeName(memberOwner(member))); out->write("Length(t, o));\n"); } } @@ -1599,7 +1554,7 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false) out->write("["); } - out->write(capitalize(::typeName(memberOwner(member)))); + out->write(capitalize(local::typeName(memberOwner(member)))); out->write(capitalize(memberName(member))); if (member->type != Object::Scalar) { @@ -2221,62 +2176,83 @@ void usageAndExit(const char* command) { fprintf(stderr, - "usage: %s " + "usage: %s " "{enums,declarations,constructors,initializations," "java-initializations}\n", command); exit(-1); } +} // namespace local + } // namespace +extern "C" uint64_t +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); +} + +extern "C" void +vmJump(void*, void*, void*, void*, uintptr_t, uintptr_t) +{ + abort(); +} + int main(int ac, char** av) { - if ((ac != 2 and ac != 3) - or (ac == 3 - and not equal(av[2], "enums") - and not equal(av[2], "declarations") - and not equal(av[2], "constructors") - and not equal(av[2], "initializations") - and not equal(av[2], "java-initializations"))) + if (ac != 5 + or not (local::equal(av[4], "enums") + or local::equal(av[4], "declarations") + or local::equal(av[4], "constructors") + or local::equal(av[4], "initializations") + or local::equal(av[4], "java-initializations"))) { - usageAndExit(av[0]); + local::usageAndExit(av[0]); } - FileInput in(0, stdin, false); + System* system = makeSystem(0); + Finder* finder = makeFinder(system, av[1], 0); - Object* declarations = parse(&in, av[1]); - - FileOutput out(0, stdout, false); - - if (ac == 2 or equal(av[2], "enums")) { - writeEnums(&out, declarations); + FILE* inStream = ::fopen(av[2], "rb"); + if (inStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[2], strerror(errno)); + return -1; } + local::FileInput in(0, inStream, false); - if (ac == 2 or equal(av[2], "declarations")) { + local::Object* declarations = local::parse(finder, &in); + + finder->dispose(); + system->dispose(); + + FILE* outStream = ::fopen(av[3], "wb"); + if (outStream == 0) { + fprintf(stderr, "unable to open %s: %s\n", av[3], strerror(errno)); + return -1; + } + local::FileOutput out(0, outStream, false); + + if (local::equal(av[4], "enums")) { + local::writeEnums(&out, declarations); + } else if (local::equal(av[4], "declarations")) { out.write("const unsigned TypeCount = "); - out.Output::write(typeCount(declarations)); + out.Output::write(local::typeCount(declarations)); out.write(";\n\n"); - writePods(&out, declarations); - writeAccessors(&out, declarations); - writeSizes(&out, declarations); - writeInitializerDeclarations(&out, declarations); - writeConstructorDeclarations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "constructors")) { - writeInitializers(&out, declarations); - writeConstructors(&out, declarations); - } - - if (ac == 2 or equal(av[2], "initializations")) { - writeInitializations(&out, declarations); - } - - if (ac == 2 or equal(av[2], "java-initializations")) { - writeJavaInitializations(&out, declarations); + local::writePods(&out, declarations); + local::writeAccessors(&out, declarations); + local::writeSizes(&out, declarations); + local::writeInitializerDeclarations(&out, declarations); + local::writeConstructorDeclarations(&out, declarations); + } else if (local::equal(av[4], "constructors")) { + local::writeInitializers(&out, declarations); + local::writeConstructors(&out, declarations); + } else if (local::equal(av[4], "initializations")) { + local::writeInitializations(&out, declarations); + } else if (local::equal(av[4], "java-initializations")) { + local::writeJavaInitializations(&out, declarations); } return 0; From efd3ccb04f74fbd379bec6518bc3c9bbb6d2cf6b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Sep 2010 18:38:38 -0600 Subject: [PATCH 050/274] set java.home to path of JRE, not JDK --- makefile | 9 ++++----- src/classpath-avian.cpp | 2 +- src/classpath-openjdk.cpp | 27 +++++++++++---------------- src/jnienv.cpp | 8 +++++++- src/machine.h | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/makefile b/makefile index 2c48a069a5..162a40398c 100644 --- a/makefile +++ b/makefile @@ -51,8 +51,8 @@ test = test classpath = avian test-executable = $(executable) -generator-classpath = $(classpath-build) boot-classpath = $(classpath-build) +java-home = /tmp ifdef openjdk classpath = openjdk @@ -62,9 +62,8 @@ ifdef openjdk else openjdk-lib-dir = $(openjdk)/jre/lib endif - classpath-cflags = -DAVIAN_OPENJDK_JAVA_HOME=\"$(openjdk)\" + java-home = $(openjdk)/jre test-executable = $(executable-dynamic) - generator-classpath := $(generator-classpath):$(openjdk)/jre/lib/rt.jar boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar endif @@ -116,7 +115,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS $(classpath-cflags) + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(java-home)\" build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread @@ -515,7 +514,7 @@ gen-arg = $(shell echo $(1) | sed -e 's:$(build)/type-\(.*\)\.cpp:\1:') $(generated-code): %.cpp: $(src)/types.def $(generator) $(classpath-dep) @echo "generating $(@)" @mkdir -p $(dir $(@)) - $(generator) $(generator-classpath) $(<) $(@) $(call gen-arg,$(@)) + $(generator) $(boot-classpath) $(<) $(@) $(call gen-arg,$(@)) $(classpath-build)/%.class: $(classpath-src)/%.java @echo $(<) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index e3bbd602fe..750f40bc16 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -128,7 +128,7 @@ enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, namespace vm { Classpath* -makeClasspath(System*, Allocator* allocator) +makeClasspath(System*, Allocator* allocator, const char*) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(allocator); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 13eed26e33..a3b41bbab6 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -139,16 +139,11 @@ makeClassNameString(Thread* t, object name) class MyClasspath : public Classpath { public: - static const unsigned BufferSize = 256; + static const unsigned BufferSize = 1024; - MyClasspath(System* s, Allocator* allocator): + MyClasspath(System* s, Allocator* allocator, const char* javaHome): allocator(allocator) { - const char* javaHome = getenv("JAVA_HOME"); - if (javaHome == 0) { - javaHome = AVIAN_OPENJDK_JAVA_HOME; - } - class StringBuilder { public: StringBuilder(System* s, char* pointer, unsigned remaining): @@ -157,7 +152,7 @@ class MyClasspath : public Classpath { void append(const char* append) { unsigned length = strlen(append); - assert(s, remaining > length); + expect(s, remaining > length); strncpy(pointer, append, remaining); @@ -186,24 +181,24 @@ class MyClasspath : public Classpath { this->classpath = sb.pointer; sb.append(javaHome); - sb.append("/jre/lib/rt.jar"); + sb.append("/lib/rt.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); - sb.append("/jre/lib/jsse.jar"); + sb.append("/lib/jsse.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); - sb.append("/jre/lib/jce.jar"); + sb.append("/lib/jce.jar"); sb.append(s->pathSeparator()); sb.append(javaHome); - sb.append("/jre/lib/resources.jar"); + sb.append("/lib/resources.jar"); sb.append('\0'); this->libraryPath = sb.pointer; sb.append(javaHome); #ifdef ARCH_x86_64 - sb.append("/jre/lib/amd64"); + sb.append("/lib/amd64"); #else - sb.append("/jre/lib"); + sb.append("/lib"); #endif } @@ -634,10 +629,10 @@ interruptLock(Thread* t, object thread) namespace vm { Classpath* -makeClasspath(System* s, Allocator* allocator) +makeClasspath(System* s, Allocator* allocator, const char* javaHome) { return new (allocator->allocate(sizeof(local::MyClasspath))) - local::MyClasspath(s, allocator); + local::MyClasspath(s, allocator, javaHome); } } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 549bdc92f4..0b6ae9b1c1 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2238,6 +2238,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) #define BOOTSTRAP_PROPERTY "avian.bootstrap" #define CRASHDIR_PROPERTY "avian.crash.dir" #define CLASSPATH_PROPERTY "java.class.path" +#define JAVA_HOME_PROPERTY "java.home" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" #define BOOTCLASSPATH_OPTION "bootclasspath" #define BOOTCLASSPATH_APPEND_OPTION "bootclasspath/a" @@ -2257,6 +2258,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) unsigned heapLimit = 0; const char* bootLibrary = 0; const char* classpath = 0; + const char* javaHome = AVIAN_JAVA_HOME; const char* bootClasspathPrepend = ""; const char* bootClasspath = ""; const char* bootClasspathAppend = ""; @@ -2296,6 +2298,10 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) sizeof(CLASSPATH_PROPERTY)) == 0) { classpath = p + sizeof(CLASSPATH_PROPERTY); + } else if (strncmp(p, JAVA_HOME_PROPERTY "=", + sizeof(JAVA_HOME_PROPERTY)) == 0) + { + javaHome = p + sizeof(JAVA_HOME_PROPERTY); } ++ propertyCount; @@ -2308,7 +2314,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); - Classpath* c = makeClasspath(s, h); + Classpath* c = makeClasspath(s, h, javaHome); const char* classpathBootClasspath = c->bootClasspath(); unsigned bcppl = strlen(bootClasspathPrepend); diff --git a/src/machine.h b/src/machine.h index 17348e8e88..4030458089 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1446,7 +1446,7 @@ runJavaThread(Thread* t) } Classpath* -makeClasspath(System* system, Allocator* allocator); +makeClasspath(System* system, Allocator* allocator, const char* javaHome); typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); From 89f6adc93c01144f8518528bc9a6efb93aed99fc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 22 Sep 2010 13:58:46 -0600 Subject: [PATCH 051/274] fix various classloading deadlocks and races --- src/builtin.cpp | 3 +- src/classpath-common.h | 2 +- src/classpath-openjdk.cpp | 1 + src/compile.cpp | 25 +++++++- src/machine.cpp | 118 +++++++++++++++++++------------------- src/machine.h | 26 +-------- src/types.def | 3 +- 7 files changed, 90 insertions(+), 88 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index f3ad3c6ec5..f113bd5ead 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -85,7 +85,8 @@ Avian_avian_SystemClassLoader_resourceExists RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - bool r = getFinder(t, loader)->exists(RUNTIME_ARRAY_BODY(n)); + bool r = static_cast(systemClassLoaderFinder(t, loader))->exists + (RUNTIME_ARRAY_BODY(n)); // fprintf(stderr, "resource %s exists? %d\n", n, r); diff --git a/src/classpath-common.h b/src/classpath-common.h index 3c65301de4..29d90753bb 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -176,7 +176,7 @@ loadLibrary(Thread* t, const char* name) } System::Library* lib; - if (LIKELY(t->m->system->success(t->m->system->load(&lib, name)))) { + if (t->m->system->success(t->m->system->load(&lib, name))) { last->setNext(lib); return lib; } else { diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index a3b41bbab6..b8b7256bdd 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1602,6 +1602,7 @@ JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) ENTER(t, Thread::ActiveState); object spec = makeByteArray(t, stringLength(t, *name) + 1); + { char* s = reinterpret_cast(&byteArrayBody(t, spec, 0)); stringChars(t, *name, s); replace('.', '/', s); diff --git a/src/compile.cpp b/src/compile.cpp index e0f1bbe00c..97e3767ec9 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8226,8 +8226,8 @@ boot(MyThread* t, BootImage* image) syncInstructionCache(code, image->codeSize); - setRoot(t, Machine::ClassMap, makeClassMap - (t, bootClassTable, image->bootClassCount, heap)); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, makeClassMap + (t, bootClassTable, image->bootClassCount, heap)); set(t, root(t, Machine::AppLoader), ClassLoaderMap, makeClassMap (t, appClassTable, image->appClassCount, heap)); @@ -8249,7 +8249,8 @@ boot(MyThread* t, BootImage* image) fixupVirtualThunks(t, image, code); - fixupMethods(t, root(t, Machine::ClassMap), image, code); + fixupMethods + (t, classLoaderMap(t, root(t, Machine::BootLoader)), image, code); fixupMethods(t, classLoaderMap(t, root(t, Machine::AppLoader)), image, code); setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); @@ -8657,6 +8658,24 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, compile(t, &context); if (UNLIKELY(t->exception)) return; + { object ehTable = codeExceptionHandlerTable(t, methodCode(t, clone)); + + if (ehTable) { + PROTECT(t, ehTable); + + // resolve all exception handler catch types before we acquire + // the class lock: + for (unsigned i = 0; i < exceptionHandlerTableLength(t, ehTable); ++i) { + ExceptionHandler* handler = exceptionHandlerTableBody(t, ehTable, i); + if (exceptionHandlerCatchType(handler)) { + resolveClassInPool + (t, clone, exceptionHandlerCatchType(handler) - 1); + if (UNLIKELY(t->exception)) return; + } + } + } + } + ACQUIRE(t, t->m->classLock); if (methodAddress(t, method) != defaultThunk(t)) { diff --git a/src/machine.cpp b/src/machine.cpp index d23c5ee1dd..df9cf6c510 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1785,15 +1785,15 @@ makeArrayClass(Thread* t, object loader, object spec, bool throw_) object elementClass = hashMapFind (t, root(t, Machine::BootstrapClassMap), elementSpec, byteArrayHash, byteArrayEqual); - + if (elementClass == 0) { elementClass = resolveClass(t, loader, elementSpec, throw_); if (elementClass == 0) return 0; } - object class_ = hashMapFind - (t, getClassLoaderMap(t, classLoader(t, elementClass)), spec, - byteArrayHash, byteArrayEqual); + PROTECT(t, elementClass); + + object class_ = findLoadedClass(t, classLoader(t, elementClass), spec); return class_ ? class_ : makeArrayClass (t, classLoader(t, elementClass), dimensions, spec, elementClass); @@ -2002,12 +2002,18 @@ boot(Thread* t) set(t, type(t, Machine::DoubleArrayType), ClassStaticTable, type(t, Machine::JdoubleType)); - setRoot(t, Machine::ClassMap, makeHashMap(t, 0, 0)); + { object map = makeHashMap(t, 0, 0); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); + } + + systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = m->bootFinder; { object map = makeHashMap(t, 0, 0); set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); } + systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = m->appFinder; + set(t, root(t, Machine::AppLoader), ClassLoaderParent, root(t, Machine::BootLoader)); @@ -3127,7 +3133,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) ACQUIRE(t, t->m->classLock); object class_ = hashMapFind - (t, getClassLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); if (class_ == 0) { if (classLoaderParent(t, loader)) { @@ -3149,7 +3155,8 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) ".class", 7); - System::Region* region = getFinder(t, loader)->find + System::Region* region = static_cast + (systemClassLoaderFinder(t, loader))->find (RUNTIME_ARRAY_BODY(file)); if (region) { @@ -3185,8 +3192,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) if (class_) { PROTECT(t, class_); - hashMapInsert - (t, getClassLoaderMap(t, loader), spec, class_, byteArrayHash); + hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_ and t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); t->exception = t->m->classpath->makeThrowable @@ -3200,48 +3206,34 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) object findLoadedClass(Thread* t, object loader, object spec) { + PROTECT(t, loader); PROTECT(t, spec); + ACQUIRE(t, t->m->classLock); - object map = getClassLoaderMap(t, loader); - if (map) { - return hashMapFind(t, map, spec, byteArrayHash, byteArrayEqual); - } else { - return 0; - } + return classLoaderMap(t, loader) ? hashMapFind + (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual) : 0; } object resolveClass(Thread* t, object loader, object spec, bool throw_) { - if (loader == root(t, Machine::BootLoader) - or loader == root(t, Machine::AppLoader)) - { + if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) { return resolveSystemClass(t, loader, spec, throw_); } else { expect(t, throw_); - PROTECT(t, loader); - PROTECT(t, spec); - - { ACQUIRE(t, t->m->classLock); - - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - object class_ = hashMapFind - (t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual); - - if (class_) { - return class_; + { object c = findLoadedClass(t, loader, spec); + if (c) { + return c; } } - object class_; + PROTECT(t, loader); + PROTECT(t, spec); + if (byteArrayBody(t, spec, 0) == '[') { - class_ = resolveArrayClass(t, loader, spec, throw_); + return resolveArrayClass(t, loader, spec, throw_); } else { if (root(t, Machine::LoadClassMethod) == 0) { object m = resolveMethod @@ -3272,31 +3264,38 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast (&byteArrayBody(t, spec, 0))); - object specString = makeString(t, "%s", s); + object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - class_ = t->m->processor->invoke(t, method, loader, specString); + object c = t->m->processor->invoke(t, method, loader, specString); - if (LIKELY(class_ and t->exception == 0)) { - class_ = jclassVmClass(t, class_); + if (LIKELY(c and t->exception == 0)) { + PROTECT(t, c); + + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + c = jclassVmClass(t, c); + + hashMapInsert + (t, classLoaderMap(t, loader), spec, c, byteArrayHash); + + return c; } } } + + if (t->exception == 0) { + object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); + t->exception = t->m->classpath->makeThrowable + (t, Machine::ClassNotFoundExceptionType, message); + } + + return 0; } - - if (class_) { - PROTECT(t, class_); - - ACQUIRE(t, t->m->classLock); - - hashMapInsert(t, classLoaderMap(t, loader), spec, class_, - byteArrayHash); - } else if (throw_ and t->exception == 0) { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = t->m->classpath->makeThrowable - (t, Machine::ClassNotFoundExceptionType, message); - } - - return class_; } } @@ -3411,6 +3410,7 @@ preInitClass(Thread* t, object c) if (classVmFlags(t, c) & NeedInitFlag) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); + if (classVmFlags(t, c) & NeedInitFlag) { if (classVmFlags(t, c) & InitFlag) { // If the class is currently being initialized and this the thread @@ -3444,8 +3444,8 @@ void postInitClass(Thread* t, object c) { PROTECT(t, c); - ACQUIRE(t, t->m->classLock); + if (t->exception) { t->exception = t->m->classpath->makeThrowable (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); @@ -3960,13 +3960,15 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) if (c) { PROTECT(t, c); - if (getClassLoaderMap(t, loader) == 0) { + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { object map = makeHashMap(t, 0, 0); set(t, loader, ClassLoaderMap, map); } - hashMapInsert(t, getClassLoaderMap(t, loader), className(t, c), c, - byteArrayHash); + hashMapInsert + (t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash); } return c; diff --git a/src/machine.h b/src/machine.h index 4030458089..7263994b1d 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1188,9 +1188,9 @@ class Machine { enum Root { BootLoader, AppLoader, - ClassMap, - LoadClassMethod, BootstrapClassMap, + FindLoadedClassMethod, + LoadClassMethod, MonitorMap, StringMap, ByteArrayMap, @@ -1777,28 +1777,6 @@ setType(Thread* t, Machine::Type type, object value) set(t, t->m->types, ArrayBody + (type * BytesPerWord), value); } -inline object -getClassLoaderMap(Thread* t, object loader) -{ - if (loader == root(t, Machine::BootLoader)) { - return root(t, Machine::ClassMap); - } else { - return classLoaderMap(t, loader); - } -} - -inline Finder* -getFinder(Thread* t, object loader) -{ - if (loader == root(t, Machine::BootLoader)) { - return t->m->bootFinder; - } else if (loader == root(t, Machine::AppLoader)) { - return t->m->appFinder; - } else { - abort(t); - } -} - inline bool objectFixed(Thread*, object o) { diff --git a/src/types.def b/src/types.def index 854798c84e..996b99e377 100644 --- a/src/types.def +++ b/src/types.def @@ -22,7 +22,8 @@ (type classLoader java/lang/ClassLoader (object map)) -(type systemClassLoader avian/SystemClassLoader) +(type systemClassLoader avian/SystemClassLoader + (void* finder)) (type field avian/VMField) From b023d147df67caef010120f008de7ce1ae4c2cc0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 23 Sep 2010 08:49:36 -0600 Subject: [PATCH 052/274] fix JVM_Available for when fd is a fifo or socket --- src/classpath-openjdk.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index b8b7256bdd..a241aa1644 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -41,6 +41,7 @@ # include # include # include +# include # include # include # include @@ -49,6 +50,7 @@ # define CLOSE close # define READ read # define WRITE write +# define FSTAT fstat # define LSEEK lseek #endif // not PLATFORM_WINDOWS @@ -2372,6 +2374,18 @@ JVM_Write(jint fd, char* src, jint length) extern "C" JNIEXPORT jint JNICALL JVM_Available(jint fd, jlong* result) { + struct stat buffer; + int n; + if (FSTAT(fd, &buffer) >= 0 + and (S_ISCHR(buffer.st_mode) + or S_ISFIFO(buffer.st_mode) + or S_ISSOCK(buffer.st_mode)) + and ioctl(fd, FIONREAD, &n) >= 0) + { + *result = n; + return 1; + } + int current = LSEEK(fd, 0, SEEK_CUR); if (current == -1) return 0; From ebc54c234f870eadb7fb63f36225878afec99166 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 23 Sep 2010 08:50:09 -0600 Subject: [PATCH 053/274] fix signedness error for wide iinc implementation --- src/compile.cpp | 2 +- test/Integers.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 97e3767ec9..fbc9450165 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -4953,7 +4953,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case iinc: { uint16_t index = codeReadInt16(t, code, ip); - uint16_t count = codeReadInt16(t, code, ip); + int16_t count = codeReadInt16(t, code, ip); storeLocal (context, 1, diff --git a/test/Integers.java b/test/Integers.java index 80e1a0e3a5..c88803b518 100644 --- a/test/Integers.java +++ b/test/Integers.java @@ -21,6 +21,11 @@ public class Integers { } public static void main(String[] args) { + { int foo = 1028; + foo -= 1023; + expect(foo == 5); + } + expect(gcd(12, 4) == 4); { int a = 2; From e75b57a1272fdbd3b99c1f3bad38b03c8d37519c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Sep 2010 15:48:15 -0600 Subject: [PATCH 054/274] don't abort when compiling an array lookup with a constant negative index Instead, just compile it as a direct call to the thunk which throws an ArrayIndexOutOfBoundsException. --- src/compiler.cpp | 40 +++++++++++++++++++++++----------------- test/Arrays.java | 11 +++++++++++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 44217336a2..5e8c447b7e 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4865,12 +4865,13 @@ class BoundsCheckEvent: public Event { Assembler* a = c->assembler; ConstantSite* constant = findConstantSite(c, index); - CodePromise* nextPromise = codePromise - (c, static_cast(0)); CodePromise* outOfBoundsPromise = 0; if (constant) { - expect(c, constant->value->value() >= 0); + if (constant->value->value() < 0) { + Assembler::Constant handlerConstant(resolved(c, handler)); + a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); + } } else { outOfBoundsPromise = codePromise(c, static_cast(0)); @@ -4880,24 +4881,29 @@ class BoundsCheckEvent: public Event { BytesPerWord, &oob, &oob); } - assert(c, object->source->type(c) == RegisterOperand); - MemorySite length(static_cast(object->source)->number, - lengthOffset, NoRegister, 1); - length.acquired = true; + if (constant == 0 or constant->value->value() >= 0) { + assert(c, object->source->type(c) == RegisterOperand); + MemorySite length(static_cast(object->source)->number, + lengthOffset, NoRegister, 1); + length.acquired = true; - ConstantSite next(nextPromise); - apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, - &length, BytesPerWord, &next, &next); + CodePromise* nextPromise = codePromise + (c, static_cast(0)); - if (constant == 0) { - outOfBoundsPromise->offset = a->offset(); + ConstantSite next(nextPromise); + apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, + &length, BytesPerWord, &next, &next); + + if (constant == 0) { + outOfBoundsPromise->offset = a->offset(); + } + + Assembler::Constant handlerConstant(resolved(c, handler)); + a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); + + nextPromise->offset = a->offset(); } - Assembler::Constant handlerConstant(resolved(c, handler)); - a->apply(Call, BytesPerWord, ConstantOperand, &handlerConstant); - - nextPromise->offset = a->offset(); - popRead(c, this, object); popRead(c, this, index); } diff --git a/test/Arrays.java b/test/Arrays.java index 2dd2bcfc30..52c519ba69 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -15,6 +15,17 @@ public class Arrays { expect(exception != null); } + { int[] array = new int[0]; + Exception exception = null; + try { + int x = array[-1]; + } catch (ArrayIndexOutOfBoundsException e) { + exception = e; + } + + expect(exception != null); + } + { int[] array = new int[3]; int i = 0; array[i++] = 1; From c939d1668718f09e199eff697012df48a1339ed9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Sep 2010 15:51:30 -0600 Subject: [PATCH 055/274] formatting tweak in Classes.java --- classpath/avian/Classes.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/classpath/avian/Classes.java b/classpath/avian/Classes.java index c73c00931d..3e18f4c0df 100644 --- a/classpath/avian/Classes.java +++ b/classpath/avian/Classes.java @@ -112,7 +112,8 @@ public class Classes { case 'c':{ byte[] name = (byte[]) Singleton.getObject(pool, read2(in) - 1); - return SystemClassLoader.getClass(loadVMClass(loader, name, 1, name.length - 3)); + return SystemClassLoader.getClass + (loadVMClass(loader, name, 1, name.length - 3)); } case '@': From a2cc95d19619952d24bca9e436e48382e5559ab3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Sep 2010 15:52:43 -0600 Subject: [PATCH 056/274] remove trailing whitespace in compile.cpp --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index fbc9450165..7c0971c781 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2601,7 +2601,7 @@ traceSize(Thread* t) void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { - if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { + if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); t->exception = t->m->classpath->makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType); From 268d2de1754a833e6287a67a73466be4d21929a8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Sep 2010 15:54:01 -0600 Subject: [PATCH 057/274] cache array class lookups in element class; misc. bugfixes --- classpath/avian/ClassAddendum.java | 1 + src/classpath-common.h | 30 -------- src/jnienv.cpp | 6 +- src/machine.cpp | 118 +++++++++++++++++++++-------- src/machine.h | 11 +-- 5 files changed, 98 insertions(+), 68 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index c20079df6b..ce13dbe35a 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -13,4 +13,5 @@ package avian; public class ClassAddendum extends Addendum { public volatile Class class_; public Object[] signers; + public volatile Class arrayClass; } diff --git a/src/classpath-common.h b/src/classpath-common.h index 29d90753bb..8567b1ae77 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -15,36 +15,6 @@ namespace vm { -object -getCaller(Thread* t, unsigned target) -{ - class Visitor: public Processor::StackVisitor { - public: - Visitor(Thread* t, unsigned target): - t(t), method(0), count(0), target(target) - { } - - virtual bool visit(Processor::StackWalker* walker) { - if (count == target) { - method = walker->method(); - return false; - } else { - ++ count; - return true; - } - } - - Thread* t; - object method; - unsigned count; - unsigned target; - } v(t, target); - - t->m->processor->walkStack(t, &v); - - return v.method; -} - object getTrace(Thread* t, unsigned skipCount) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 0b6ae9b1c1..0c4a7070da 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -304,7 +304,11 @@ FindClass(Thread* t, const char* name) object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); - object c = resolveClass(t, root(t, Machine::AppLoader), n); + object caller = getCaller(t, 0); + + object c = resolveClass + (t, caller ? classLoader(t, methodClass(t, caller)) + : root(t, Machine::AppLoader), n); return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); } diff --git a/src/machine.cpp b/src/machine.cpp index df9cf6c510..9640760fa2 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -960,8 +960,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) unsigned i = 0; for (HashMapIterator it(t, map); it.hasMore();) { - object interface = resolveClass - (t, classLoader(t, class_), tripleFirst(t, it.next())); + object interface = tripleSecond(t, it.next()); if (UNLIKELY(t->exception)) return; set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface); @@ -1630,7 +1629,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body, 0, 0); + object addendum = makeClassAddendum(t, pool, body, 0, 0, 0); set(t, class_, ClassAddendum, addendum); } else { @@ -1816,6 +1815,58 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) } } +object +resolveObjectArrayClass(Thread* t, object loader, object elementClass) +{ + object addendum = classAddendum(t, elementClass); + if (addendum) { + object arrayClass = classAddendumArrayClass(t, addendum); + if (arrayClass) { + return arrayClass; + } + } else { + PROTECT(t, loader); + PROTECT(t, elementClass); + + ACQUIRE(t, t->m->classLock); + + object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); + + set(t, elementClass, ClassAddendum, addendum); + } + + PROTECT(t, loader); + PROTECT(t, elementClass); + + object elementSpec = className(t, elementClass); + PROTECT(t, elementSpec); + + object spec; + if (byteArrayBody(t, elementSpec, 0) == '[') { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); + byteArrayBody(t, spec, 0) = '['; + memcpy(&byteArrayBody(t, spec, 1), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec)); + } else { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); + byteArrayBody(t, spec, 0) = '['; + byteArrayBody(t, spec, 1) = 'L'; + memcpy(&byteArrayBody(t, spec, 2), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec) - 1); + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; + } + + object arrayClass = resolveClass(t, loader, spec); + + set(t, classAddendum(t, elementClass), ClassAddendumArrayClass, + arrayClass); + + return arrayClass; +} + void removeMonitor(Thread* t, object o) { @@ -2301,7 +2352,7 @@ Thread::init() if (exception == 0) { setRoot(this, Machine::ArrayIndexOutOfBoundsException, m->classpath->makeThrowable - (this, Machine::IndexOutOfBoundsExceptionType)); + (this, Machine::ArrayIndexOutOfBoundsExceptionType)); } } @@ -3356,33 +3407,6 @@ resolveField(Thread* t, object class_, const char* fieldName, } } -object -resolveObjectArrayClass(Thread* t, object loader, object elementSpec) -{ - PROTECT(t, loader); - PROTECT(t, elementSpec); - - object spec; - if (byteArrayBody(t, elementSpec, 0) == '[') { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); - byteArrayBody(t, spec, 0) = '['; - memcpy(&byteArrayBody(t, spec, 1), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec)); - } else { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); - byteArrayBody(t, spec, 0) = '['; - byteArrayBody(t, spec, 1) = 'L'; - memcpy(&byteArrayBody(t, spec, 2), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec) - 1); - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; - } - - return resolveClass(t, loader, spec); -} - bool classNeedsInit(Thread* t, object c) { @@ -3476,7 +3500,7 @@ object makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass - (t, classLoader(t, elementClass), className(t, elementClass)); + (t, classLoader(t, elementClass), elementClass); PROTECT(t, arrayClass); object array = makeArray(t, count); @@ -3951,6 +3975,36 @@ parseUtf8(Thread* t, const char* data, unsigned length) return ::parseUtf8(t, s, length); } +object +getCaller(Thread* t, unsigned target) +{ + class Visitor: public Processor::StackVisitor { + public: + Visitor(Thread* t, unsigned target): + t(t), method(0), count(0), target(target) + { } + + virtual bool visit(Processor::StackWalker* walker) { + if (count == target) { + method = walker->method(); + return false; + } else { + ++ count; + return true; + } + } + + Thread* t; + object method; + unsigned count; + unsigned target; + } v(t, target); + + t->m->processor->walkStack(t, &v); + + return v.method; +} + object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length) { diff --git a/src/machine.h b/src/machine.h index 7263994b1d..772bcd864c 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2178,9 +2178,6 @@ resolveField(Thread* t, object loader, const char* className, } } -object -resolveObjectArrayClass(Thread* t, object loader, object elementSpec); - bool classNeedsInit(Thread* t, object c); @@ -2992,7 +2989,7 @@ getJClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); - object addendum = makeClassAddendum(t, 0, 0, 0, 0); + object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); set(t, c, ClassAddendum, addendum); } @@ -3048,7 +3045,8 @@ registerNative(Thread* t, object method, void* function) } inline void -unregisterNatives(Thread* t, object c) { +unregisterNatives(Thread* t, object c) +{ if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); @@ -3059,6 +3057,9 @@ unregisterNatives(Thread* t, object c) { } } +object +getCaller(Thread* t, unsigned target); + object defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); From 1d4b54a9f6607f9f193f2fa2ded6de062228536c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Sep 2010 16:35:18 -0600 Subject: [PATCH 058/274] fix failure to add abstract virtuals to class with no declared virtuals --- src/machine.cpp | 1 + test/Misc.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/machine.cpp b/src/machine.cpp index 9640760fa2..4c7d26a21a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1494,6 +1494,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool) bool populateInterfaceVtables = false; if (declaredVirtualCount == 0 + and abstractVirtuals == 0 and (classFlags(t, class_) & ACC_INTERFACE) == 0) { if (classSuper(t, class_)) { diff --git a/test/Misc.java b/test/Misc.java index 5542ce5cfd..2bdc3396ca 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -1,4 +1,16 @@ public class Misc { + private interface Bar { + public int baz(); + } + + private static abstract class Bim implements Bar { } + + private static class Baz extends Bim { + public int baz() { + return 42; + } + } + private static int alpha; private static int beta; private static byte byte1, byte2, byte3; @@ -93,6 +105,9 @@ public class Misc { } public static void main(String[] args) { + Bim bim = new Baz(); + expect(bim.baz() == 42); + expect(queryDefault(new Object()) != null); { Foo foo = new Foo(); From 8c789fb92c45c5a9a5620037f999607664096d02 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 27 Sep 2010 09:39:44 -0600 Subject: [PATCH 059/274] return empty object array from MyProcessor::getStackTrace on failure --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 7c0971c781..f5ec9015f3 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7637,7 +7637,7 @@ class MyProcessor: public Processor { collect(t, Heap::MinorCollection); } - return visitor.trace ? visitor.trace : makeArray(t, 0); + return visitor.trace ? visitor.trace : makeObjectArray(t, 0); } virtual void initialize(BootImage* image, uint8_t* code, unsigned capacity) { From c1c9d2111bc0cf7c8287e3785c9ea042d0ed60f9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 27 Sep 2010 15:58:02 -0600 Subject: [PATCH 060/274] remove GNU Classpath and Apache Harmony compatibility code Rather than try to support mixing Avian's core classes with those of an external class library -- which necessitates adding a lot of stub methods which throw UnsupportedOperationExceptions, among other comprimises -- we're looking to support such external class libraries in their unmodified forms. The latter strategy has already proven successful with OpenJDK's class library. Thus, this commit removes the stub methods, etc., which not only cleans up the code but avoids misleading application developers as to what classes and methods Avian's built-in class library supports. --- classpath/java/lang/Class.java | 30 +----------- classpath/java/lang/String.java | 38 +-------------- classpath/java/lang/Thread.java | 23 +-------- classpath/java/lang/ThreadGroup.java | 2 +- classpath/java/lang/reflect/Constructor.java | 20 +------- classpath/java/lang/reflect/Field.java | 4 -- .../java/lang/reflect/GenericDeclaration.java | 15 ------ classpath/java/lang/reflect/Member.java | 2 - classpath/java/lang/reflect/Method.java | 28 +---------- classpath/java/lang/reflect/TypeVariable.java | 19 -------- classpath/java/util/Formatter.java | 23 --------- classpath/java/util/regex/Matcher.java | 48 ------------------- classpath/java/util/regex/Pattern.java | 4 -- readme.txt | 30 ------------ src/jnienv.cpp | 19 -------- 15 files changed, 7 insertions(+), 298 deletions(-) delete mode 100644 classpath/java/lang/reflect/GenericDeclaration.java delete mode 100644 classpath/java/lang/reflect/TypeVariable.java delete mode 100644 classpath/java/util/Formatter.java diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 65021739fb..15e4053175 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -21,11 +21,9 @@ import java.lang.reflect.Method; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.GenericDeclaration; import java.lang.reflect.AnnotatedElement; import java.lang.annotation.Annotation; import java.io.InputStream; @@ -37,9 +35,7 @@ import java.security.ProtectionDomain; import java.security.Permissions; import java.security.AllPermission; -public final class Class - implements Type, GenericDeclaration, AnnotatedElement -{ +public final class Class implements Type, AnnotatedElement { private static final int PrimitiveFlag = 1 << 5; public final VMClass vmClass; @@ -667,30 +663,6 @@ public final class Class return array; } - public boolean isEnum() { - throw new UnsupportedOperationException(); - } - - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } - - public Method getEnclosingMethod() { - throw new UnsupportedOperationException(); - } - - public Constructor getEnclosingConstructor() { - throw new UnsupportedOperationException(); - } - - public Class getEnclosingClass() { - throw new UnsupportedOperationException(); - } - - public Class[] getDeclaredClasses() { - throw new UnsupportedOperationException(); - } - public ProtectionDomain getProtectionDomain() { Permissions p = new Permissions(); p.add(new AllPermission()); diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 143c60fd72..0dd019d09f 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -13,7 +13,6 @@ package java.lang; import java.io.UnsupportedEncodingException; import java.util.regex.Pattern; import java.util.Comparator; -import java.util.Formatter; import java.util.Locale; import java.io.Serializable; import avian.Utf8; @@ -507,9 +506,7 @@ public final class String } public static String valueOf(int v) { - // use Integer.toString(int, int), because GNU Classpath's - // Integer.toString(int) just calls String.valueOf(int): - return Integer.toString(v, 10); + return Integer.toString(v); } public static String valueOf(long v) { @@ -575,37 +572,4 @@ public final class String public int codePointCount(int start, int end) { return Character.codePointCount(this, start, end); } - - public String replace(CharSequence match, CharSequence replacement) { - throw new UnsupportedOperationException(); - } - - public String toUpperCase(Locale locale) { - throw new UnsupportedOperationException(); - } - - public String toLowerCase(Locale locale) { - throw new UnsupportedOperationException(); - } - - public static String format(Locale locale, String format, Object ... args) { - return new Formatter(locale).format(format, args).toString(); - } - - public static String format(String format, Object ... args) { - return format(Locale.getDefault(), format, args); - } - - // for GNU Classpath compatibility: - static char[] zeroBasedStringValue(String s) { - if (s.offset == 0) { - if (s.data instanceof char[]) { - char[] data = (char[]) s.data; - if (data.length == s.length) { - return data; - } - } - } - return s.toCharArray(); - } } diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 64d0eab00a..3633921866 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -24,11 +24,8 @@ public class Thread implements Runnable { private Object sleepLock; private ClassLoader classLoader; private UncaughtExceptionHandler exceptionHandler; - - // package private for GNU Classpath, which inexplicably bypasses - // the accessor methods: - String name; - ThreadGroup group; + private String name; + private ThreadGroup group; private static UncaughtExceptionHandler defaultExceptionHandler; @@ -287,22 +284,6 @@ public class Thread implements Runnable { return peer; } - public void stop() { - throw new UnsupportedOperationException(); - } - - public void stop(Throwable t) { - throw new UnsupportedOperationException(); - } - - public void suspend() { - throw new UnsupportedOperationException(); - } - - public void resume() { - throw new UnsupportedOperationException(); - } - public interface UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e); } diff --git a/classpath/java/lang/ThreadGroup.java b/classpath/java/lang/ThreadGroup.java index 5145f0e865..95ad3383b1 100644 --- a/classpath/java/lang/ThreadGroup.java +++ b/classpath/java/lang/ThreadGroup.java @@ -13,7 +13,7 @@ package java.lang; import avian.Cell; public class ThreadGroup implements Thread.UncaughtExceptionHandler { - final ThreadGroup parent; // package private for GNU Classpath compatibility + private final ThreadGroup parent; private final String name; private Cell subgroups; diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index 324797fe9a..7c52df5955 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -12,9 +12,7 @@ package java.lang.reflect; import java.lang.annotation.Annotation; -public class Constructor extends AccessibleObject - implements Member, GenericDeclaration -{ +public class Constructor extends AccessibleObject implements Member { private Method method; public Constructor(Method method) { @@ -42,10 +40,6 @@ public class Constructor extends AccessibleObject return method.getParameterTypes(); } - public Class[] getExceptionTypes() { - return method.getExceptionTypes(); - } - public int getModifiers() { return method.getModifiers(); } @@ -54,10 +48,6 @@ public class Constructor extends AccessibleObject return method.getName(); } - public boolean isSynthetic() { - return method.isSynthetic(); - } - public T getAnnotation(Class class_) { return method.getAnnotation(class_); } @@ -70,14 +60,6 @@ public class Constructor extends AccessibleObject return method.getDeclaredAnnotations(); } - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } - - public Type[] getGenericParameterTypes() { - return method.getGenericParameterTypes(); - } - private static native Object make(avian.VMClass c); public T newInstance(Object ... arguments) diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 23fe3bf40f..038ccea54b 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -254,10 +254,6 @@ public class Field extends AccessibleObject { return getAnnotations(); } - public boolean isEnumConstant() { - throw new UnsupportedOperationException(); - } - private static native long getPrimitive (Object instance, int code, int offset); diff --git a/classpath/java/lang/reflect/GenericDeclaration.java b/classpath/java/lang/reflect/GenericDeclaration.java deleted file mode 100644 index 61914661bb..0000000000 --- a/classpath/java/lang/reflect/GenericDeclaration.java +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (c) 2009, 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.reflect; - -public interface GenericDeclaration { - public TypeVariable[] getTypeParameters(); -} diff --git a/classpath/java/lang/reflect/Member.java b/classpath/java/lang/reflect/Member.java index cfe00749bb..e5e74042c6 100644 --- a/classpath/java/lang/reflect/Member.java +++ b/classpath/java/lang/reflect/Member.java @@ -19,6 +19,4 @@ public interface Member { public int getModifiers(); public String getName(); - - public boolean isSynthetic(); } diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index 2db5698eac..b97b648070 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -16,9 +16,7 @@ import avian.SystemClassLoader; import java.lang.annotation.Annotation; -public class Method extends AccessibleObject - implements Member, GenericDeclaration -{ +public class Method extends AccessibleObject implements Member { private final VMMethod vmMethod; private boolean accessible; @@ -200,28 +198,4 @@ public class Method extends AccessibleObject public Annotation[] getDeclaredAnnotations() { return getAnnotations(); } - - public boolean isSynthetic() { - throw new UnsupportedOperationException(); - } - - public Object getDefaultValue() { - throw new UnsupportedOperationException(); - } - - public Type[] getGenericParameterTypes() { - throw new UnsupportedOperationException(); - } - - public Type getGenericReturnType() { - throw new UnsupportedOperationException(); - } - - public Class[] getExceptionTypes() { - throw new UnsupportedOperationException(); - } - - public TypeVariable>[] getTypeParameters() { - throw new UnsupportedOperationException(); - } } diff --git a/classpath/java/lang/reflect/TypeVariable.java b/classpath/java/lang/reflect/TypeVariable.java deleted file mode 100644 index 65d531d6bf..0000000000 --- a/classpath/java/lang/reflect/TypeVariable.java +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright (c) 2009, 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.reflect; - -public interface TypeVariable - extends Type -{ - public Type[] getBounds(); - public T getGenericDeclaration(); - public String getName(); -} diff --git a/classpath/java/util/Formatter.java b/classpath/java/util/Formatter.java deleted file mode 100644 index 6acf9b5fba..0000000000 --- a/classpath/java/util/Formatter.java +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2009, 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.util; - -public class Formatter { - private final Locale locale; - - public Formatter(Locale locale) { - this.locale = locale; - } - - public Formatter format(String format, Object ... args) { - throw new UnsupportedOperationException(); - } -} diff --git a/classpath/java/util/regex/Matcher.java b/classpath/java/util/regex/Matcher.java index 2296b4bf9d..99f9d9daad 100644 --- a/classpath/java/util/regex/Matcher.java +++ b/classpath/java/util/regex/Matcher.java @@ -36,18 +36,6 @@ public class Matcher { } } - public boolean requireEnd() { - throw new UnsupportedOperationException(); - } - - public boolean hitEnd() { - throw new UnsupportedOperationException(); - } - - public boolean lookingAt() { - throw new UnsupportedOperationException(); - } - public Matcher reset() { return reset(input); } @@ -63,26 +51,6 @@ public class Matcher { return start; } - public int start(int group) { - throw new UnsupportedOperationException(); - } - - public Pattern pattern() { - throw new UnsupportedOperationException(); - } - - public Matcher region(int start, int end) { - throw new UnsupportedOperationException(); - } - - public int regionEnd() { - throw new UnsupportedOperationException(); - } - - public int regionStart() { - throw new UnsupportedOperationException(); - } - public String replaceAll(String replacement) { return replace(replacement, Integer.MAX_VALUE); } @@ -124,10 +92,6 @@ public class Matcher { return end; } - public int end(int group) { - throw new UnsupportedOperationException(); - } - public boolean find() { return find(end); } @@ -143,16 +107,4 @@ public class Matcher { return false; } } - - public int groupCount() { - throw new UnsupportedOperationException(); - } - - public String group() { - throw new UnsupportedOperationException(); - } - - public String group(int group) { - throw new UnsupportedOperationException(); - } } diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index 2a48591592..c9827c1f70 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.java @@ -92,10 +92,6 @@ public class Pattern { return pattern; } - public static String quote(String s) { - throw new UnsupportedOperationException(); - } - public String[] split(CharSequence input) { return split(input, 0); } diff --git a/readme.txt b/readme.txt index 93e658dada..1f04cf69d0 100644 --- a/readme.txt +++ b/readme.txt @@ -191,36 +191,6 @@ Finally, build with the msvc flag set to the MSVC tool directory: $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" -Building with GNU Classpath ---------------------------- - - ** Please note that this feature is still under development and is - neither complete nor well-tested. ** - -By default, Avian uses its own lightweight class library. However, -that library only contains a relatively small subset of the classes -and methods included in the JRE. If your application requires -features beyond that subset, you may want to tell Avian to use GNU -Classpath instead. In order for this to work, you must configure -Classpath with "--enable-static" and "--with-pic". For example: - - $ cd classpath-0.98 - $ ./configure --prefix=/usr/local/classpath-0.98 --disable-plugin \ - --enable-static --with-pic - $ make && make install - -Then, when building Avian, specify the directory where Classpath is -installed, e.g.: - - $ cd ../avian - $ make clean - $ make gnu=/usr/local/classpath-0.98 - -This build will use the classes and native code from Classpath, except -that certain core classes are replaced with implementations from the -Avian class library for compatibility with the VM. - - Installing ---------- diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 0c4a7070da..74bab29f5a 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -367,7 +367,6 @@ ExceptionCheck(Thread* t) return t->exception != 0; } -#ifndef AVIAN_GNU jobject JNICALL NewDirectByteBuffer(Thread*, void*, jlong) { @@ -385,7 +384,6 @@ GetDirectBufferCapacity(Thread*, jobject) { return -1; } -#endif// not AVIAN_GNU jclass JNICALL GetObjectClass(Thread* t, jobject o) @@ -2038,17 +2036,6 @@ append(char** p, const char* value, unsigned length, char tail) namespace vm { -#ifdef AVIAN_GNU -jobject JNICALL -NewDirectByteBuffer(Thread*, void*, jlong); - -void* JNICALL -GetDirectBufferAddress(Thread*, jobject); - -jlong JNICALL -GetDirectBufferCapacity(Thread*, jobject); -#endif//AVIAN_GNU - void populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) { @@ -2081,15 +2068,9 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) envTable->ThrowNew = local::ThrowNew; envTable->Throw = local::Throw; envTable->ExceptionCheck = local::ExceptionCheck; -#ifdef AVIAN_GNU - envTable->NewDirectByteBuffer = vm::NewDirectByteBuffer; - envTable->GetDirectBufferAddress = vm::GetDirectBufferAddress; - envTable->GetDirectBufferCapacity = vm::GetDirectBufferCapacity; -#else envTable->NewDirectByteBuffer = local::NewDirectByteBuffer; envTable->GetDirectBufferAddress = local::GetDirectBufferAddress; envTable->GetDirectBufferCapacity = local::GetDirectBufferCapacity; -#endif envTable->DeleteLocalRef = local::DeleteLocalRef; envTable->GetObjectClass = local::GetObjectClass; envTable->IsInstanceOf = local::IsInstanceOf; From 1f67aea456d7220e403438ae3f634c5804f6da00 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 27 Sep 2010 17:12:08 -0600 Subject: [PATCH 061/274] fix process=interpret build --- src/compile.cpp | 31 -------------------------- src/interpret.cpp | 55 ++++++++++++----------------------------------- src/process.cpp | 39 +++++++++++++++++++++++++++++---- src/process.h | 6 +++--- 4 files changed, 52 insertions(+), 79 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index f5ec9015f3..e0b3ee8586 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6131,37 +6131,6 @@ compileVirtualMethod(MyThread* t) } } -void -resolveNative(MyThread* t, object method) -{ - PROTECT(t, method); - - assert(t, methodFlags(t, method) & ACC_NATIVE); - - initClass(t, methodClass(t, method)); - - if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { - object native = resolveNativeMethod(t, method); - if (UNLIKELY(native == 0)) { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - - t->exception = t->m->classpath->makeThrowable - (t, Machine::UnsatisfiedLinkErrorType, message); - return; - } - - // ensure other threads only see the methodCode field populated - // once the object it points do has been populated: - storeStoreMemoryBarrier(); - - set(t, method, MethodCode, native); - } -} - uint64_t invokeNativeFast(MyThread* t, object method, void* function) { diff --git a/src/interpret.cpp b/src/interpret.cpp index a228d6f696..f14b7084d0 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -376,10 +376,9 @@ popFrame(Thread* t) } if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag) - and t->classInitList) - { - assert(t, t->classInitList->class_ == methodClass(t, method)); - + and t->classInitList + and t->classInitList->class_ == methodClass(t, method)) + { t->classInitList->pop(); postInitClass(t, methodClass(t, method)); @@ -429,30 +428,6 @@ class MyStackWalker: public Processor::StackWalker { int frame; }; -inline void -resolveNative(Thread* t, object method) -{ - if (methodCode(t, method) == 0) { - object native = resolveNativeMethod(t, method); - if (LIKELY(native)) { - // ensure other threads only see the methodCode field populated - // once the object it points do has been populated: - storeStoreMemoryBarrier(); - - set(t, method, MethodCode, native); - } else { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - - t->exception = t->m->classpath->makeThrowable - (t, Machine::UnsatisfiedLinkErrorType, message); - } - } -} - inline void checkStack(Thread* t, object method) { @@ -538,7 +513,7 @@ pushResult(Thread* t, unsigned returnCode, uint64_t result, bool indirect) void marshalArguments(Thread* t, uintptr_t* args, uint8_t* types, unsigned sp, - object method, bool indirect) + object method, bool fastCallingConvention) { MethodSpecIterator it (t, reinterpret_cast @@ -565,19 +540,19 @@ marshalArguments(Thread* t, uintptr_t* args, uint8_t* types, unsigned sp, case INT64_TYPE: { uint64_t v = peekLong(t, sp); memcpy(args + argOffset, &v, 8); - argOffset += (8 / BytesPerWord); + argOffset += fastCallingConvention ? 2 : (8 / BytesPerWord); sp += 2; } break; case POINTER_TYPE: { - if (indirect) { + if (fastCallingConvention) { + args[argOffset++] = reinterpret_cast(peekObject(t, sp++)); + } else { object* v = reinterpret_cast(t->stack + ((sp++) * 2) + 1); if (*v == 0) { v = 0; } args[argOffset++] = reinterpret_cast(v); - } else { - args[argOffset++] = reinterpret_cast(peekObject(t, sp++)); } } break; @@ -628,7 +603,7 @@ invokeNativeSlow(Thread* t, object method, void* function) marshalArguments (t, RUNTIME_ARRAY_BODY(args) + argOffset, - RUNTIME_ARRAY_BODY(types) + typeOffset, sp, method, true); + RUNTIME_ARRAY_BODY(types) + typeOffset, sp, method, false); unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); @@ -685,19 +660,17 @@ invokeNative(Thread* t, object method) if (nativeFast(t, native)) { pushFrame(t, method); - unsigned footprint = methodParameterFootprint(t, method) + 1; + unsigned footprint = methodParameterFootprint(t, method); RUNTIME_ARRAY(uintptr_t, args, footprint); unsigned sp = frameBase(t, t->frame); unsigned argOffset = 0; - if (methodFlags(t, method) & ACC_STATIC) { - ++ footprint; - } else { + if ((methodFlags(t, method) & ACC_STATIC) == 0) { RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(peekObject(t, sp++)); } marshalArguments - (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, false); + (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, true); uint64_t result = reinterpret_cast (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); @@ -2829,7 +2802,7 @@ interpret(Thread* t) case iinc: { uint16_t index = codeReadInt16(t, code, ip); - uint16_t count = codeReadInt16(t, code, ip); + int16_t count = codeReadInt16(t, code, ip); setLocalInt(t, index, localInt(t, index) + count); } goto loop; @@ -3072,7 +3045,7 @@ class MyProcessor: public Processor { { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code, 0); + offset, 0, name, spec, addendum, class_, code); } virtual object diff --git a/src/process.cpp b/src/process.cpp index 090d253170..c9ed7a4505 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -203,10 +203,6 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, return 0; } -} // namespace - -namespace vm { - object resolveNativeMethod(Thread* t, object method) { @@ -223,6 +219,41 @@ resolveNativeMethod(Thread* t, object method) return 0; } +} // namespace + +namespace vm { + +void +resolveNative(Thread* t, object method) +{ + PROTECT(t, method); + + assert(t, methodFlags(t, method) & ACC_NATIVE); + + initClass(t, methodClass(t, method)); + + if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { + object native = resolveNativeMethod(t, method); + if (UNLIKELY(native == 0)) { + object message = makeString + (t, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); + + t->exception = t->m->classpath->makeThrowable + (t, Machine::UnsatisfiedLinkErrorType, message); + return; + } + + // ensure other threads only see the methodCode field populated + // once the object it points do has been populated: + storeStoreMemoryBarrier(); + + set(t, method, MethodCode, native); + } +} + int findLineNumber(Thread* t, object method, unsigned ip) { diff --git a/src/process.h b/src/process.h index 0b4ead129e..2405734657 100644 --- a/src/process.h +++ b/src/process.h @@ -56,9 +56,6 @@ isSpecialMethod(Thread* t, object method, object class_) and isSuperclass(t, methodClass(t, method), class_); } -object -resolveNativeMethod(Thread* t, object method); - inline void populateMultiArray(Thread* t, object array, int32_t* counts, unsigned index, unsigned dimensions) @@ -90,6 +87,9 @@ populateMultiArray(Thread* t, object array, int32_t* counts, } } +void +resolveNative(Thread* t, object method); + int findLineNumber(Thread* t, object method, unsigned ip); From ca251dfa1769fc6f31c97f26a34d9cf24bbe2024 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 13 Oct 2010 13:37:09 -0600 Subject: [PATCH 062/274] print error message on failed dlopen if Verbose is true in posix.cpp --- src/posix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index 0d34e2828a..2f7554698e 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -755,7 +755,9 @@ class MySystem: public System { return 0; } else { -// fprintf(stderr, "dlerror: %s\n", dlerror()); + if (Verbose) { + fprintf(stderr, "dlerror opening %s: %s\n", name, dlerror()); + } return 1; } } From b3accf1b308a04ce11f239ebb20bcca74ea5cc4d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 13 Oct 2010 13:38:31 -0600 Subject: [PATCH 063/274] ServerSocketChannel throws IOException, not Exception --- classpath/java/nio/channels/ServerSocketChannel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index c8a691c5c5..61dfe60559 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -40,7 +40,7 @@ public class ServerSocketChannel extends SelectableChannel { channel.close(); } - public SocketChannel accept() throws Exception { + public SocketChannel accept() throws IOException { SocketChannel c = new SocketChannel(); c.socket = doAccept(); c.connected = true; From 081d2d68ce195abc4a1c587f9044cb4767d0fcdb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 14 Oct 2010 23:43:35 +0000 Subject: [PATCH 064/274] handle and ignore SIGPIPE on Posix systems We must handle this signal or we'll get the default behavior of exiting the process whenever we get an unexpected network disconnection. --- src/posix.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 2f7554698e..da0397c107 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -65,13 +65,16 @@ const int AltSegFaultSignal = SIGBUS; const int AltSegFaultSignal = InvalidSignal; #endif const unsigned AltSegFaultSignalIndex = 3; +const int PipeSignal = SIGPIPE; +const unsigned PipeSignalIndex = 4; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal, - AltSegFaultSignal }; + AltSegFaultSignal, + PipeSignal }; -const unsigned SignalCount = 4; +const unsigned SignalCount = 5; class MySystem; MySystem* system; @@ -530,6 +533,7 @@ class MySystem: public System { system = this; registerHandler(&nullHandler, InterruptSignalIndex); + registerHandler(&nullHandler, PipeSignalIndex); registerHandler(&nullHandler, VisitSignalIndex); expect(this, make(&visitLock) == 0); @@ -786,6 +790,7 @@ class MySystem: public System { registerHandler(0, InterruptSignalIndex); registerHandler(0, VisitSignalIndex); + registerHandler(0, PipeSignalIndex); system = 0; ::free(this); @@ -862,6 +867,10 @@ handleSignal(int signal, siginfo_t* info, void* context) index = InterruptSignalIndex; } break; + case PipeSignal: { + index = PipeSignalIndex; + } break; + default: abort(); } @@ -873,6 +882,7 @@ handleSignal(int signal, siginfo_t* info, void* context) switch (signal) { case VisitSignal: case InterruptSignal: + case PipeSignal: break; default: From cf14a2c22270d6e20d01624ba458f826f7cd356d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 15 Oct 2010 23:06:03 +0000 Subject: [PATCH 065/274] add exception for Object.clone() to vm.pro Proguard gets confused about clone() and array classes (see http://sourceforge.net/tracker/index.php?func=detail&aid=2851344&group_id=54750&atid=474704). --- vm.pro | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vm.pro b/vm.pro index a6a2a54413..c2bd83c3d6 100644 --- a/vm.pro +++ b/vm.pro @@ -97,3 +97,9 @@ -keepnames public class avian.Callback -keepnames public class java.util.concurrent.Callable + +# Proguard gets confused about clone() and array classes (http://sourceforge.net/tracker/index.php?func=detail&aid=2851344&group_id=54750&atid=474704): + +-keepclassmembers class java.lang.Object { + protected java.lang.Object clone(); + } From 5cbfee467ccc80bbff7b8bc35c0a150e3be5c9da Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 22 Oct 2010 14:39:38 -0600 Subject: [PATCH 066/274] fix Runtime.exec on Posix Due to a silly cut-and-paste error, we were incorrectly passing the stdout and stderr file descriptors back from native code to Java, which prevented reading the output of the child process. --- classpath/java-lang.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 8303e3e4e1..9331ee099f 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -234,7 +234,8 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { - char** argv = static_cast(malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); + char** argv = static_cast + (malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); int i; for(i = 0; i < e->GetArrayLength(command); i++){ jstring element = (jstring) e->GetObjectArrayElement(command, i); @@ -255,11 +256,11 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast(out[1]); - e->SetLongArrayRegion(process, 1, 1, &outDescriptor); + e->SetLongArrayRegion(process, 2, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast(err[0]); - e->SetLongArrayRegion(process, 1, 1, &errDescriptor); + e->SetLongArrayRegion(process, 3, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { From 1ed03b909643052c1fea1b8745e2e49652ed5199 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 22 Oct 2010 18:20:19 -0600 Subject: [PATCH 067/274] fix build breakage due to makefile syntax confusion Consider the following makefile construct: target: dep0 target: dep1 dep2 command -o $(@) $(^) With some versions of make, $(^) will expand to "dep1 dep2", but on others it will expand to "dep0 dep1 dep2". The commit ensures that we no longer rely on the former behavior (nor the latter, for that matter). --- makefile | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/makefile b/makefile index 162a40398c..c66c09493c 100644 --- a/makefile +++ b/makefile @@ -649,23 +649,24 @@ $(classpath-object-dep): $(classpath-libraries) for x in $(classpath-libraries); do ar x $${x}; done) @touch $(@) -$(executable): $(classpath-object-dep) -$(executable): \ - $(vm-objects) $(jni-objects) $(driver-object) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) +executable-objects = $(vm-objects) $(jni-objects) $(driver-object) \ + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) + +$(executable): $(classpath-object-dep) $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc - $(ld) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb -IMPLIB:$(@).lib \ - -MANIFESTFILE:$(@).manifest + $(ld) $(lflags) $(executable-objects) -out:$(@) -PDB:$(@).pdb \ + -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(^) $(call classpath-objects) + $(dlltool) -z $(@).def $(executable-objects) $(call classpath-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(^) $(call classpath-objects) $(lflags) -o $(@) + $(ld) $(@).exp $(executable-objects) $(call classpath-objects) $(lflags) \ + -o $(@) endif else - $(ld) $(^) $(call classpath-objects) $(rdynamic) $(lflags) \ + $(ld) $(executable-objects) $(call classpath-objects) $(rdynamic) $(lflags) \ $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -696,17 +697,18 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -$(dynamic-library): $(classpath-object-dep) -$(dynamic-library): \ - $(vm-objects) $(dynamic-object) $(jni-objects) $(vm-heapwalk-objects) \ - $(boot-object) $(vm-classpath-object) $(classpath-libraries) +dynamic-library-objects = $(vm-objects) $(dynamic-object) $(jni-objects) \ + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ + $(classpath-libraries) + +$(dynamic-library): $(classpath-object-dep) $(dynamic-library-objects) @echo "linking $(@)" ifdef msvc - $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ - -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest + $(ld) $(shared) $(lflags) $(dynamic-library-objects) -out:$(@) \ + -PDB:$(@).pdb -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) -Wl,--version-script=openjdk.ld \ + $(ld) $(dynamic-library-objects) -Wl,--version-script=openjdk.ld \ $(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) From 05ff032f69c9431917f8d05e44980cf138e07951 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 Oct 2010 20:38:42 -0600 Subject: [PATCH 068/274] pass -march=i586 to gcc when targetting 32-bit x86 Recent versions of GCC will only give us __sync_bool_compare_and_swap_8 if we target i586 and above, apparently. --- makefile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/makefile b/makefile index c66c09493c..0109e672a6 100644 --- a/makefile +++ b/makefile @@ -57,11 +57,6 @@ java-home = /tmp ifdef openjdk classpath = openjdk options := $(options)-openjdk - ifeq ($(arch),x86_64) - openjdk-lib-dir = $(openjdk)/jre/lib/amd64 - else - openjdk-lib-dir = $(openjdk)/jre/lib - endif java-home = $(openjdk)/jre test-executable = $(executable-dynamic) boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar @@ -252,7 +247,7 @@ endif ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: - cflags += -march=i486 + cflags += -march=i586 endif endif From 6df0b2cfd9042d8fc41ca12cd65f9f3bcf549fb9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 Oct 2010 20:40:48 -0600 Subject: [PATCH 069/274] look for 32-bit JRE libraries under lib/i386 --- src/classpath-openjdk.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index a241aa1644..7c76128444 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -200,7 +200,8 @@ class MyClasspath : public Classpath { #ifdef ARCH_x86_64 sb.append("/lib/amd64"); #else - sb.append("/lib"); + // todo: handle other architectures + sb.append("/lib/i386"); #endif } @@ -2272,7 +2273,8 @@ JVM_GetMethodIxByteCodeLength(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT void JNICALL JVM_GetMethodIxExceptionTableEntry(Thread*, jclass, jint, jint, - local::JVM_ExceptionTableEntryType*) { abort(); } + local::JVM_ExceptionTableEntryType*) +{ abort(); } extern "C" JNIEXPORT jint JNICALL JVM_GetMethodIxExceptionTableLength(Thread*, jclass, int) { abort(); } From 9c603c6525ced49e4502b2c81d1191d9cc7211b6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 23 Oct 2010 20:41:45 -0600 Subject: [PATCH 070/274] fix member offset calculation inconsistencies in type-generator.cpp --- src/type-generator.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/type-generator.cpp b/src/type-generator.cpp index b8d63a9572..1480fb92a4 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -44,7 +44,7 @@ inline unsigned pad(unsigned size, unsigned alignment) { unsigned n = alignment; - while (size and n % size and n % BytesPerWord) ++ n; + while (size and n % size) ++ n; return n - alignment; } @@ -886,11 +886,11 @@ class MemberIterator { offset_(type->type == Object::Pod ? 0 : BytesPerWord), size_(0), padding_(0), - alignment_(0) + alignment_(BytesPerWord) { while (skipSupers and hasMore() and this->type != type) next(); padding_ = 0; - alignment_ = 0; + alignment_ = BytesPerWord; } bool hasMore() { @@ -924,7 +924,7 @@ class MemberIterator { case Object::Scalar: { size_ = memberSize(member); padding_ = pad(size_, alignment_); - alignment_ = (alignment_ + size_ + padding_) % BytesPerWord; + alignment_ = (alignment_ + size_ + padding_) % 8; } break; case Object::Array: { @@ -938,11 +938,11 @@ class MemberIterator { offset_ += padding_; -// fprintf(stderr, -// "type: %s; member: %s; size: %d; padding: %d; alignment: %d;" -// " offset: %d;\n", -// typeName(type), memberName(member), size_, padding_, alignment_, -// offset_); + // fprintf(stderr, + // "type: %s; member: %s; size: %d; padding: %d; alignment: %d;" + // " offset: %d;\n", + // typeName(type), memberName(member), size_, padding_, alignment_, + // offset_); return member; } From ec6080fea60263ffd993e2d5c05217f5d2adfb1c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 Oct 2010 11:45:41 -0600 Subject: [PATCH 071/274] update readme.txt to point to new classpath.jar path --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 1f04cf69d0..e90201703a 100644 --- a/readme.txt +++ b/readme.txt @@ -390,7 +390,7 @@ Step 2: Create a stage1 directory and extract the contents of the class library jar into it. $ mkdir stage1 - $ (cd stage1 && jar xf ../../build/classpath.jar) + $ (cd stage1 && jar xf ../../build/${platform}-${arch}/classpath.jar) Step 3: Build the Java code and add it to stage1. From 6f839323a78805437ae98db9870056b46dc93db4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 Oct 2010 11:49:12 -0600 Subject: [PATCH 072/274] use user-specified boot classpath exclusively when present --- src/classpath-avian.cpp | 2 +- src/classpath-openjdk.cpp | 2 ++ src/jnienv.cpp | 14 +++++++------- src/main.cpp | 9 --------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 750f40bc16..13bbf44f41 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -95,7 +95,7 @@ class MyClasspath : public Classpath { virtual const char* bootClasspath() { - return ""; + return BOOT_CLASSPATH; } virtual void diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 7c76128444..0c13971f4a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -182,6 +182,8 @@ class MyClasspath : public Classpath { sb.append('\0'); this->classpath = sb.pointer; + sb.append(BOOT_CLASSPATH); + sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/rt.jar"); sb.append(s->pathSeparator()); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 74bab29f5a..0e249d2aba 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2245,7 +2245,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) const char* classpath = 0; const char* javaHome = AVIAN_JAVA_HOME; const char* bootClasspathPrepend = ""; - const char* bootClasspath = ""; + const char* bootClasspath = 0; const char* bootClasspathAppend = ""; const char* crashDumpDirectory = 0; @@ -2300,21 +2300,21 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); Classpath* c = makeClasspath(s, h, javaHome); - const char* classpathBootClasspath = c->bootClasspath(); + + if (bootClasspath == 0) { + bootClasspath = c->bootClasspath(); + } unsigned bcppl = strlen(bootClasspathPrepend); unsigned bcpl = strlen(bootClasspath); - unsigned cbcpl = strlen(classpathBootClasspath); unsigned bcpal = strlen(bootClasspathAppend); - unsigned bootClasspathBufferSize = bcppl + bcpl + cbcpl + bcpal + 3; + unsigned bootClasspathBufferSize = bcppl + bcpl + bcpal + 3; RUNTIME_ARRAY(char, bootClasspathBuffer, bootClasspathBufferSize); char* bootClasspathPointer = RUNTIME_ARRAY_BODY(bootClasspathBuffer); local::append(&bootClasspathPointer, bootClasspathPrepend, bcppl, - bcpl + cbcpl + bcpal ? PATH_SEPARATOR : 0); + bcpl + bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspath, bcpl, - cbcpl + bcpal ? PATH_SEPARATOR : 0); - local::append(&bootClasspathPointer, classpathBootClasspath, cbcpl, bcpal ? PATH_SEPARATOR : 0); local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); diff --git a/src/main.cpp b/src/main.cpp index 383e324a3c..38cc765a3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,10 +105,6 @@ main(int ac, const char** av) ++ vmArgs.nOptions; #endif -#ifdef BOOT_CLASSPATH - ++ vmArgs.nOptions; -#endif - #ifdef BOOT_IMAGE ++ vmArgs.nOptions; #endif @@ -127,11 +123,6 @@ main(int ac, const char** av) = const_cast("-Davian.bootimage=" BOOT_IMAGE); #endif -#ifdef BOOT_CLASSPATH - vmArgs.options[optionIndex++].optionString - = const_cast("-Xbootclasspath:" BOOT_CLASSPATH); -#endif - #ifdef BOOT_LIBRARY vmArgs.options[optionIndex++].optionString = const_cast("-Davian.bootstrap=" BOOT_LIBRARY); From 25ca40931db2963b6f9cdc3c1af1caa7231525c2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 Oct 2010 11:49:59 -0600 Subject: [PATCH 073/274] keep track of original class in resolveField so we can throw an exception with a useful message --- src/machine.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 4c7d26a21a..b9e849f6b4 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3391,8 +3391,11 @@ resolveField(Thread* t, object class_, const char* fieldName, object field = findInInterfaces(t, class_, name, spec, findFieldInClass); - for (; class_ != 0 and field == 0; class_ = classSuper(t, class_)) { - field = findFieldInClass(t, class_, name, spec); + object c = class_; + PROTECT(t, c); + + for (; c != 0 and field == 0; c = classSuper(t, c)) { + field = findFieldInClass(t, c, name, spec); } if (t->exception == 0 and field == 0) { From cdcc9caeb2719a8b8c94fe41ea9d978b89fa42dd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 Oct 2010 11:52:14 -0600 Subject: [PATCH 074/274] initial work towards ProGuard-enabled OpenJDK builds --- openjdk.pro | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vm.pro | 12 ++++++ 2 files changed, 116 insertions(+) create mode 100644 openjdk.pro diff --git a/openjdk.pro b/openjdk.pro new file mode 100644 index 0000000000..ce9522245a --- /dev/null +++ b/openjdk.pro @@ -0,0 +1,104 @@ +# proguard include file (http://proguard.sourceforge.net) + +# This file is for use in combination with vm.pro when ProGuarding +# OpenJDK-based builds + +# the following methods and fields are refered to by name in the VM: + +-keepclassmembers class java.lang.Thread { + public void run(); + } + +-keep class java.lang.System { + private static void initializeSystemClass(); + } + +-keep class java.lang.ClassLoader { + private static java.lang.ClassLoader scl; + private static boolean sclSet; + + protected ClassLoader(java.lang.ClassLoader); + } + +-keep class java.util.Properties { + public java.lang.Object setProperty(java.lang.String, java.lang.String); + } + +-keep class avian.OpenJDK { + public static java.security.ProtectionDomain getProtectionDomain(); + } + +-keepclassmembers public class java.security.PrivilegedAction { + public java.lang.Object run(); + } + +-keepclassmembers public class * implements java.security.PrivilegedAction { + public java.lang.Object run(); + } + +-keepclassmembers public class java.security.PrivilegedExceptionAction { + public java.lang.Object run(); + } + +-keepclassmembers public class * implements java.security.PrivilegedExceptionAction { + public java.lang.Object run(); + } + +-keep public class java.security.PrivilegedActionException { + public PrivilegedActionException(java.lang.Exception); + } + +# these class names are used to disambiguate JNI method lookups: + +-keepnames public class java.security.PrivilegedAction +-keepnames public class java.security.PrivilegedExceptionAction +-keepnames public class java.security.AccessControlContext + +# the following methods and fields are refered to by name in the OpenJDK +# native code: + +-keep class java.util.Properties { + public java.lang.Object put(java.lang.Object, java.lang.Object); + } + +-keepclassmembers class * { + public boolean equals(java.lang.Object); + public void wait(); + public void notify(); + public void notifyAll(); + public java.lang.String toString(); + } + +-keepclassmembers class java.lang.String { + public String(byte[]); + public String(byte[], java.lang.String); + public byte[] getBytes(); + public byte[] getBytes(java.lang.String); + } + +-keepclassmembers class java.io.FileDescriptor { + private int fd; + } + +-keepclassmembers class java.io.FileInputStream { + private java.io.FileDescriptor fd; + } + +-keepclassmembers class java.io.FileOutputStream { + private java.io.FileDescriptor fd; + } + +# ProGuard will not realize AtomicInteger.value is changed from native +# code unless we tell it (todo: handle other Atomic* classes) +-keepclassmembers class java.util.concurrent.atomic.AtomicInteger { + private int value; + } + +# this field as accessed via an AtomicReferenceFieldUpdater: +-keepclassmembers class java.io.BufferedInputStream { + protected byte[] buf; + } + + + +# (to be continued...) diff --git a/vm.pro b/vm.pro index a6a2a54413..9cc2a2fdd2 100644 --- a/vm.pro +++ b/vm.pro @@ -12,6 +12,7 @@ -keepclassmembers class java.lang.ClassLoader { !static ; } -keepclassmembers class java.lang.String { !static ; } -keepclassmembers class java.lang.Thread { !static ; } +-keepclassmembers class java.lang.ThreadGroup { !static ; } -keepclassmembers class java.lang.StackTraceElement { !static ; } -keepclassmembers class java.lang.Throwable { !static ; } -keepclassmembers class java.lang.Byte { !static ; } @@ -28,6 +29,17 @@ -keepclassmembers class java.lang.ref.PhantomReference { !static ; } -keepclassmembers class java.lang.reflect.Field { !static ; } -keepclassmembers class java.lang.reflect.Method { !static ; } +-keepclassmembers class java.lang.reflect.Constructor { !static ; } +-keepclassmembers class java.lang.reflect.AccessibleObject { !static ; } +-keepclassmembers class sun.reflect.ConstantPool { !static ; } +-keepclassmembers class avian.VMClass { !static ; } +-keepclassmembers class avian.VMMethod { !static ; } +-keepclassmembers class avian.VMField { !static ; } +-keepclassmembers class avian.ClassAddendum { !static ; } +-keepclassmembers class avian.MethodAddendum { !static ; } +-keepclassmembers class avian.FieldAddendum { !static ; } +-keepclassmembers class avian.Continuations$Continuation { !static ; } +-keepclassmembers class avian.Continuations$UnwindResult { !static ; } # the VM may throw instances of the following: From 21deedc500a333c057a3f00aeccbf09ae4c64e08 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 24 Oct 2010 14:50:33 -0600 Subject: [PATCH 075/274] update openjdk.pro --- openjdk.pro | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/openjdk.pro b/openjdk.pro index ce9522245a..8067305599 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -88,17 +88,48 @@ private java.io.FileDescriptor fd; } -# ProGuard will not realize AtomicInteger.value is changed from native -# code unless we tell it (todo: handle other Atomic* classes) +# changed in native code via sun.misc.Unsafe (todo: handle other +# Atomic* classes) -keepclassmembers class java.util.concurrent.atomic.AtomicInteger { private int value; } -# this field as accessed via an AtomicReferenceFieldUpdater: +# avoid inlining due to access check using a fixed offset into call stack: +-keep,allowshrinking,allowobfuscation class java.util.concurrent.atomic.AtomicReferenceFieldUpdater { + *** newUpdater(...); + } + +# accessed reflectively via an AtomicReferenceFieldUpdater: -keepclassmembers class java.io.BufferedInputStream { protected byte[] buf; } +-keep class java.lang.System { + public static java.io.InputStream in; + public static java.io.PrintStream out; + public static java.io.PrintStream err; + # avoid inlining due to access check using fixed offset into call stack: + static java.lang.Class getCallerClass(); + } +# refered to by name from native code: +-keepnames public class java.io.InputStream +-keepnames public class java.io.PrintStream -# (to be continued...) +# avoid inlining due to access check using fixed offset into call stack: +-keep,allowshrinking,allowobfuscation class java.lang.System { + static java.lang.Class getCallerClass(); + } + +-keep class java.io.UnixFileSystem { + public UnixFileSystem(); + } + +-keep class java.io.File { + private java.lang.String path; + } + +-keepclassmembers class java.lang.ClassLoader$NativeLibrary { + long handle; + private int jniVersion; + } From 5ade8d1cf65cf62adc6d8f85072967060f4659fc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 28 Oct 2010 20:30:49 -0600 Subject: [PATCH 076/274] use GetSystemTimeAsFileTime instead of _ftime on Windows It seems that _ftime has devolved to only giving 1-second resolution on Windows 7. GetSystemTimeAsFileTime does better, so that's what we'll use. --- classpath/java-lang.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 9331ee099f..ea37b2f275 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -36,9 +36,6 @@ # define isnan _isnan # define isfinite _finite # define strtof strtod -# define FTIME _ftime_s -# else -# define FTIME _ftime # endif #else // not PLATFORM_WINDOWS @@ -469,9 +466,13 @@ extern "C" JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis(JNIEnv*, jclass) { #ifdef PLATFORM_WINDOWS - _timeb tb; - FTIME(&tb); - return (static_cast(tb.time) * 1000) + static_cast(tb.millitm); + // We used to use _ftime here, but that only gives us 1-second + // resolution on Windows 7. _ftime_s might work better, but MinGW + // doesn't have it as of this writing. So we use this mess instead: + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((static_cast(time.dwHighDateTime) << 32) + | time.dwLowDateTime) / 10000) - 11644473600000LL; #else timeval tv = { 0, 0 }; gettimeofday(&tv, 0); From cabad6926f56943ad58a08b409e11fe02f72d9b5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Nov 2010 11:02:09 -0600 Subject: [PATCH 077/274] enable standalone OpenJDK builds As described in readme.txt, a standalone OpenJDK build embeds all libraries, classes, and other files needed at runtime in the resulting binary, eliminating dependencies on external resources. --- makefile | 110 +++++++++++++++---------- openjdk-src.mk | 166 ++++++++++++++++++++++++++++++++++++++ readme.txt | 48 +++++++++++ src/classpath-openjdk.cpp | 142 +++++++++++++++++++++++++++----- src/compile.cpp | 14 +--- src/jnienv.cpp | 12 ++- src/machine.cpp | 14 +--- src/machine.h | 62 +++++++++++++- src/openjdk/jni_md.h | 29 +++++++ src/types.def | 4 + 10 files changed, 509 insertions(+), 92 deletions(-) create mode 100644 openjdk-src.mk create mode 100644 src/openjdk/jni_md.h diff --git a/makefile b/makefile index 0109e672a6..edaecb7ff8 100644 --- a/makefile +++ b/makefile @@ -52,22 +52,31 @@ classpath = avian test-executable = $(executable) boot-classpath = $(classpath-build) -java-home = /tmp +java-home = /avian-embedded ifdef openjdk + ifdef openjdk-src + include openjdk-src.mk + options := $(options)-openjdk-src + classpath-objects = $(openjdk-objects) + classpath-cflags = -DAVIAN_OPENJDK_SRC + openjdk-jar-dep = $(build)/openjdk-jar.dep + classpath-jar-dep = $(openjdk-jar-dep) + else + options := $(options)-openjdk + test-executable = $(executable-dynamic) + library-path = LD_LIBRARY_PATH=$(build) + java-home = $(openjdk)/jre + endif + classpath = openjdk - options := $(options)-openjdk - java-home = $(openjdk)/jre - test-executable = $(executable-dynamic) boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar endif -ifneq ($(classpath),avian) - classpath-object-dep = $(build)/classpath-object.dep - classpath-objects = $(shell find $(build)/classpath-objects -name "*.o") -else +ifeq ($(classpath),avian) jni-sources := $(shell find $(classpath-src) -name '*.cpp') jni-objects = $(call cpp-objects,$(jni-sources),$(classpath-src),$(build)) + classpath-objects = $(jni-objects) endif input = List @@ -95,6 +104,7 @@ vg = nice valgrind --num-callers=32 --db-attach=yes --freelist-vol=100000000 vg += --leak-check=full --suppressions=valgrind.supp db = gdb --args javac = "$(JAVA_HOME)/bin/javac" +javah = "$(JAVA_HOME)/bin/javah" jar = "$(JAVA_HOME)/bin/jar" strip = strip strip-all = --strip-all @@ -108,7 +118,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ - "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) \ + "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(java-home)\" @@ -222,28 +232,30 @@ ifeq ($(platform),windows) endif ifeq ($(mode),debug) - cflags += -O0 -g3 + optimization-cflags = -O0 -g3 strip = : endif ifeq ($(mode),debug-fast) - cflags += -O0 -g3 -DNDEBUG + optimization-cflags = -O0 -g3 -DNDEBUG strip = : endif ifeq ($(mode),stress) - cflags += -O0 -g3 -DVM_STRESS + optimization-cflags = -O0 -g3 -DVM_STRESS strip = : endif ifeq ($(mode),stress-major) - cflags += -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR + optimization-cflags = -O0 -g3 -DVM_STRESS -DVM_STRESS_MAJOR strip = : endif ifeq ($(mode),fast) - cflags += -O3 -g3 -DNDEBUG + optimization-cflags = -O3 -g3 -DNDEBUG endif ifeq ($(mode),small) - cflags += -Os -g3 -DNDEBUG + optimization-cflags = -Os -g3 -DNDEBUG endif +cflags += $(optimization-cflags) + ifneq ($(platform),darwin) ifeq ($(arch),i386) # this is necessary to support __sync_bool_compare_and_swap: @@ -467,15 +479,15 @@ $(test-extra-dep): $(classpath-dep) .PHONY: run run: build - LD_LIBRARY_PATH=$(build) $(test-executable) $(test-args) + $(library-path) $(test-executable) $(test-args) .PHONY: debug debug: build - LD_LIBRARY_PATH=$(build) gdb --args $(test-executable) $(test-args) + $(library-path) gdb --args $(test-executable) $(test-args) .PHONY: vg vg: build - LD_LIBRARY_PATH=$(build) $(vg) $(test-executable) $(test-args) + $(library-path) $(vg) $(test-executable) $(test-args) .PHONY: test test: build @@ -581,7 +593,8 @@ $(driver-dynamic-object): $(driver-source) $(boot-object): $(boot-source) $(compile-object) -$(build)/classpath.jar: $(classpath-dep) +$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) + @echo "creating $(@)" (wd=$$(pwd) && \ cd $(classpath-build) && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) @@ -622,11 +635,10 @@ $(generator-objects): $(build)/%-build.o: $(src)/%.cpp $(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(classpath-object-dep) -$(static-library): $(vm-objects) $(jni-objects) $(vm-heapwalk-objects) +$(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) @echo "creating $(@)" rm -rf $(@) - $(ar) cru $(@) $(^) $(call classpath-objects) + $(ar) cru $(@) $(^) $(ranlib) $(@) $(bootimage-bin): $(bootimage-generator) @@ -638,16 +650,10 @@ $(bootimage-object): $(bootimage-bin) $(converter) _binary_bootimage_bin_end $(platform) $(arch) $(pointer-size) \ writable executable -$(classpath-object-dep): $(classpath-libraries) - @mkdir -p $(build)/classpath-objects - (cd $(build)/classpath-objects && \ - for x in $(classpath-libraries); do ar x $${x}; done) - @touch $(@) - -executable-objects = $(vm-objects) $(jni-objects) $(driver-object) \ +executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) -$(executable): $(classpath-object-dep) $(executable-objects) +$(executable): $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -655,14 +661,12 @@ ifdef msvc -IMPLIB:$(@).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(dlltool) -z $(@).def $(executable-objects) $(call classpath-objects) + $(dlltool) -z $(@).def $(executable-objects) $(dlltool) -d $(@).def -e $(@).exp - $(ld) $(@).exp $(executable-objects) $(call classpath-objects) $(lflags) \ - -o $(@) + $(ld) $(@).exp $(executable-objects) $(lflags) -o $(@) endif else - $(ld) $(executable-objects) $(call classpath-objects) $(rdynamic) $(lflags) \ - $(bootimage-lflags) -o $(@) + $(ld) $(executable-objects) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -675,8 +679,8 @@ $(bootimage-generator): $(bootimage-generator) $(build-bootimage-generator): \ - $(vm-objects) $(classpath-object) $(jni-objects) $(heapwalk-objects) \ - $(bootimage-generator-objects) + $(vm-objects) $(classpath-object) $(classpath-objects) \ + $(heapwalk-objects) $(bootimage-generator-objects) @echo "linking $(@)" ifeq ($(platform),windows) ifdef msvc @@ -692,11 +696,11 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -dynamic-library-objects = $(vm-objects) $(dynamic-object) $(jni-objects) \ - $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ - $(classpath-libraries) +dynamic-library-objects = $(vm-objects) $(dynamic-object) \ + $(classpath-objects) $(vm-heapwalk-objects) $(boot-object) \ + $(vm-classpath-object) $(classpath-libraries) -$(dynamic-library): $(classpath-object-dep) $(dynamic-library-objects) +$(dynamic-library): $(dynamic-library-objects) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(dynamic-library-objects) -out:$(@) \ @@ -704,7 +708,7 @@ ifdef msvc $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else $(ld) $(dynamic-library-objects) -Wl,--version-script=openjdk.ld \ - $(call classpath-objects) $(shared) $(lflags) $(bootimage-lflags) -o $(@) + $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) @@ -722,3 +726,25 @@ endif $(generator): $(generator-objects) @echo "linking $(@)" $(build-ld) $(^) $(build-lflags) -o $(@) + +$(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ + $(openjdk-headers-dep) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cc) -fPIC -fvisibility=hidden $(openjdk-cflags) $(optimization-cflags) \ + -w -c $(<) $(call output,$(@)) + +$(openjdk-headers-dep): $(openjdk)/jre/lib/rt.jar + @echo "generating openjdk headers" + @mkdir -p $(dir $(@)) + $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ + $(openjdk-headers-classes) + @touch $(@) + +$(openjdk-jar-dep): $(openjdk)/jre/lib/rt.jar $(openjdk)/jre/lib/jsse.jar \ + $(openjdk)/jre/lib/jce.jar $(openjdk)/jre/lib/resources.jar + @echo "extracting openjdk classes" + @mkdir -p $(dir $(@)) + @mkdir -p $(classpath-build) + (cd $(classpath-build) && for x in $(^); do jar xf $${x}; done) + @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk new file mode 100644 index 0000000000..5ee6a46096 --- /dev/null +++ b/openjdk-src.mk @@ -0,0 +1,166 @@ +openjdk-sources = \ + $(openjdk-src)/share/native/common/check_code.c \ + $(openjdk-src)/share/native/common/check_format.c \ + $(openjdk-src)/share/native/common/check_version.c \ + $(openjdk-src)/share/native/common/jdk_util.c \ + $(openjdk-src)/share/native/common/jio.c \ + $(openjdk-src)/share/native/common/jni_util.c \ + $(openjdk-src)/share/native/common/verify_stub.c \ + $(openjdk-src)/share/native/java/io/FileInputStream.c \ + $(openjdk-src)/share/native/java/io/io_util.c \ + $(openjdk-src)/share/native/java/io/ObjectInputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectOutputStream.c \ + $(openjdk-src)/share/native/java/io/ObjectStreamClass.c \ + $(openjdk-src)/share/native/java/io/RandomAccessFile.c \ + $(openjdk-src)/share/native/java/lang/Class.c \ + $(openjdk-src)/share/native/java/lang/ClassLoader.c \ + $(openjdk-src)/share/native/java/lang/Compiler.c \ + $(openjdk-src)/share/native/java/lang/Double.c \ + $(openjdk-src)/share/native/java/lang/Float.c \ + $(openjdk-src)/share/native/java/lang/Object.c \ + $(openjdk-src)/share/native/java/lang/Package.c \ + $(openjdk-src)/share/native/java/lang/ref/Finalizer.c \ + $(openjdk-src)/share/native/java/lang/reflect/Array.c \ + $(openjdk-src)/share/native/java/lang/reflect/Proxy.c \ + $(openjdk-src)/share/native/java/lang/ResourceBundle.c \ + $(openjdk-src)/share/native/java/lang/Runtime.c \ + $(openjdk-src)/share/native/java/lang/SecurityManager.c \ + $(openjdk-src)/share/native/java/lang/Shutdown.c \ + $(openjdk-src)/share/native/java/lang/StrictMath.c \ + $(openjdk-src)/share/native/java/lang/String.c \ + $(openjdk-src)/share/native/java/lang/System.c \ + $(openjdk-src)/share/native/java/lang/Thread.c \ + $(openjdk-src)/share/native/java/lang/Throwable.c \ + $(wildcard $(openjdk-src)/share/native/java/lang/fdlibm/src/*.c) \ + $(openjdk-src)/share/native/java/nio/Bits.c \ + $(openjdk-src)/share/native/java/security/AccessController.c \ + $(openjdk-src)/share/native/java/sql/DriverManager.c \ + $(openjdk-src)/share/native/java/util/concurrent/atomic/AtomicLong.c \ + $(openjdk-src)/share/native/java/util/TimeZone.c \ + $(openjdk-src)/share/native/java/util/zip/Adler32.c \ + $(openjdk-src)/share/native/java/util/zip/CRC32.c \ + $(openjdk-src)/share/native/java/util/zip/Deflater.c \ + $(openjdk-src)/share/native/java/util/zip/Inflater.c \ + $(openjdk-src)/share/native/java/util/zip/ZipEntry.c \ + $(openjdk-src)/share/native/java/util/zip/ZipFile.c \ + $(openjdk-src)/share/native/java/util/zip/zip_util.c \ + $(openjdk-src)/share/native/sun/misc/GC.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 \ + $(openjdk-src)/share/native/sun/misc/Version.c \ + $(openjdk-src)/share/native/sun/misc/VM.c \ + $(openjdk-src)/share/native/sun/misc/VMSupport.c \ + $(openjdk-src)/share/native/sun/reflect/ConstantPool.c \ + $(openjdk-src)/share/native/sun/reflect/NativeAccessors.c \ + $(openjdk-src)/share/native/sun/reflect/Reflection.c + +openjdk-headers-classes = \ + java.io.Console \ + java.io.FileDescriptor \ + java.io.FileInputStream \ + java.io.FileOutputStream \ + java.io.FileSystem \ + java.io.ObjectInputStream \ + java.io.ObjectOutputStream \ + java.io.ObjectStreamClass \ + java.io.RandomAccessFile \ + java.lang.Class \ + java.lang.ClassLoader \ + java.lang.Compiler \ + java.lang.Double \ + java.lang.Float \ + java.lang.Object \ + java.lang.Package \ + java.lang.Runtime \ + java.lang.SecurityManager \ + java.lang.Shutdown \ + java.lang.StrictMath \ + java.lang.String \ + java.lang.System \ + java.lang.Thread \ + java.lang.Throwable \ + java.lang.ref.Finalizer \ + java.lang.reflect.Array \ + java.lang.reflect.Proxy \ + java.security.AccessController \ + java.util.ResourceBundle \ + java.util.TimeZone \ + java.util.concurrent.atomic.AtomicLong \ + java.util.jar.JarFile \ + java.util.zip.Adler32 \ + java.util.zip.CRC32 \ + java.util.zip.Deflater \ + java.util.zip.Inflater \ + java.util.zip.ZipEntry \ + java.util.zip.ZipFile \ + sun.misc.GC \ + sun.misc.MessageUtils \ + sun.misc.NativeSignalHandler \ + sun.misc.Signal \ + sun.misc.VM \ + sun.misc.VMSupport \ + sun.misc.Version \ + sun.reflect.ConstantPool \ + sun.reflect.NativeConstructorAccessorImpl \ + sun.reflect.NativeMethodAccessorImpl \ + sun.reflect.Reflection \ + +# todo: set properties according to architecture targeted and OpenJDK +# version used: +openjdk-cflags = \ + "-I$(src)/openjdk" \ + "-I$(build)/openjdk" \ + "-I$(openjdk-src)/share/javavm/export" \ + "-I$(openjdk-src)/share/native/common" \ + "-I$(openjdk-src)/share/native/java/io" \ + "-I$(openjdk-src)/share/native/java/lang" \ + "-I$(openjdk-src)/share/native/java/lang/fdlibm/include" \ + "-I$(openjdk-src)/share/native/java/util/zip" \ + "-I$(openjdk-src)/share/javavm/include" \ + -D_LITTLE_ENDIAN \ + -DARCHPROPNAME=\"x86\" \ + -DRELEASE=\"1.6.0\" \ + -DJDK_MAJOR_VERSION=\"1\" \ + -DJDK_MINOR_VERSION=\"6\" \ + -DJDK_MICRO_VERSION=\"0\" \ + -DJDK_BUILD_NUMBER=\"0\" \ + -D_GNU_SOURCE + +ifeq ($(platform),windows) +# todo +else + openjdk-sources += \ + $(openjdk-src)/solaris/native/common/jdk_util_md.c \ + $(openjdk-src)/solaris/native/java/io/canonicalize_md.c \ + $(openjdk-src)/solaris/native/java/io/Console_md.c \ + $(openjdk-src)/solaris/native/java/io/FileDescriptor_md.c \ + $(openjdk-src)/solaris/native/java/io/FileInputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileOutputStream_md.c \ + $(openjdk-src)/solaris/native/java/io/FileSystem_md.c \ + $(openjdk-src)/solaris/native/java/io/io_util_md.c \ + $(openjdk-src)/solaris/native/java/io/RandomAccessFile_md.c \ + $(openjdk-src)/solaris/native/java/io/UnixFileSystem_md.c \ + $(openjdk-src)/solaris/native/java/lang/java_props_md.c \ + $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ + $(openjdk-src)/solaris/native/java/util/FileSystemPreferences.c \ + $(openjdk-src)/solaris/native/java/util/logging.c \ + $(openjdk-src)/solaris/native/java/util/TimeZone_md.c + + openjdk-headers-classes += \ + java.io.UnixFileSystem + + openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ + "-I$(openjdk-src)/solaris/native/common" \ + "-I$(openjdk-src)/solaris/native/java/io" \ + "-I$(openjdk-src)/solaris/native/java/util" \ + "-I$(openjdk-src)/solaris/javavm/include" +endif + +c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) + +openjdk-objects = \ + $(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) + +openjdk-headers-dep = $(build)/openjdk/headers.dep diff --git a/readme.txt b/readme.txt index e90201703a..57b978c1fc 100644 --- a/readme.txt +++ b/readme.txt @@ -191,6 +191,54 @@ Finally, build with the msvc flag set to the MSVC tool directory: $ make msvc="/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/VC" +Building with the OpenJDK Class Library +--------------------------------------- + +By default, Avian uses its own lightweight class library. However, +that library only contains a relatively small subset of the classes +and methods included in the JRE. If your application requires +features beyond that subset, you may want to tell Avian to use +OpenJDK's class library instead. To do so, specify the directory +where OpenJDK is installed, e.g.: + + $ make openjdk=/usr/lib/jvm/java-6-openjdk + +This will build Avian as a conventional JVM (e.g. libjvm.so) which +loads its boot class library and native libraries (e.g. libjava.so) +from /usr/lib/jvm/java-6-openjdk/jre at runtime. To run an +application in this configuration, you'll need to make sure the VM is +in your library search path. For example: + + $ LD_LIBRARY_PATH=build/linux-x86_64-openjdk \ + build/linux-x86_64-openjdk/avian-dynamic -cp /path/to/my/application \ + com.example.MyApplication + +Alternatively, you can enable a stand-alone build using OpenJDK by +specifying the location of the OpenJDK source code, e.g.: + + $ make openjdk=$(pwd)/../jdk6/build/linux-amd64/j2sdk-image \ + openjdk-src=$(pwd)/../jdk6/jdk/src + +The result of such a build is a self-contained binary which does not +depend on external libraries, jars, or other files. In this case, the +specified paths are used only at build time; anything needed at +runtime is embedded in the binary. Thus, the process of running an +application is simplified: + + $ build/linux-x86_64-openjdk-src/avian -cp /path/to/my/application \ + com.example.MyApplication + +Note that the resulting binary will be very large due to the size of +OpenJDK's class library. This can be mitigated using UPX, preferably +an LZMA-enabled version: + + $ upx --lzma --best build/linux-x86_64-openjdk-src/avian + +You can reduce the size futher for embedded builds by using ProGuard +and the supplied openjdk.pro configuration file (see "Embedding with +ProGuard and a Boot Image" below). + + Installing ---------- diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 0c13971f4a..5dd2c32c68 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -35,6 +35,9 @@ # define CREAT _wcreat # endif +# define LIBRARY_PREFIX "" +# define LIBRARY_SUFFIX ".dll" + #else // not PLATFORM_WINDOWS # include @@ -53,6 +56,9 @@ # define FSTAT fstat # define LSEEK lseek +# define LIBRARY_PREFIX "lib" +# define LIBRARY_SUFFIX ".so" + #endif // not PLATFORM_WINDOWS using namespace vm; @@ -139,6 +145,72 @@ makeClassNameString(Thread* t, object name) return makeString(t, "%s", s); } +#ifdef AVIAN_OPENJDK_SRC +// only safe to call during bootstrap when there's only one thread +// running: +void +intercept(Thread* t, object c, const char* name, const char* spec, + void* function) +{ + object m = findMethodOrNull(t, c, name, spec); + if (m) { + PROTECT(t, m); + + object clone = methodClone(t, m); + + // make clone private to prevent vtable updates at compilation + // time. Otherwise, our interception might be bypassed by calls + // through the vtable. + methodFlags(t, clone) |= ACC_PRIVATE; + + methodFlags(t, m) |= ACC_NATIVE; + + object native = makeNativeIntercept(t, function, true, clone); + + set(t, m, MethodCode, native); + } +} + +const char* +zipLibrary(Thread*); + +int64_t JNICALL +getFileAttributes +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Exists = 1; + const unsigned Regular = 2; + + object file = reinterpret_cast(arguments[1]); + + object pathField = findFieldInClass2 + (t, objectClass(t, file), "path", "Ljava/lang/String;"); + + if (pathField) { + object path = cast(file, fieldOffset(t, pathField)); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + + if (strcmp(zipLibrary(t), p) == 0) { + return Exists | Regular; + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), + reinterpret_cast(arguments[0]), file); + return (r ? intValue(t, r) : 0); + } + } else { + object message = makeString + (t, "path Ljava/lang/String; not found in %s", + &byteArrayBody(t, className(t, objectClass(t, file)), 0)); + t->exception = t->m->classpath->makeThrowable + (t, Machine::RuntimeExceptionType, message); + return 0; + } +} +#endif // AVIAN_OPENJDK_SRC + class MyClasspath : public Classpath { public: static const unsigned BufferSize = 1024; @@ -205,6 +277,14 @@ class MyClasspath : public Classpath { // todo: handle other architectures sb.append("/lib/i386"); #endif + sb.append('\0'); + + this->zipLibrary = sb.pointer; + sb.append(this->libraryPath); + sb.append("/"); + sb.append(LIBRARY_PREFIX); + sb.append("zip"); + sb.append(LIBRARY_SUFFIX); } virtual object @@ -296,9 +376,20 @@ class MyClasspath : public Classpath { { globalMachine = t->m; +#ifdef AVIAN_OPENJDK_SRC + { object c = resolveClass + (t, root(t, Machine::BootLoader), "java/io/UnixFileSystem"); + + if (c) { + intercept(t, c, "getBooleanAttributes0", "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); + } + } +#else // not AVIAN_OPENJDK_SRC if (loadLibrary(t, libraryPath, "java", true, true) == 0) { abort(t); } +#endif // not AVIAN_OPENJDK_SRC t->m->processor->invoke (t, root(t, Machine::BootLoader), "java/lang/System", @@ -351,6 +442,7 @@ class MyClasspath : public Classpath { const char* javaHome; const char* classpath; const char* libraryPath; + const char* zipLibrary; char buffer[BufferSize]; }; @@ -374,6 +466,12 @@ struct jvm_version_info { unsigned int: 32; }; +const char* +zipLibrary(Thread* t) +{ + return static_cast(t->m->classpath)->zipLibrary; +} + unsigned countMethods(Thread* t, object c, bool publicOnly) { @@ -1205,7 +1303,13 @@ extern "C" JNIEXPORT void* JNICALL JVM_LoadLibrary(const char* name) { Thread* t = static_cast(local::globalMachine->localThread->get()); - + +#ifdef AVIAN_OPENJDK_SRC + if (strcmp(local::zipLibrary(t), name) == 0) { + return t->m->libraries; + } +#endif // AVIAN_OPENJDK_SRC + ENTER(t, Thread::ActiveState); return loadLibrary @@ -2597,18 +2701,18 @@ jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) return vm::vsnprintf(dst, size, format, a); } -extern "C" JNIEXPORT int -jio_snprintf(char* dst, size_t size, const char* format, ...) -{ - va_list a; - va_start(a, format); +// extern "C" JNIEXPORT int +// jio_snprintf(char* dst, size_t size, const char* format, ...) +// { +// va_list a; +// va_start(a, format); - int r = jio_vsnprintf(dst, size, format, a); +// int r = jio_vsnprintf(dst, size, format, a); - va_end(a); +// va_end(a); - return r; -} +// return r; +// } extern "C" JNIEXPORT int jio_vfprintf(FILE* stream, const char* format, va_list a) @@ -2616,15 +2720,15 @@ jio_vfprintf(FILE* stream, const char* format, va_list a) return vfprintf(stream, format, a); } -extern "C" JNIEXPORT int -jio_fprintf(FILE* stream, const char* format, ...) -{ - va_list a; - va_start(a, format); +// extern "C" JNIEXPORT int +// jio_fprintf(FILE* stream, const char* format, ...) +// { +// va_list a; +// va_start(a, format); - int r = jio_vfprintf(stream, format, a); +// int r = jio_vfprintf(stream, format, a); - va_end(a); +// va_end(a); - return r; -} +// return r; +// } diff --git a/src/compile.cpp b/src/compile.cpp index e0b3ee8586..280cb3f2fc 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -8601,19 +8601,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, // method so that we won't be confused if another thread updates the // original while we're working. - object clone = makeMethod - (t, methodVmFlags(t, method), - methodReturnCode(t, method), - methodParameterCount(t, method), - methodParameterFootprint(t, method), - methodFlags(t, method), - methodOffset(t, method), - methodNativeID(t, method), - methodName(t, method), - methodSpec(t, method), - methodAddendum(t, method), - methodClass(t, method), - methodCode(t, method)); + object clone = methodClone(t, method); loadMemoryBarrier(); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 0e249d2aba..680992c4df 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1928,10 +1928,16 @@ RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, for (int i = 0; i < methodCount; ++i) { if (methods[i].function) { - object method = findMethod(t, c, methods[i].name, methods[i].signature); - if (UNLIKELY(t->exception)) return -1; + object method = findMethodOrNull + (t, jclassVmClass(t, *c), methods[i].name, methods[i].signature); - registerNative(t, method, methods[i].function); + if (method == 0 or (methodFlags(t, method) & ACC_NATIVE) == 0) { + // The JNI spec says we must throw a NoSuchMethodError in this + // case, but that would prevent using a code shrinker like + // ProGuard effectively. Instead, we just ignore it. + } else { + registerNative(t, method, methods[i].function); + } } } diff --git a/src/machine.cpp b/src/machine.cpp index b9e849f6b4..184649e0e5 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3546,9 +3546,8 @@ findInTable(Thread* t, object table, object name, object spec, } object -findInHierarchy(Thread* t, object class_, object name, object spec, - object (*find)(Thread*, object, object, object), - Machine::Type errorType) +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)) { object originalClass = class_; @@ -3570,15 +3569,6 @@ findInHierarchy(Thread* t, object class_, object name, object spec, } } - if (o == 0) { - object message = makeString - (t, "%s %s not found in %s", - &byteArrayBody(t, name, 0), - &byteArrayBody(t, spec, 0), - &byteArrayBody(t, className(t, originalClass), 0)); - t->exception = t->m->classpath->makeThrowable(t, errorType, message); - } - return o; } diff --git a/src/machine.h b/src/machine.h index 772bcd864c..1955adadb8 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2127,11 +2127,11 @@ object resolveClass(Thread* t, object loader, object name, bool throw_ = true); inline object -resolveClass(Thread* t, object loader, const char* name) +resolveClass(Thread* t, object loader, const char* name, bool throw_ = true) { PROTECT(t, loader); object n = makeByteArray(t, "%s", name); - return resolveClass(t, loader, n); + return resolveClass(t, loader, n, throw_); } object @@ -2211,6 +2211,16 @@ findFieldInClass(Thread* t, object class_, object name, object spec) (t, classFieldTable(t, class_), name, spec, fieldName, fieldSpec); } +inline object +findFieldInClass2(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findFieldInClass(t, class_, n, s); +} + inline object findMethodInClass(Thread* t, object class_, object name, object spec) { @@ -2219,9 +2229,27 @@ findMethodInClass(Thread* t, object class_, object name, object spec) } object +findInHierarchyOrNull(Thread* t, object class_, object name, object spec, + object (*find)(Thread*, object, object, object)); + +inline object findInHierarchy(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object), - Machine::Type errorType); + Machine::Type errorType) +{ + object o = findInHierarchyOrNull(t, class_, name, spec, find); + + if (o == 0) { + object message = makeString + (t, "%s %s not found in %s", + &byteArrayBody(t, name, 0), + &byteArrayBody(t, spec, 0), + &byteArrayBody(t, className(t, class_), 0)); + t->exception = t->m->classpath->makeThrowable(t, errorType, message); + } + + return o; +} inline object findMethod(Thread* t, object class_, object name, object spec) @@ -2230,6 +2258,16 @@ findMethod(Thread* t, object class_, object name, object spec) (t, class_, name, spec, findMethodInClass, Machine::NoSuchMethodErrorType); } +inline object +findMethodOrNull(Thread* t, object class_, const char* name, const char* spec) +{ + PROTECT(t, class_); + object n = makeByteArray(t, "%s", name); + PROTECT(t, n); + object s = makeByteArray(t, "%s", spec); + return findInHierarchyOrNull(t, class_, n, s, findMethodInClass); +} + inline object findVirtualMethod(Thread* t, object method, object class_) { @@ -3066,6 +3104,24 @@ defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length); void dumpHeap(Thread* t, FILE* out); +inline object +methodClone(Thread* t, object method) +{ + return makeMethod + (t, methodVmFlags(t, method), + methodReturnCode(t, method), + methodParameterCount(t, method), + methodParameterFootprint(t, method), + methodFlags(t, method), + methodOffset(t, method), + methodNativeID(t, method), + methodName(t, method), + methodSpec(t, method), + methodAddendum(t, method), + methodClass(t, method), + methodCode(t, method)); +} + } // namespace vm void diff --git a/src/openjdk/jni_md.h b/src/openjdk/jni_md.h new file mode 100644 index 0000000000..3ddc8b9460 --- /dev/null +++ b/src/openjdk/jni_md.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2010, 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. */ + +#ifndef JNI_MD_H +#define JNI_MD_H + +#include "stdint.h" + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __declspec(dllexport) +#else // not (defined __MINGW32__) || (defined _MSC_VER) +# define JNIEXPORT __attribute__ ((visibility("default"))) +#endif // not (defined __MINGW32__) || (defined _MSC_VER) + +#define JNIIMPORT +#define JNICALL + +typedef int32_t jint; +typedef int64_t jlong; +typedef int8_t jbyte; + +#endif//JNI_MD_H diff --git a/src/types.def b/src/types.def index 996b99e377..158483115a 100644 --- a/src/types.def +++ b/src/types.def @@ -44,6 +44,10 @@ (void* function) (uint8_t fast)) +(type nativeIntercept + (extends native) + (object original)) + (pod exceptionHandler (uint16_t start) (uint16_t end) From 4cb796d2fb46bec73caf8978a48bfe1dc7e9f5b9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 4 Nov 2010 11:43:50 -0600 Subject: [PATCH 078/274] only return null from JVM_GetClassLoader when called from Unsafe.getUnsafe sun.misc.Unsafe.getUnsafe expects a null result if the class loader is the boot classloader and will throw a SecurityException otherwise (whereas it should really be checking both for null and comparing against the system classloader). However, just returning null whenever the loader is the boot loader can cause trouble for embedded apps which put everything in the boot loader, including application resources. Therefore, we only return null if it's the boot loader and we're being called from Unsafe.getUnsafe. --- src/classpath-openjdk.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 5dd2c32c68..c6f6949380 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -391,9 +391,8 @@ class MyClasspath : public Classpath { } #endif // not AVIAN_OPENJDK_SRC - t->m->processor->invoke - (t, root(t, Machine::BootLoader), "java/lang/System", - "initializeSystemClass", "()V", 0); + resolveSystemClass(t, root(t, Machine::BootLoader), + className(t, type(t, Machine::ClassLoaderType))); if (UNLIKELY(t->exception)) return; object constructor = resolveMethod @@ -424,6 +423,10 @@ class MyClasspath : public Classpath { cast(classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, sclSet)) = true; + + t->m->processor->invoke + (t, root(t, Machine::BootLoader), "java/lang/System", + "initializeSystemClass", "()V", 0); } virtual const char* @@ -1781,8 +1784,24 @@ JVM_GetClassLoader(Thread* t, jclass c) ENTER(t, Thread::ActiveState); object loader = classLoader(t, jclassVmClass(t, *c)); - return loader == root(t, Machine::BootLoader) - ? 0 : makeLocalReference(t, loader); + + if (loader == root(t, Machine::BootLoader)) { + // sun.misc.Unsafe.getUnsafe expects a null result if the class + // loader is the boot classloader and will throw a + // SecurityException otherwise. + object caller = getCaller(t, 2); + if (caller and strcmp + (reinterpret_cast + (&byteArrayBody(t, className(t, methodClass(t, caller)), 0)), + "sun/misc/Unsafe") == 0) + { + return 0; + } else { + return makeLocalReference(t, root(t, Machine::BootLoader)); + } + } else { + return makeLocalReference(t, loader); + } } extern "C" JNIEXPORT jboolean JNICALL From d0a6096eb0452480a8612b4cb8a61379d1dc7936 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 5 Nov 2010 13:18:28 -0600 Subject: [PATCH 079/274] add support for accessing embedded JARs as if they were directories This allows OpenJDK to access time zone data which is normally found under java.home, but which we must embed in the executable itself to create a self-contained build. The VM intercepts various file operations, looking for paths which start with a prefix specified by the avian.embed.prefix property and redirecting those operations to an embedded JAR. For example, if avian.embed.prefix is "/avian-embedded", and code calls File.exists() with a path of "/avian-embedded/javahomeJar/foo.txt", the VM looks for a function named javahomeJar via dlsym, calls the function to find the memory region containing the embeded JAR, and finally consults the JAR to see if the file "foo.txt" exists. --- makefile | 53 ++-- src/boot.cpp | 30 +++ src/builtin.cpp | 5 +- src/classpath-avian.cpp | 2 +- src/classpath-openjdk.cpp | 510 +++++++++++++++++++++++++++++++------- src/compile.cpp | 2 +- src/finder.cpp | 269 +++++++++++++------- src/finder.h | 10 +- src/jnienv.cpp | 12 +- src/machine.cpp | 21 +- src/machine.h | 9 +- src/posix.cpp | 8 +- src/system.h | 2 +- src/type-generator.cpp | 26 +- src/types.def | 9 + src/util.cpp | 21 +- src/util.h | 3 + test/Misc.java | 2 + 18 files changed, 773 insertions(+), 221 deletions(-) diff --git a/makefile b/makefile index edaecb7ff8..5214d37f0e 100644 --- a/makefile +++ b/makefile @@ -52,25 +52,29 @@ classpath = avian test-executable = $(executable) boot-classpath = $(classpath-build) -java-home = /avian-embedded +embed-prefix = /avian-embedded ifdef openjdk ifdef openjdk-src include openjdk-src.mk options := $(options)-openjdk-src classpath-objects = $(openjdk-objects) - classpath-cflags = -DAVIAN_OPENJDK_SRC + classpath-cflags = -DAVIAN_OPENJDK_SRC -DBOOT_JAVAHOME openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) + javahome = $(embed-prefix)/javahomeJar + javahome-files = lib/zi + javahome-object = $(build)/javahome-jar.o else options := $(options)-openjdk test-executable = $(executable-dynamic) library-path = LD_LIBRARY_PATH=$(build) - java-home = $(openjdk)/jre + javahome = $(openjdk)/jre endif classpath = openjdk boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar + build-javahome = $(openjdk)/jre endif ifeq ($(classpath),avian) @@ -120,7 +124,8 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(java-home)\" + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread @@ -593,12 +598,6 @@ $(driver-dynamic-object): $(driver-source) $(boot-object): $(boot-source) $(compile-object) -$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) - @echo "creating $(@)" - (wd=$$(pwd) && \ - cd $(classpath-build) && \ - $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) - $(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build-cxx) -c $(^) -o $(@) @@ -620,11 +619,28 @@ $(build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp $(converter): $(converter-objects) $(build-cxx) $(^) -o $(@) +$(build)/classpath.jar: $(classpath-dep) $(classpath-jar-dep) + @echo "creating $(@)" + (wd=$$(pwd) && \ + cd $(classpath-build) && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" .) + $(classpath-object): $(build)/classpath.jar $(converter) @echo "creating $(@)" $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) +$(build)/javahome.jar: $(foreach x,$(javahome-files),$(build-javahome)/$(x)) + @echo "creating $(@)" + (wd=$$(pwd) && \ + cd $(build-javahome) && \ + $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $(javahome-files)) + +$(javahome-object): $(build)/javahome.jar $(converter) + @echo "creating $(@)" + $(converter) $(<) $(@) _binary_javahome_jar_start \ + _binary_javahome_jar_end $(platform) $(arch) + $(generator-objects): $(generator-depends) $(generator-objects): $(build)/%-build.o: $(src)/%.cpp @echo "compiling $(@)" @@ -651,7 +667,8 @@ $(bootimage-object): $(bootimage-bin) $(converter) writable executable executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ - $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ + $(javahome-object) $(executable): $(executable-objects) @echo "linking $(@)" @@ -696,18 +713,16 @@ else $(ld) $(^) $(rdynamic) $(lflags) -o $(@) endif -dynamic-library-objects = $(vm-objects) $(dynamic-object) \ - $(classpath-objects) $(vm-heapwalk-objects) $(boot-object) \ - $(vm-classpath-object) $(classpath-libraries) - -$(dynamic-library): $(dynamic-library-objects) +$(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ + $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ + $(classpath-libraries) $(javahome-object) @echo "linking $(@)" ifdef msvc - $(ld) $(shared) $(lflags) $(dynamic-library-objects) -out:$(@) \ - -PDB:$(@).pdb -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest + $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ + -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(dynamic-library-objects) -Wl,--version-script=openjdk.ld \ + $(ld) $(^) -Wl,--version-script=openjdk.ld \ $(shared) $(lflags) $(bootimage-lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/src/boot.cpp b/src/boot.cpp index 186cf4745f..f6a1cd8d20 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -52,6 +52,8 @@ extern "C" { } +#undef SYMBOL + #endif//BOOT_IMAGE #ifdef BOOT_CLASSPATH @@ -76,4 +78,32 @@ extern "C" { } +#undef SYMBOL + #endif//BOOT_CLASSPATH + +#ifdef BOOT_JAVAHOME + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define SYMBOL(x) binary_javahome_jar_##x +#else +# define SYMBOL(x) _binary_javahome_jar_##x +#endif + +extern "C" { + + extern const uint8_t SYMBOL(start)[]; + extern const uint8_t SYMBOL(end)[]; + + EXPORT const uint8_t* + javahomeJar(unsigned* size) + { + *size = SYMBOL(end) - SYMBOL(start); + return SYMBOL(start); + } + +} + +#undef SYMBOL + +#endif//BOOT_JAVAHOME diff --git a/src/builtin.cpp b/src/builtin.cpp index f113bd5ead..75de37c759 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -85,8 +85,9 @@ Avian_avian_SystemClassLoader_resourceExists RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); - bool r = static_cast(systemClassLoaderFinder(t, loader))->exists - (RUNTIME_ARRAY_BODY(n)); + unsigned length; + bool r = static_cast(systemClassLoaderFinder(t, loader))->stat + (RUNTIME_ARRAY_BODY(n), &length) == System::TypeFile; // fprintf(stderr, "resource %s exists? %d\n", n, r); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 13bbf44f41..aacfb7e9d5 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -128,7 +128,7 @@ enumerateThreads(Thread* t, Thread* x, object array, unsigned* index, namespace vm { Classpath* -makeClasspath(System*, Allocator* allocator, const char*) +makeClasspath(System*, Allocator* allocator, const char*, const char*) { return new (allocator->allocate(sizeof(local::MyClasspath))) local::MyClasspath(allocator); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c6f6949380..f3eb91ec59 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -88,6 +88,7 @@ namespace local { const unsigned InterfaceVersion = 4; const unsigned PageSize = 4 * 1024; +const int VirtualFileBase = 1000000000; Machine* globalMachine; @@ -145,7 +146,6 @@ makeClassNameString(Thread* t, object name) return makeString(t, "%s", s); } -#ifdef AVIAN_OPENJDK_SRC // only safe to call during bootstrap when there's only one thread // running: void @@ -171,51 +171,20 @@ intercept(Thread* t, object c, const char* name, const char* spec, } } -const char* -zipLibrary(Thread*); - int64_t JNICALL getFileAttributes -(Thread* t, object method, uintptr_t* arguments) -{ - const unsigned Exists = 1; - const unsigned Regular = 2; +(Thread* t, object method, uintptr_t* arguments); - object file = reinterpret_cast(arguments[1]); - - object pathField = findFieldInClass2 - (t, objectClass(t, file), "path", "Ljava/lang/String;"); - - if (pathField) { - object path = cast(file, fieldOffset(t, pathField)); - - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); - stringChars(t, path, RUNTIME_ARRAY_BODY(p)); - - if (strcmp(zipLibrary(t), p) == 0) { - return Exists | Regular; - } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), - reinterpret_cast(arguments[0]), file); - return (r ? intValue(t, r) : 0); - } - } else { - object message = makeString - (t, "path Ljava/lang/String; not found in %s", - &byteArrayBody(t, className(t, objectClass(t, file)), 0)); - t->exception = t->m->classpath->makeThrowable - (t, Machine::RuntimeExceptionType, message); - return 0; - } -} -#endif // AVIAN_OPENJDK_SRC +int64_t JNICALL +getLength +(Thread* t, object method, uintptr_t* arguments); class MyClasspath : public Classpath { public: static const unsigned BufferSize = 1024; - MyClasspath(System* s, Allocator* allocator, const char* javaHome): + MyClasspath(System* s, Allocator* allocator, const char* javaHome, + const char* embedPrefix): allocator(allocator) { class StringBuilder { @@ -285,6 +254,11 @@ class MyClasspath : public Classpath { sb.append(LIBRARY_PREFIX); sb.append("zip"); sb.append(LIBRARY_SUFFIX); + sb.append('\0'); + + this->embedPrefix = sb.pointer; + sb.append(embedPrefix); + this->embedPrefixLength = sb.pointer - this->embedPrefix; } virtual object @@ -377,13 +351,32 @@ class MyClasspath : public Classpath { globalMachine = t->m; #ifdef AVIAN_OPENJDK_SRC - { object c = resolveClass + { object ufsClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/UnixFileSystem"); - if (c) { - intercept(t, c, "getBooleanAttributes0", "(Ljava/io/File;)I", - voidPointer(getFileAttributes)); + if (ufsClass) { + PROTECT(t, ufsClass); + + object fileClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/File"); + + if (fileClass) { + object pathField = findFieldInClass2 + (t, fileClass, "path", "Ljava/lang/String;"); + + if (pathField) { + this->pathField = fieldOffset(t, pathField); + + intercept(t, ufsClass, "getBooleanAttributes0", + "(Ljava/io/File;)I", voidPointer(getFileAttributes)); + + intercept(t, ufsClass, "getLength", "(Ljava/io/File;)J", + voidPointer(getLength)); + } + } } + + if (UNLIKELY(t->exception)) return; } #else // not AVIAN_OPENJDK_SRC if (loadLibrary(t, libraryPath, "java", true, true) == 0) { @@ -437,7 +430,7 @@ class MyClasspath : public Classpath { virtual void dispose() - { + { allocator->free(this, sizeof(*this)); } @@ -446,33 +439,202 @@ class MyClasspath : public Classpath { const char* classpath; const char* libraryPath; const char* zipLibrary; + const char* embedPrefix; + unsigned embedPrefixLength; + unsigned pathField; char buffer[BufferSize]; }; -struct JVM_ExceptionTableEntryType{ - jint start_pc; - jint end_pc; - jint handler_pc; - jint catchType; +struct JVM_ExceptionTableEntryType { + jint start_pc; + jint end_pc; + jint handler_pc; + jint catchType; }; struct jvm_version_info { - unsigned int jvm_version; - unsigned int update_version: 8; - unsigned int special_update_version: 8; - unsigned int reserved1: 16; - unsigned int reserved2; - unsigned int is_attach_supported: 1; - unsigned int is_kernel_jvm: 1; - unsigned int: 30; - unsigned int: 32; - unsigned int: 32; + unsigned jvm_version; + unsigned update_version: 8; + unsigned special_update_version: 8; + unsigned reserved1: 16; + unsigned reserved2; + unsigned is_attach_supported: 1; + unsigned is_kernel_jvm: 1; + unsigned: 30; + unsigned: 32; + unsigned: 32; }; -const char* -zipLibrary(Thread* t) +Finder* +getFinder(Thread* t, const char* name, unsigned nameLength) { - return static_cast(t->m->classpath)->zipLibrary; + ACQUIRE(t, t->m->referenceLock); + + for (object p = root(t, Machine::VirtualFileFinders); + p; p = finderNext(t, p)) + { + if (byteArrayLength(t, finderName(t, p)) == nameLength + and strncmp(reinterpret_cast + (&byteArrayBody(t, finderName(t, p), 0)), + name, nameLength)) + { + return static_cast(finderFinder(t, p)); + } + } + + object n = makeByteArray(t, nameLength + 1); + memcpy(&byteArrayBody(t, n, 0), name, nameLength); + + void* p = t->m->libraries->resolve + (reinterpret_cast(&byteArrayBody(t, n, 0))); + if (p) { + uint8_t* (*function)(unsigned*); + memcpy(&function, &p, BytesPerWord); + + unsigned size; + uint8_t* data = function(&size); + if (data) { + Finder* f = makeFinder(t->m->system, t->m->heap, data, size); + object finder = makeFinder + (t, f, n, root(t, Machine::VirtualFileFinders)); + + setRoot(t, Machine::VirtualFileFinders, finder); + + return f; + } + } + + return 0; +} + +class EmbeddedFile { + public: + EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) { + if (strncmp(cp->embedPrefix, path, cp->embedPrefixLength) == 0) { + const char* p = path + cp->embedPrefixLength; + while (*p == '/') ++ p; + + this->jar = p; + + if (*p == 0) { + this->jarLength = 0; + this->path = 0; + this->pathLength = 0; + return; + } + + while (*p and *p != '/') ++p; + + this->jarLength = p - this->jar; + + while (*p == '/') ++p; + + this->path = p; + this->pathLength = pathLength - (p - path); + } else { + this->jar = 0; + this->jarLength =0; + this->path = 0; + this->pathLength = 0; + } + } + + const char* jar; + const char* path; + unsigned jarLength; + unsigned pathLength; +}; + +int64_t JNICALL +getFileAttributes +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Exists = 1; + const unsigned Regular = 2; + const unsigned Directory = 4; + + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + object path = cast(file, cp->pathField); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + + if (strcmp(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) == 0) { + return Exists | Regular; + } else { + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return Exists | Directory; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return Exists | Directory; + } + + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeUnknown: return Exists; + case System::TypeDoesNotExist: return 0; + case System::TypeFile: return Exists | Regular; + case System::TypeDirectory: return Exists | Directory; + default: abort(t); + } + } else { + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), + reinterpret_cast(arguments[0]), file); + + return (r ? intValue(t, r) : 0); + } + } +} + +int64_t JNICALL +getLength +(Thread* t, object method, uintptr_t* arguments) +{ + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + object path = cast(file, cp->pathField); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return 0; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return 0; + } + + unsigned fileLength; + finder->stat(ef.path, &fileLength); + return fileLength; + } + + return 0; + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), + reinterpret_cast(arguments[0]), file); + + return (r ? longValue(t, r) : 0); + } } unsigned @@ -735,10 +897,11 @@ interruptLock(Thread* t, object thread) namespace vm { Classpath* -makeClasspath(System* s, Allocator* allocator, const char* javaHome) +makeClasspath(System* s, Allocator* allocator, const char* javaHome, + const char* embedPrefix) { return new (allocator->allocate(sizeof(local::MyClasspath))) - local::MyClasspath(s, allocator, javaHome); + local::MyClasspath(s, allocator, javaHome, embedPrefix); } } // namespace vm @@ -1308,7 +1471,9 @@ JVM_LoadLibrary(const char* name) Thread* t = static_cast(local::globalMachine->localThread->get()); #ifdef AVIAN_OPENJDK_SRC - if (strcmp(local::zipLibrary(t), name) == 0) { + if (strcmp(static_cast(t->m->classpath)->zipLibrary, + name) == 0) + { return t->m->libraries; } #endif // AVIAN_OPENJDK_SRC @@ -2475,21 +2640,126 @@ JVM_NativePath(char* path) } extern "C" JNIEXPORT jint JNICALL -JVM_Open(const char* name, jint flags, jint mode) +JVM_Open(const char* path, jint flags, jint mode) { - return OPEN(name, flags, mode); + Thread* t = static_cast(local::globalMachine->localThread->get()); + local::MyClasspath* cp = static_cast(t->m->classpath); + + local::EmbeddedFile ef(cp, path, strlen(path)); + if (ef.jar) { + if (flags != O_RDONLY) { + errno = EACCES; + return -1; + } + + if (ef.jarLength == 0 or ef.pathLength == 0) { + errno = ENOENT; + return -1; + } + + Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + errno = ENOENT; + return -1; + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + errno = ENOENT; + return -1; + } + + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->referenceLock); + + int index = -1; + unsigned oldLength = root(t, Machine::VirtualFiles) + ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; + + for (unsigned i = 0; i < oldLength; ++i) { + if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { + index = i; + break; + } + } + + if (index == -1) { + object newArray = growArray(t, root(t, Machine::VirtualFiles)); + setRoot(t, Machine::VirtualFiles, newArray); + index = oldLength; + } + + object region = makeRegion(t, r, 0); + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + region); + + return index + local::VirtualFileBase; + } else { + int r = OPEN(path, flags, mode); + expect(t, r < local::VirtualFileBase); + return r; + } } extern "C" JNIEXPORT jint JNICALL JVM_Close(jint fd) { - return CLOSE(fd); + if (fd >= local::VirtualFileBase) { + Thread* t = static_cast(local::globalMachine->localThread->get()); + unsigned index = fd - local::VirtualFileBase; + + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + if (region) { + static_cast(regionRegion(t, region))->dispose(); + } + + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + 0); + + return 0; + } else { + return CLOSE(fd); + } } extern "C" JNIEXPORT jint JNICALL JVM_Read(jint fd, char* dst, jint length) { - return READ(fd, dst, length); + if (fd >= local::VirtualFileBase) { + Thread* t = static_cast(local::globalMachine->localThread->get()); + unsigned index = fd - local::VirtualFileBase; + + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + int available = r->length() - regionPosition(t, region); + if (length > available) { + length = available; + } + + memcpy(dst, r->start(), length); + + regionPosition(t, region) += length; + + return length; + } else { + errno = EINVAL; + return -1; + } + } else { + return READ(fd, dst, length); + } } extern "C" JNIEXPORT jint JNICALL @@ -2501,34 +2771,94 @@ JVM_Write(jint fd, char* src, jint length) extern "C" JNIEXPORT jint JNICALL JVM_Available(jint fd, jlong* result) { - struct stat buffer; - int n; - if (FSTAT(fd, &buffer) >= 0 - and (S_ISCHR(buffer.st_mode) - or S_ISFIFO(buffer.st_mode) - or S_ISSOCK(buffer.st_mode)) - and ioctl(fd, FIONREAD, &n) >= 0) - { - *result = n; + if (fd >= local::VirtualFileBase) { + Thread* t = static_cast(local::globalMachine->localThread->get()); + unsigned index = fd - local::VirtualFileBase; + + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + if (region) { + return static_cast(regionRegion(t, region))->length() + - regionPosition(t, region); + } else { + return 0; + } + } else { + struct stat buffer; + int n; + if (FSTAT(fd, &buffer) >= 0 + and (S_ISCHR(buffer.st_mode) + or S_ISFIFO(buffer.st_mode) + or S_ISSOCK(buffer.st_mode)) + and ioctl(fd, FIONREAD, &n) >= 0) + { + *result = n; + return 1; + } + + int current = LSEEK(fd, 0, SEEK_CUR); + if (current == -1) return 0; + + int end = LSEEK(fd, 0, SEEK_END); + if (end == -1) return 0; + + if (LSEEK(fd, current, SEEK_SET) == -1) return 0; + + *result = end - current; return 1; } - - int current = LSEEK(fd, 0, SEEK_CUR); - if (current == -1) return 0; - - int end = LSEEK(fd, 0, SEEK_END); - if (end == -1) return 0; - - if (LSEEK(fd, current, SEEK_SET) == -1) return 0; - - *result = end - current; - return 1; } extern "C" JNIEXPORT jlong JNICALL -JVM_Lseek(jint fd, jlong offset, jint start) +JVM_Lseek(jint fd, jlong offset, jint seek) { - return LSEEK(fd, offset, start); + if (fd >= local::VirtualFileBase) { + Thread* t = static_cast(local::globalMachine->localThread->get()); + unsigned index = fd - local::VirtualFileBase; + + ENTER(t, Thread::ActiveState); + + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + switch (seek) { + case SEEK_SET: + break; + + case SEEK_CUR: + offset += regionPosition(t, region); + break; + + case SEEK_END: + offset += r->length(); + break; + + default: + errno = EINVAL; + return -1; + } + + if (offset >= 0 and offset <= static_cast(r->length())) { + regionPosition(t, region) = offset; + return offset; + } else { + errno = EINVAL; + return -1; + } + } else { + errno = EINVAL; + return -1; + } + } else { + return LSEEK(fd, offset, seek); + } } extern "C" JNIEXPORT jint JNICALL diff --git a/src/compile.cpp b/src/compile.cpp index 280cb3f2fc..b9858a1b71 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7156,7 +7156,7 @@ class SegFaultHandler: public System::SignalHandler { t->exception = root(t, Machine::NullPointerException); } -// printTrace(t, t->exception); + printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, base, stack, &continuation); diff --git a/src/finder.cpp b/src/finder.cpp index 4e0fa64166..17e9078243 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -20,12 +20,12 @@ namespace { const bool DebugFind = false; const char* -append(System* s, const char* a, const char* b, const char* c) +append(Allocator* allocator, const char* a, const char* b, const char* c) { unsigned al = strlen(a); unsigned bl = strlen(b); unsigned cl = strlen(c); - char* p = static_cast(allocate(s, (al + bl + cl) + 1)); + char* p = static_cast(allocator->allocate((al + bl + cl) + 1)); memcpy(p, a, al); memcpy(p + al, b, bl); memcpy(p + al + bl, c, cl + 1); @@ -33,10 +33,10 @@ append(System* s, const char* a, const char* b, const char* c) } const char* -copy(System* s, const char* a) +copy(Allocator* allocator, const char* a) { unsigned al = strlen(a); - char* p = static_cast(allocate(s, al + 1)); + char* p = static_cast(allocator->allocate(al + 1)); memcpy(p, a, al + 1); return p; } @@ -63,7 +63,8 @@ class Element { virtual Iterator* iterator() = 0; virtual System::Region* find(const char* name) = 0; - virtual bool exists(const char* name) = 0; + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) = 0; virtual void dispose() = 0; Element* next; @@ -73,8 +74,9 @@ class DirectoryElement: public Element { public: class Iterator: public Element::Iterator { public: - Iterator(System* s, const char* name, unsigned skip): - s(s), name(name), skip(skip), directory(0), last(0), it(0) + Iterator(System* s, Allocator* allocator, const char* name, unsigned skip): + s(s), allocator(allocator), name(name), skip(skip), directory(0), + last(0), it(0) { if (not s->success(s->open(&directory, name))) { directory = 0; @@ -93,15 +95,17 @@ class DirectoryElement: public Element { } if (last) { - s->free(last); + allocator->free(last, strlen(last) + 1); } if (directory) { for (const char* v = directory->next(); v; v = directory->next()) { if (v[0] != '.') { - last = append(s, name, "/", v); - if (s->identify(last) == System::TypeDirectory) { - it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip); + last = append(allocator, name, "/", v); + unsigned length; + if (s->stat(last, &length) == System::TypeDirectory) { + it = new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, last, skip); it->name = last; } const char* result = last + skip; @@ -116,10 +120,11 @@ class DirectoryElement: public Element { virtual void dispose() { directory->dispose(); - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const char* name; unsigned skip; System::Directory* directory; @@ -127,20 +132,20 @@ class DirectoryElement: public Element { Iterator* it; }; - DirectoryElement(System* s, const char* name): - s(s), name(name) + DirectoryElement(System* s, Allocator* allocator, const char* name): + s(s), allocator(allocator), name(name) { } virtual Element::Iterator* iterator() { - return new (allocate(s, sizeof(Iterator))) - Iterator(s, name, strlen(name) + 1); + return new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, name, strlen(name) + 1); } virtual System::Region* find(const char* name) { - const char* file = append(s, this->name, "/", name); + const char* file = append(allocator, this->name, "/", name); System::Region* region; System::Status status = s->map(®ion, file); - s->free(file); + allocator->free(file, strlen(file) + 1); if (s->success(status)) { if (DebugFind) { @@ -155,26 +160,29 @@ class DirectoryElement: public Element { } } - virtual bool exists(const char* name) { - const char* file = append(s, this->name, "/", name); - System::FileType type = s->identify(file); - s->free(file); - return type != System::TypeDoesNotExist; + virtual System::FileType stat(const char* name, unsigned* length, bool) { + const char* file = append(allocator, this->name, "/", name); + System::FileType type = s->stat(file, length); + allocator->free(file, strlen(file) + 1); + return type; } virtual void dispose() { - s->free(name); - s->free(this); + allocator->free(name, strlen(name) + 1); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const char* name; }; class PointerRegion: public System::Region { public: - PointerRegion(System* s, const uint8_t* start, size_t length): + PointerRegion(System* s, Allocator* allocator, const uint8_t* start, + size_t length): s(s), + allocator(allocator), start_(start), length_(length) { } @@ -188,18 +196,20 @@ class PointerRegion: public System::Region { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; const uint8_t* start_; size_t length_; }; class DataRegion: public System::Region { public: - DataRegion(System* s, size_t length): + DataRegion(System* s, Allocator* allocator, size_t length): s(s), + allocator(allocator), length_(length) { } @@ -212,10 +222,11 @@ class DataRegion: public System::Region { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; size_t length_; uint8_t data[0]; }; @@ -241,11 +252,12 @@ class JarIndex { Node* next; }; - JarIndex(System* s, unsigned capacity): + JarIndex(System* s, Allocator* allocator, unsigned capacity): s(s), + allocator(allocator), capacity(capacity), position(0), - nodes(static_cast(allocate(s, sizeof(Node) * capacity))) + nodes(static_cast(allocator->allocate(sizeof(Node) * capacity))) { memset(table, 0, sizeof(Node*) * capacity); } @@ -322,14 +334,16 @@ class JarIndex { commentFieldLength(p); } - static JarIndex* make(System* s, unsigned capacity) { + static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) { return new - (allocate(s, sizeof(JarIndex) + (sizeof(Node*) * capacity))) - JarIndex(s, capacity); + (allocator->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity))) + JarIndex(s, allocator, capacity); } - static JarIndex* open(System* s, System::Region* region) { - JarIndex* index = make(s, 32); + static JarIndex* open(System* s, Allocator* allocator, + System::Region* region) + { + JarIndex* index = make(s, allocator, 32); const uint8_t* start = region->start(); const uint8_t* end = start + region->length(); @@ -362,7 +376,7 @@ class JarIndex { table[i] = new (nodes + (position++)) Node(hash, entry, table[i]); return this; } else { - JarIndex* index = make(s, capacity * 2); + JarIndex* index = make(s, allocator, capacity * 2); for (unsigned i = 0; i < capacity; ++i) { index->add(nodes[i].hash, nodes[i].entry); } @@ -390,15 +404,15 @@ class JarIndex { const uint8_t* p = n->entry; switch (compressionMethod(p)) { case Stored: { - return new (allocate(s, sizeof(PointerRegion))) - PointerRegion(s, fileData(start + localHeaderOffset(p)), + return new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, fileData(start + localHeaderOffset(p)), compressedSize(p)); } break; case Deflated: { DataRegion* region = new - (allocate(s, sizeof(DataRegion) + uncompressedSize(p))) - DataRegion(s, uncompressedSize(p)); + (allocator->allocate(sizeof(DataRegion) + uncompressedSize(p))) + DataRegion(s, allocator, uncompressedSize(p)); z_stream zStream; memset(&zStream, 0, sizeof(z_stream)); @@ -428,16 +442,41 @@ class JarIndex { return 0; } - bool exists(const char* name) { - return findNode(name) != 0; + System::FileType stat(const char* name, unsigned* length, bool tryDirectory) + { + Node* node = findNode(name); + if (node) { + *length = uncompressedSize(node->entry); + return System::TypeFile; + } else if (tryDirectory) { + *length = 0; + + // try again with '/' appended + unsigned length = strlen(name); + RUNTIME_ARRAY(char, n, length + 2); + memcpy(RUNTIME_ARRAY_BODY(n), name, length); + RUNTIME_ARRAY_BODY(n)[length] = '/'; + RUNTIME_ARRAY_BODY(n)[length + 1] = 0; + + node = findNode(n); + if (node) { + return System::TypeDirectory; + } else { + return System::TypeDoesNotExist; + } + } else { + *length = 0; + return System::TypeDoesNotExist; + } } void dispose() { - s->free(nodes); - s->free(this); + allocator->free(nodes, sizeof(Node) * capacity); + allocator->free(this, sizeof(*this) + (sizeof(Node*) * capacity)); } System* s; + Allocator* allocator; unsigned capacity; unsigned position; @@ -449,7 +488,9 @@ class JarElement: public Element { public: class Iterator: public Element::Iterator { public: - Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { } + Iterator(System* s, Allocator* allocator, JarIndex* index): + s(s), allocator(allocator), index(index), position(0) + { } virtual const char* next(unsigned* size) { if (position < index->position) { @@ -462,22 +503,34 @@ class JarElement: public Element { } virtual void dispose() { - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; JarIndex* index; unsigned position; }; - JarElement(System* s, const char* name): - s(s), name(name), region(0), index(0) + JarElement(System* s, Allocator* allocator, const char* name): + s(s), allocator(allocator), name(name), region(0), index(0) + { } + + JarElement(System* s, Allocator* allocator, const uint8_t* jarData, + unsigned jarLength): + s(s), + allocator(allocator), + name(0), + region(new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, jarData, jarLength)), + index(JarIndex::open(s, allocator, region)) { } virtual Element::Iterator* iterator() { init(); - return new (allocate(s, sizeof(Iterator))) Iterator(s, index); + return new (allocator->allocate(sizeof(Iterator))) + Iterator(s, allocator, index); } virtual void init() { @@ -485,7 +538,7 @@ class JarElement: public Element { System::Region* r; if (s->success(s->map(&r, name))) { region = r; - index = JarIndex::open(s, r); + index = JarIndex::open(s, allocator, r); } } } @@ -506,26 +559,34 @@ class JarElement: public Element { return r; } - virtual bool exists(const char* name) { + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) + { init(); while (*name == '/') name++; - return (index ? index->exists(name) : 0); + return (index ? index->stat(name, length, tryDirectory) + : System::TypeDoesNotExist); } virtual void dispose() { - s->free(name); + dispose(sizeof(*this)); + } + + virtual void dispose(unsigned size) { + allocator->free(name, strlen(name) + 1); if (index) { index->dispose(); } if (region) { region->dispose(); } - s->free(this); + allocator->free(this, size); } System* s; + Allocator* allocator; const char* name; System::Region* region; JarIndex* index; @@ -533,9 +594,10 @@ class JarElement: public Element { class BuiltinElement: public JarElement { public: - BuiltinElement(System* s, const char* name, const char* libraryName): - JarElement(s, name), - libraryName(libraryName ? copy(s, libraryName) : 0) + BuiltinElement(System* s, Allocator* allocator, const char* name, + const char* libraryName): + JarElement(s, allocator, name), + libraryName(libraryName ? copy(allocator, libraryName) : 0) { } virtual void init() { @@ -549,9 +611,9 @@ class BuiltinElement: public JarElement { unsigned size; uint8_t* data = function(&size); if (data) { - region = new (allocate(s, sizeof(PointerRegion))) - PointerRegion(s, data, size); - index = JarIndex::open(s, region); + region = new (allocator->allocate(sizeof(PointerRegion))) + PointerRegion(s, allocator, data, size); + index = JarIndex::open(s, allocator, region); } } } @@ -560,8 +622,10 @@ class BuiltinElement: public JarElement { virtual void dispose() { library->disposeAll(); - s->free(libraryName); - JarElement::dispose(); + if (libraryName) { + allocator->free(libraryName, strlen(libraryName) + 1); + } + JarElement::dispose(sizeof(*this)); } System::Library* library; @@ -569,7 +633,8 @@ class BuiltinElement: public JarElement { }; Element* -parsePath(System* s, const char* path, const char* bootLibrary) +parsePath(System* s, Allocator* allocator, const char* path, + const char* bootLibrary) { Element* first = 0; Element* prev = 0; @@ -578,29 +643,31 @@ parsePath(System* s, const char* path, const char* bootLibrary) Element* e; if (*token.s == '[' and token.s[token.length - 1] == ']') { - char* name = static_cast(allocate(s, token.length - 1)); + char* name = static_cast(allocator->allocate(token.length - 1)); memcpy(name, token.s + 1, token.length - 1); name[token.length - 2] = 0; - e = new (allocate(s, sizeof(BuiltinElement))) - BuiltinElement(s, name, bootLibrary); + e = new (allocator->allocate(sizeof(BuiltinElement))) + BuiltinElement(s, allocator, name, bootLibrary); } else { - char* name = static_cast(allocate(s, token.length + 1)); + char* name = static_cast(allocator->allocate(token.length + 1)); memcpy(name, token.s, token.length); name[token.length] = 0; - switch (s->identify(name)) { + unsigned length; + switch (s->stat(name, &length)) { case System::TypeFile: { - e = new (allocate(s, sizeof(JarElement))) JarElement(s, name); + e = new (allocator->allocate(sizeof(JarElement))) + JarElement(s, allocator, name); } break; case System::TypeDirectory: { - e = new (allocate(s, sizeof(DirectoryElement))) - DirectoryElement(s, name); + e = new (allocator->allocate(sizeof(DirectoryElement))) + DirectoryElement(s, allocator, name); } break; default: { - s->free(name); + allocator->free(name, strlen(name) + 1); e = 0; } break; } @@ -621,8 +688,9 @@ parsePath(System* s, const char* path, const char* bootLibrary) class MyIterator: public Finder::IteratorImp { public: - MyIterator(System* s, Element* path): - s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0) + MyIterator(System* s, Allocator* allocator, Element* path): + s(s), allocator(allocator), e(path ? path->next : 0), + it(path ? path->iterator() : 0) { } virtual const char* next(unsigned* size) { @@ -645,25 +713,37 @@ class MyIterator: public Finder::IteratorImp { virtual void dispose() { if (it) it->dispose(); - s->free(this); + allocator->free(this, sizeof(*this)); } System* s; + Allocator* allocator; Element* e; Element::Iterator* it; }; class MyFinder: public Finder { public: - MyFinder(System* system, const char* path, const char* bootLibrary): + MyFinder(System* system, Allocator* allocator, const char* path, + const char* bootLibrary): system(system), - path_(parsePath(system, path, bootLibrary)), - pathString(copy(system, path)) + allocator(allocator), + path_(parsePath(system, allocator, path, bootLibrary)), + pathString(copy(allocator, path)) + { } + + MyFinder(System* system, Allocator* allocator, const uint8_t* jarData, + unsigned jarLength): + system(system), + allocator(allocator), + path_(new (allocator->allocate(sizeof(JarElement))) + JarElement(system, allocator, jarData, jarLength)), + pathString(0) { } virtual IteratorImp* iterator() { - return new (allocate(system, sizeof(MyIterator))) - MyIterator(system, path_); + return new (allocator->allocate(sizeof(MyIterator))) + MyIterator(system, allocator, path_); } virtual System::Region* find(const char* name) { @@ -677,14 +757,17 @@ class MyFinder: public Finder { return 0; } - virtual bool exists(const char* name) { + virtual System::FileType stat(const char* name, unsigned* length, + bool tryDirectory) + { for (Element* e = path_; e; e = e->next) { - if (e->exists(name)) { - return true; + System::FileType type = e->stat(name, length, tryDirectory); + if (type != System::TypeDoesNotExist) { + return type; } } - return false; + return System::TypeDoesNotExist; } virtual const char* path() { @@ -697,11 +780,12 @@ class MyFinder: public Finder { e = e->next; t->dispose(); } - system->free(pathString); - system->free(this); + allocator->free(pathString, strlen(pathString) + 1); + allocator->free(this, sizeof(*this)); } System* system; + Allocator* allocator; Element* path_; const char* pathString; }; @@ -711,9 +795,16 @@ class MyFinder: public Finder { namespace vm { Finder* -makeFinder(System* s, const char* path, const char* bootLibrary) +makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary) { - return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary); + return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary); +} + +Finder* +makeFinder(System* s, Allocator* a, const uint8_t* jarData, unsigned jarLength) +{ + return new (a->allocate(sizeof(MyFinder))) + MyFinder(s, a, jarData, jarLength); } } // namespace vm diff --git a/src/finder.h b/src/finder.h index 4cd1256baf..203abb49e3 100644 --- a/src/finder.h +++ b/src/finder.h @@ -60,13 +60,19 @@ class Finder { virtual IteratorImp* iterator() = 0; virtual System::Region* find(const char* name) = 0; - virtual bool exists(const char* name) = 0; + virtual System::FileType stat(const char* name, + unsigned* length, + bool tryDirectory = false) = 0; virtual const char* path() = 0; virtual void dispose() = 0; }; Finder* -makeFinder(System* s, const char* path, const char* bootLibrary); +makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary); + +Finder* +makeFinder(System* s, Allocator* a, const uint8_t* jarData, + unsigned jarLength); } // namespace vm diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 680992c4df..44cbb0cb91 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2228,6 +2228,7 @@ populateJNITables(JavaVMVTable* vmTable, JNIEnvVTable* envTable) #define BOOTSTRAP_PROPERTY "avian.bootstrap" #define CRASHDIR_PROPERTY "avian.crash.dir" +#define EMBED_PREFIX_PROPERTY "avian.embed.prefix" #define CLASSPATH_PROPERTY "java.class.path" #define JAVA_HOME_PROPERTY "java.home" #define BOOTCLASSPATH_PREPEND_OPTION "bootclasspath/p" @@ -2250,6 +2251,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) const char* bootLibrary = 0; const char* classpath = 0; const char* javaHome = AVIAN_JAVA_HOME; + const char* embedPrefix = AVIAN_EMBED_PREFIX; const char* bootClasspathPrepend = ""; const char* bootClasspath = 0; const char* bootClasspathAppend = ""; @@ -2293,6 +2295,10 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) sizeof(JAVA_HOME_PROPERTY)) == 0) { javaHome = p + sizeof(JAVA_HOME_PROPERTY); + } else if (strncmp(p, EMBED_PREFIX_PROPERTY "=", + sizeof(EMBED_PREFIX_PROPERTY)) == 0) + { + embedPrefix = p + sizeof(EMBED_PREFIX_PROPERTY); } ++ propertyCount; @@ -2305,7 +2311,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) System* s = makeSystem(crashDumpDirectory); Heap* h = makeHeap(s, heapLimit); - Classpath* c = makeClasspath(s, h, javaHome); + Classpath* c = makeClasspath(s, h, javaHome, embedPrefix); if (bootClasspath == 0) { bootClasspath = c->bootClasspath(); @@ -2325,8 +2331,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) local::append(&bootClasspathPointer, bootClasspathAppend, bcpal, 0); Finder* bf = makeFinder - (s, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); - Finder* af = makeFinder(s, classpath, bootLibrary); + (s, h, RUNTIME_ARRAY_BODY(bootClasspathBuffer), bootLibrary); + Finder* af = makeFinder(s, h, classpath, bootLibrary); Processor* p = makeProcessor(s, h, true); const char** properties = static_cast diff --git a/src/machine.cpp b/src/machine.cpp index 184649e0e5..9d3ab655fb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -193,6 +193,23 @@ turnOffTheLights(Thread* t) } } + if (root(t, Machine::VirtualFiles)) { + for (unsigned i = 0; i < arrayLength(t, root(t, Machine::VirtualFiles)); + ++i) + { + object region = arrayBody(t, root(t, Machine::VirtualFiles), i); + if (region) { + static_cast(regionRegion(t, region))->dispose(); + } + } + } + + for (object p = root(t, Machine::VirtualFileFinders); + p; p = finderNext(t, p)) + { + static_cast(finderFinder(t, p))->dispose(); + } + Machine* m = t->m; disposeAll(t, t->m->rootThread); @@ -204,13 +221,13 @@ turnOffTheLights(Thread* t) Finder* bf = m->bootFinder; Finder* af = m->appFinder; + c->dispose(); m->dispose(); h->disposeFixies(); - c->dispose(); p->dispose(); - h->dispose(); bf->dispose(); af->dispose(); + h->dispose(); s->dispose(); } diff --git a/src/machine.h b/src/machine.h index 1955adadb8..15782d5240 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1198,10 +1198,12 @@ class Machine { ShutdownHooks, ObjectsToFinalize, NullPointerException, - ArrayIndexOutOfBoundsException + ArrayIndexOutOfBoundsException, + VirtualFileFinders, + VirtualFiles }; - static const unsigned RootCount = ArrayIndexOutOfBoundsException + 1; + static const unsigned RootCount = VirtualFiles + 1; Machine(System* system, Heap* heap, Finder* bootFinder, Finder* appFinder, Processor* processor, Classpath* classpath, const char** properties, @@ -1446,7 +1448,8 @@ runJavaThread(Thread* t) } Classpath* -makeClasspath(System* system, Allocator* allocator, const char* javaHome); +makeClasspath(System* system, Allocator* allocator, const char* javaHome, + const char* embedPrefix); typedef uint64_t (JNICALL *FastNativeFunction)(Thread*, object, uintptr_t*); diff --git a/src/posix.cpp b/src/posix.cpp index 47ef06fe34..1c3e0c6d09 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -698,18 +698,22 @@ class MySystem: public System { return status; } - virtual FileType identify(const char* name) { + virtual FileType stat(const char* name, unsigned* length) { struct stat s; - int r = stat(name, &s); + int r = ::stat(name, &s); if (r == 0) { if (S_ISREG(s.st_mode)) { + *length = s.st_size; return TypeFile; } else if (S_ISDIR(s.st_mode)) { + *length = 0; return TypeDirectory; } else { + *length = 0; return TypeUnknown; } } else { + *length = 0; return TypeDoesNotExist; } } diff --git a/src/system.h b/src/system.h index 1cdddb3afe..5cf7211ab9 100644 --- a/src/system.h +++ b/src/system.h @@ -132,7 +132,7 @@ class System { unsigned count, unsigned size, unsigned returnType) = 0; virtual Status map(Region**, const char* name) = 0; - virtual FileType identify(const char* name) = 0; + virtual FileType stat(const char* name, unsigned* length) = 0; virtual Status open(Directory**, const char* name) = 0; virtual const char* libraryPrefix() = 0; virtual const char* librarySuffix() = 0; diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 1480fb92a4..c2eeb76684 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -2213,7 +2213,31 @@ main(int ac, char** av) } System* system = makeSystem(0); - Finder* finder = makeFinder(system, av[1], 0); + + class MyAllocator: public Allocator { + public: + MyAllocator(System* s): s(s) { } + + virtual void* tryAllocate(unsigned size) { + return s->tryAllocate(size); + } + + virtual void* allocate(unsigned size) { + void* p = tryAllocate(size); + if (p == 0) { + abort(s); + } + return p; + } + + virtual void free(const void* p, unsigned) { + s->free(p); + } + + System* s; + } allocator(system); + + Finder* finder = makeFinder(system, &allocator, av[1], 0); FILE* inStream = ::fopen(av[2], "rb"); if (inStream == 0) { diff --git a/src/types.def b/src/types.def index 158483115a..1cb88bcf86 100644 --- a/src/types.def +++ b/src/types.def @@ -48,6 +48,15 @@ (extends native) (object original)) +(type finder + (void* finder) + (object name) + (object next)) + +(type region + (void* region) + (unsigned position)) + (pod exceptionHandler (uint16_t start) (uint16_t end) diff --git a/src/util.cpp b/src/util.cpp index 0745f98f72..0e9bd6d4b7 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -529,11 +529,6 @@ vectorAppend(Thread* t, object vector, object value) vectorSize(t, vector) * BytesPerWord); } - memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1), - 0, - (vectorLength(t, newVector) - vectorSize(t, vector) - 1) - * BytesPerWord); - vector = newVector; } @@ -542,6 +537,22 @@ vectorAppend(Thread* t, object vector, object value) return vector; } +object +growArray(Thread* t, object array) +{ + PROTECT(t, array); + + object newArray = makeArray + (t, array == 0 ? 16 : (arrayLength(t, array) * 2)); + + if (array) { + memcpy(&arrayBody(t, newArray, 0), &arrayBody(t, array, 0), + arrayLength(t, array)); + } + + return newArray; +} + object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)) diff --git a/src/util.h b/src/util.h index bf895f6bae..ecd9a54a6b 100644 --- a/src/util.h +++ b/src/util.h @@ -84,6 +84,9 @@ listAppend(Thread* t, object list, object value); object vectorAppend(Thread* t, object vector, object value); +object +growArray(Thread* t, object array); + object treeQuery(Thread* t, object tree, intptr_t key, object sentinal, intptr_t (*compare)(Thread* t, intptr_t key, object b)); diff --git a/test/Misc.java b/test/Misc.java index 2bdc3396ca..c1a5a016d4 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -204,5 +204,7 @@ public class Misc { } while (x != 1); } } + + System.out.println(java.util.Calendar.getInstance().toString()); } } From df299f35649f6cdad5aacf991cd0740ccaeb120e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 5 Nov 2010 15:34:28 -0600 Subject: [PATCH 080/274] fix build against latest JRE 1.6.0_22 This commit accomodates a new field in java.lang.Thread and implements JVM_FindClassFromBootLoader. --- src/classpath-openjdk.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index f3eb91ec59..d2b3f131cc 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -298,14 +298,18 @@ class MyClasspath : public Classpath { if (parent) { group = threadGroup(t, parent->javaThread); } else { - group = makeThreadGroup - (t, 0, 0, MaxPriority, false, false, false, 0, 0, 0, 0, 0); + group = allocate(t, FixedSizeOfThreadGroup, true); + setObjectClass(t, group, type(t, Machine::ThreadGroupType)); + threadGroupMaxPriority(t, group) = MaxPriority; } + + object thread = allocate(t, FixedSizeOfThread, true); + setObjectClass(t, thread, type(t, Machine::ThreadType)); + threadPriority(t, thread) = NormalPriority; + threadGroup(t, thread) = group; + threadContextClassLoader(t, thread) = root(t, Machine::BootLoader); - return vm::makeThread - (t, 0, NormalPriority, 0, 0, false, false, false, 0, group, - root(t, Machine::BootLoader), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, 0, 0, - 0, 0, false); + return thread; } virtual void @@ -1869,6 +1873,12 @@ JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, return makeLocalReference(t, getJClass(t, c)); } +extern "C" JNIEXPORT jclass JNICALL +JVM_FindClassFromBootLoader(Thread* t, const char* name, jboolean throwError) +{ + return JVM_FindClassFromClassLoader(t, name, false, 0, throwError); +} + extern "C" JNIEXPORT jclass JNICALL JVM_FindClassFromClass(Thread*, const char*, jboolean, jclass) { abort(); } From e1b808024a79f5b7e1bad1366c0405890f4bef2b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 6 Nov 2010 22:21:19 -0600 Subject: [PATCH 081/274] initial support for Windows OpenJDK build All the tests are passing for openjdk-src builds, but the non-src openjdk build is crashing and there's trouble loading time zone info from the embedded java.home directory. --- makefile | 9 ++- openjdk-src.mk | 30 +++++++- src/classpath-openjdk.cpp | 154 +++++++++++++++++++++++++++++++++----- src/openjdk/Wincon.h | 3 + src/openjdk/jni_md.h | 3 +- src/windows.cpp | 40 +++++----- 6 files changed, 196 insertions(+), 43 deletions(-) create mode 100644 src/openjdk/Wincon.h diff --git a/makefile b/makefile index 5214d37f0e..ee50870fc9 100644 --- a/makefile +++ b/makefile @@ -124,7 +124,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DUSE_ATOMIC_OPERATIONS "-DAVIAN_JAVA_HOME=\"$(javahome)\"" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ @@ -138,6 +138,8 @@ build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl +build-system = posix + system = posix asm = x86 @@ -196,6 +198,8 @@ ifeq ($(platform),windows) inc = "$(root)/win32/include" lib = "$(root)/win32/lib" + embed-prefix = c:/avian-embedded + system = windows so-prefix = @@ -213,6 +217,7 @@ ifeq ($(platform),windows) ranlib = i586-mingw32msvc-ranlib strip = i586-mingw32msvc-strip else + build-platform = windows common-cflags += "-I$(JAVA_HOME)/include/win32" build-cflags = $(common-cflags) -I$(src) -mthreads ifeq ($(build-platform),cygwin) @@ -402,7 +407,7 @@ boot-object = $(build)/boot.o generator-depends := $(wildcard $(src)/*.h) generator-sources = \ $(src)/type-generator.cpp \ - $(src)/$(system).cpp \ + $(src)/$(build-system).cpp \ $(src)/finder.cpp generator-cpp-objects = \ $(foreach x,$(1),$(patsubst $(2)/%.cpp,$(3)/%-build.o,$(x))) diff --git a/openjdk-src.mk b/openjdk-src.mk index 5ee6a46096..1c2e62d0cd 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -128,7 +128,35 @@ openjdk-cflags = \ -D_GNU_SOURCE ifeq ($(platform),windows) -# todo + openjdk-sources += \ + $(openjdk-src)/windows/native/java/io/canonicalize_md.c \ + $(openjdk-src)/windows/native/java/io/Console_md.c \ + $(openjdk-src)/windows/native/java/io/FileDescriptor_md.c \ + $(openjdk-src)/windows/native/java/io/FileInputStream_md.c \ + $(openjdk-src)/windows/native/java/io/FileOutputStream_md.c \ + $(openjdk-src)/windows/native/java/io/FileSystem_md.c \ + $(openjdk-src)/windows/native/java/io/io_util_md.c \ + $(openjdk-src)/windows/native/java/io/RandomAccessFile_md.c \ + $(openjdk-src)/windows/native/java/io/Win32FileSystem_md.c \ + $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ + $(openjdk-src)/windows/native/java/lang/java_props_md.c \ + $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ + $(openjdk-src)/windows/native/java/util/logging.c \ + $(openjdk-src)/windows/native/java/util/TimeZone_md.c \ + $(openjdk-src)/windows/native/sun/io/Win32ErrorMode.c \ + + openjdk-headers-classes += \ + sun.io.Win32ErrorMode + + openjdk-cflags += "-I$(openjdk-src)/windows/javavm/export" \ + "-I$(openjdk-src)/windows/native/common" \ + "-I$(openjdk-src)/windows/native/java/io" \ + "-I$(openjdk-src)/windows/native/java/util" \ + "-I$(openjdk-src)/windows/javavm/include" \ + "-I$(root)/win32/include" \ + -D_JNI_IMPLEMENTATION_ \ + -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ else openjdk-sources += \ $(openjdk-src)/solaris/native/common/jdk_util_md.c \ diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index d2b3f131cc..3dea5e4efb 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -20,10 +20,21 @@ # include # include # include +# include +# include +# include +# include + +#undef interface # define CLOSE _close # define READ _read # define WRITE _write +# define FSTAT _fstat +# define STAT _stat +# define LSEEK _lseek + +# define S_ISSOCK(x) false # ifdef _MSC_VER # define S_ISREG(x) ((x) | _S_IFREG) @@ -31,13 +42,17 @@ # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE # else -# define OPEN _wopen -# define CREAT _wcreat +# define OPEN _open +# define CREAT _creat # endif +#define O_RDONLY _O_RDONLY + # define LIBRARY_PREFIX "" # define LIBRARY_SUFFIX ".dll" +typedef int socklen_t; + #else // not PLATFORM_WINDOWS # include @@ -355,11 +370,20 @@ class MyClasspath : public Classpath { globalMachine = t->m; #ifdef AVIAN_OPENJDK_SRC - { object ufsClass = resolveClass - (t, root(t, Machine::BootLoader), "java/io/UnixFileSystem"); + { +#ifdef PLATFORM_WINDOWS + const char* const fsClassName = "java/io/WinNTFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes"; +#else + const char* const fsClassName = "java/io/UnixFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes0"; +#endif - if (ufsClass) { - PROTECT(t, ufsClass); + object fsClass = resolveClass + (t, root(t, Machine::BootLoader), fsClassName, false); + + if (fsClass) { + PROTECT(t, fsClass); object fileClass = resolveClass (t, root(t, Machine::BootLoader), "java/io/File"); @@ -371,10 +395,10 @@ class MyClasspath : public Classpath { if (pathField) { this->pathField = fieldOffset(t, pathField); - intercept(t, ufsClass, "getBooleanAttributes0", - "(Ljava/io/File;)I", voidPointer(getFileAttributes)); + intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); - intercept(t, ufsClass, "getLength", "(Ljava/io/File;)J", + intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", voidPointer(getLength)); } } @@ -511,10 +535,30 @@ getFinder(Thread* t, const char* name, unsigned nameLength) return 0; } +bool +pathEqual(const char* a, const char* b, unsigned length) +{ +#ifdef PLATFORM_WINDOWS + return strncasecmp(a, b, length) == 0; +#else + return strncmp(a, b, length) == 0; +#endif +} + +bool +pathEqual(const char* a, const char* b) +{ +#ifdef PLATFORM_WINDOWS + return strcasecmp(a, b) == 0; +#else + return strcmp(a, b) == 0; +#endif +} + class EmbeddedFile { public: EmbeddedFile(MyClasspath* cp, const char* path, unsigned pathLength) { - if (strncmp(cp->embedPrefix, path, cp->embedPrefixLength) == 0) { + if (pathEqual(cp->embedPrefix, path, cp->embedPrefixLength)) { const char* p = path + cp->embedPrefixLength; while (*p == '/') ++ p; @@ -564,8 +608,9 @@ getFileAttributes RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); - if (strcmp(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) == 0) { + if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p))) { return Exists | Regular; } else { EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); @@ -613,6 +658,7 @@ getLength RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { @@ -894,6 +940,31 @@ interruptLock(Thread* t, object thread) return threadInterruptLock(t, thread); } +bool +pipeAvailable(int fd, int* available) +{ +#ifdef PLATFORM_WINDOWS + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + + DWORD n; + if (PeekNamedPipe(h, 0,0, 0, &n, 0)) { + *available = n; + } else { + if (GetLastError() != ERROR_BROKEN_PIPE) { + return false; + } + *available = 0; + } + + return true; +#else + return ioctl(fd, FIONREAD, available) >= 0; +#endif +} + } // namespace local } // namespace @@ -1470,13 +1541,17 @@ extern "C" JNIEXPORT jint JNICALL JVM_ActiveProcessorCount(void) { abort(); } extern "C" JNIEXPORT void* JNICALL -JVM_LoadLibrary(const char* name) +JVM_LoadLibrary(const char* path) { Thread* t = static_cast(local::globalMachine->localThread->get()); + RUNTIME_ARRAY(char, p, strlen(path) + 1); + replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); + #ifdef AVIAN_OPENJDK_SRC - if (strcmp(static_cast(t->m->classpath)->zipLibrary, - name) == 0) + if (local::pathEqual + (static_cast(t->m->classpath)->zipLibrary, + RUNTIME_ARRAY_BODY(p))) { return t->m->libraries; } @@ -1485,8 +1560,8 @@ JVM_LoadLibrary(const char* name) ENTER(t, Thread::ActiveState); return loadLibrary - (t, static_cast(t->m->classpath)->libraryPath, name, - false, false); + (t, static_cast(t->m->classpath)->libraryPath, + RUNTIME_ARRAY_BODY(p), false, false); } extern "C" JNIEXPORT void JNICALL @@ -1597,7 +1672,11 @@ JVM_SetThreadPriority(Thread*, jobject, jint) extern "C" JNIEXPORT void JNICALL JVM_Yield(Thread*, jclass) { +#ifdef PLATFORM_WINDOWS + SwitchToThread(); +#else sched_yield(); +#endif } extern "C" JNIEXPORT void JNICALL @@ -2655,7 +2734,12 @@ JVM_Open(const char* path, jint flags, jint mode) Thread* t = static_cast(local::globalMachine->localThread->get()); local::MyClasspath* cp = static_cast(t->m->classpath); - local::EmbeddedFile ef(cp, path, strlen(path)); + unsigned length = strlen(path); + + RUNTIME_ARRAY(char, p, length + 1); + replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); + + local::EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), length); if (ef.jar) { if (flags != O_RDONLY) { errno = EACCES; @@ -2706,7 +2790,7 @@ JVM_Open(const char* path, jint flags, jint mode) return index + local::VirtualFileBase; } else { - int r = OPEN(path, flags, mode); + int r = OPEN(RUNTIME_ARRAY_BODY(p), flags, mode); expect(t, r < local::VirtualFileBase); return r; } @@ -2797,13 +2881,13 @@ JVM_Available(jint fd, jlong* result) return 0; } } else { - struct stat buffer; + struct STAT buffer; int n; if (FSTAT(fd, &buffer) >= 0 and (S_ISCHR(buffer.st_mode) or S_ISFIFO(buffer.st_mode) or S_ISSOCK(buffer.st_mode)) - and ioctl(fd, FIONREAD, &n) >= 0) + and local::pipeAvailable(fd, &n)) { *result = n; return 1; @@ -2877,7 +2961,22 @@ JVM_SetLength(jint, jlong) { abort(); } extern "C" JNIEXPORT jint JNICALL JVM_Sync(jint fd) { +#ifdef PLATFORM_WINDOWS + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + errno = EBADF; + return -1; + } + + if (FlushFileBuffers(h)) { + return 0; + } else { + errno = EIO; + return -1; + } +#else return fsync(fd); +#endif } extern "C" JNIEXPORT jint JNICALL @@ -3091,3 +3190,18 @@ jio_vfprintf(FILE* stream, const char* format, va_list a) // return r; // } + +#ifdef PLATFORM_WINDOWS +namespace { HMODULE jvmHandle = 0; } + +extern "C" int JDK_InitJvmHandle() +{ + jvmHandle = GetModuleHandle(0); + return jvmHandle != 0; +} + +extern "C" void* JDK_FindJvmEntry(const char* name) +{ + return voidPointer(GetProcAddress(jvmHandle, name)); +} +#endif diff --git a/src/openjdk/Wincon.h b/src/openjdk/Wincon.h new file mode 100644 index 0000000000..40d2ad2a68 --- /dev/null +++ b/src/openjdk/Wincon.h @@ -0,0 +1,3 @@ +// Console_md.c #includes "Wincon.h", which only matches "wincon.h" on +// a case insensive filesystem, so we redirect here. +#include "wincon.h" diff --git a/src/openjdk/jni_md.h b/src/openjdk/jni_md.h index 3ddc8b9460..bda8d5ef35 100644 --- a/src/openjdk/jni_md.h +++ b/src/openjdk/jni_md.h @@ -15,12 +15,13 @@ #if (defined __MINGW32__) || (defined _MSC_VER) # define JNIEXPORT __declspec(dllexport) +# define JNICALL __stdcall #else // not (defined __MINGW32__) || (defined _MSC_VER) # define JNIEXPORT __attribute__ ((visibility("default"))) +# define JNICALL #endif // not (defined __MINGW32__) || (defined _MSC_VER) #define JNIIMPORT -#define JNICALL typedef int32_t jint; typedef int64_t jlong; diff --git a/src/windows.cpp b/src/windows.cpp index b0146334b6..3e32a15503 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -457,11 +457,10 @@ class MySystem: public System { class Library: public System::Library { public: - Library(System* s, HMODULE handle, const char* name, bool mapName): + Library(System* s, HMODULE handle, const char* name): s(s), handle(handle), name_(name), - mapName_(mapName), next_(0) { } @@ -476,10 +475,6 @@ class MySystem: public System { return name_; } - virtual bool mapName() { - return mapName_; - } - virtual System::Library* next() { return next_; } @@ -511,7 +506,6 @@ class MySystem: public System { System* s; HMODULE handle; const char* name_; - bool mapName_; System::Library* next_; }; @@ -701,35 +695,40 @@ class MySystem: public System { return status; } - virtual FileType identify(const char* name) { + virtual FileType stat(const char* name, unsigned* length) { struct _stat s; int r = _stat(name, &s); if (r == 0) { if (S_ISREG(s.st_mode)) { + *length = s.st_size; return TypeFile; } else if (S_ISDIR(s.st_mode)) { + *length = 0; return TypeDirectory; } else { + *length = 0; return TypeUnknown; } } else { + *length = 0; return TypeDoesNotExist; } } + virtual const char* libraryPrefix() { + return ""; + } + + virtual const char* librarySuffix() { + return SO_SUFFIX; + } + virtual Status load(System::Library** lib, - const char* name, - bool mapName) + const char* name) { HMODULE handle; unsigned nameLength = (name ? strlen(name) : 0); - if (mapName and name) { - unsigned size = sizeof(SO_PREFIX) + nameLength + sizeof(SO_SUFFIX); - RUNTIME_ARRAY(char, buffer, size);; - vm::snprintf - (RUNTIME_ARRAY_BODY(buffer), size, SO_PREFIX "%s" SO_SUFFIX, name); - handle = LoadLibrary(RUNTIME_ARRAY_BODY(buffer)); - } else if (name) { + if (name) { handle = LoadLibrary(name); } else { handle = GetModuleHandle(0); @@ -748,8 +747,7 @@ class MySystem: public System { n = 0; } - *lib = new (allocate(this, sizeof(Library))) - Library(this, handle, n, mapName); + *lib = new (allocate(this, sizeof(Library))) Library(this, handle, n); return 0; } else { @@ -761,6 +759,10 @@ class MySystem: public System { return ';'; } + virtual char fileSeparator() { + return '\\'; + } + virtual int64_t now() { static LARGE_INTEGER frequency; static LARGE_INTEGER time; From 33b945c10b979f9758e02af1240f339e95c1b5f6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 10:08:04 -0700 Subject: [PATCH 082/274] fix Windows openjdk (non-openjdk-src) build --- makefile | 21 +- src/classpath-common.h | 3 +- src/classpath-openjdk.cpp | 1171 +++++++++++++++++++++---------------- src/types.def | 4 + src/windows.cpp | 9 +- 5 files changed, 700 insertions(+), 508 deletions(-) diff --git a/makefile b/makefile index ee50870fc9..1715391afd 100644 --- a/makefile +++ b/makefile @@ -64,6 +64,9 @@ ifdef openjdk classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar javahome-files = lib/zi + ifeq ($(platform),windows) + javahome-files += lib/tzmappings + endif javahome-object = $(build)/javahome-jar.o else options := $(options)-openjdk @@ -210,12 +213,18 @@ ifeq ($(platform),windows) cflags = -I$(inc) $(common-cflags) ifeq (,$(filter mingw32 cygwin,$(build-platform))) - cxx = i586-mingw32msvc-g++ - cc = i586-mingw32msvc-gcc - dlltool = i586-mingw32msvc-dlltool - ar = i586-mingw32msvc-ar - ranlib = i586-mingw32msvc-ranlib - strip = i586-mingw32msvc-strip + cxx = x86_64-w64-mingw32-g++ -m32 + cc = x86_64-w64-mingw32-gcc -m32 + dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 + ar = x86_64-w64-mingw32-ar + ranlib = x86_64-w64-mingw32-ranlib + strip = x86_64-w64-mingw32-strip --strip-all + # cxx = i586-mingw32msvc-g++ + # cc = i586-mingw32msvc-gcc + # dlltool = i586-mingw32msvc-dlltool + # ar = i586-mingw32msvc-ar + # ranlib = i586-mingw32msvc-ranlib + # strip = i586-mingw32msvc-strip else build-platform = windows common-cflags += "-I$(JAVA_HOME)/include/win32" diff --git a/src/classpath-common.h b/src/classpath-common.h index 8567b1ae77..45b93850ed 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -205,8 +205,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, RUNTIME_ARRAY(char, fullName, fullNameLength + 1); snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, - "%*s%c%s", token.length, token.s, t->m->system->fileSeparator(), - name); + "%*s/%s", token.length, token.s, name); lib = loadLibrary(t, RUNTIME_ARRAY_BODY(fullName)); if (lib) break; diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 3dea5e4efb..ab9c6acd3a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -25,7 +25,7 @@ # include # include -#undef interface +# undef interface # define CLOSE _close # define READ _read @@ -46,7 +46,9 @@ # define CREAT _creat # endif -#define O_RDONLY _O_RDONLY +# define O_RDONLY _O_RDONLY + +# define EXPORT(x) _##x # define LIBRARY_PREFIX "" # define LIBRARY_SUFFIX ".dll" @@ -68,9 +70,12 @@ typedef int socklen_t; # define CLOSE close # define READ read # define WRITE write +# define STAT stat # define FSTAT fstat # define LSEEK lseek +# define EXPORT(x) x + # define LIBRARY_PREFIX "lib" # define LIBRARY_SUFFIX ".so" @@ -161,38 +166,8 @@ makeClassNameString(Thread* t, object name) return makeString(t, "%s", s); } -// only safe to call during bootstrap when there's only one thread -// running: void -intercept(Thread* t, object c, const char* name, const char* spec, - void* function) -{ - object m = findMethodOrNull(t, c, name, spec); - if (m) { - PROTECT(t, m); - - object clone = methodClone(t, m); - - // make clone private to prevent vtable updates at compilation - // time. Otherwise, our interception might be bypassed by calls - // through the vtable. - methodFlags(t, clone) |= ACC_PRIVATE; - - methodFlags(t, m) |= ACC_NATIVE; - - object native = makeNativeIntercept(t, function, true, clone); - - set(t, m, MethodCode, native); - } -} - -int64_t JNICALL -getFileAttributes -(Thread* t, object method, uintptr_t* arguments); - -int64_t JNICALL -getLength -(Thread* t, object method, uintptr_t* arguments); +interceptFileOperations(Thread*); class MyClasspath : public Classpath { public: @@ -255,7 +230,9 @@ class MyClasspath : public Classpath { this->libraryPath = sb.pointer; sb.append(javaHome); -#ifdef ARCH_x86_64 +#ifdef PLATFORM_WINDOWS + sb.append("/bin"); +#elif defined ARCH_x86_64 sb.append("/lib/amd64"); #else // todo: handle other architectures @@ -370,44 +347,12 @@ class MyClasspath : public Classpath { globalMachine = t->m; #ifdef AVIAN_OPENJDK_SRC - { -#ifdef PLATFORM_WINDOWS - const char* const fsClassName = "java/io/WinNTFileSystem"; - const char* const gbaMethodName = "getBooleanAttributes"; -#else - const char* const fsClassName = "java/io/UnixFileSystem"; - const char* const gbaMethodName = "getBooleanAttributes0"; -#endif - - object fsClass = resolveClass - (t, root(t, Machine::BootLoader), fsClassName, false); - - if (fsClass) { - PROTECT(t, fsClass); - - object fileClass = resolveClass - (t, root(t, Machine::BootLoader), "java/io/File"); - - if (fileClass) { - object pathField = findFieldInClass2 - (t, fileClass, "path", "Ljava/lang/String;"); - - if (pathField) { - this->pathField = fieldOffset(t, pathField); - - intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", - voidPointer(getFileAttributes)); - - intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", - voidPointer(getLength)); - } - } - } - - if (UNLIKELY(t->exception)) return; - } + interceptFileOperations(t); + if (UNLIKELY(t->exception)) return; #else // not AVIAN_OPENJDK_SRC - if (loadLibrary(t, libraryPath, "java", true, true) == 0) { + if (loadLibrary(t, libraryPath, "verify", true, true) == 0 + or loadLibrary(t, libraryPath, "java", true, true) == 0) + { abort(t); } #endif // not AVIAN_OPENJDK_SRC @@ -469,7 +414,9 @@ class MyClasspath : public Classpath { const char* zipLibrary; const char* embedPrefix; unsigned embedPrefixLength; - unsigned pathField; + unsigned filePathField; + unsigned fileDescriptorFdField; + unsigned fileInputStreamFdField; char buffer[BufferSize]; }; @@ -604,7 +551,7 @@ getFileAttributes MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); - object path = cast(file, cp->pathField); + object path = cast(file, cp->filePathField); RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); @@ -654,7 +601,7 @@ getLength MyClasspath* cp = static_cast(t->m->classpath); object file = reinterpret_cast(arguments[1]); - object path = cast(file, cp->pathField); + object path = cast(file, cp->filePathField); RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); @@ -687,6 +634,379 @@ getLength } } +void JNICALL +openFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object path = reinterpret_cast(arguments[1]); + + MyClasspath* cp = static_cast(t->m->classpath); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + local::EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0 or ef.pathLength == 0) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::FileNotFoundExceptionType); + return; + } + + Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::FileNotFoundExceptionType); + return; + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + t->exception = t->m->classpath->makeThrowable + (t, Machine::FileNotFoundExceptionType); + return; + } + + PROTECT(t, this_); + + ACQUIRE(t, t->m->referenceLock); + + int index = -1; + unsigned oldLength = root(t, Machine::VirtualFiles) + ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; + + for (unsigned i = 0; i < oldLength; ++i) { + if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { + index = i; + break; + } + } + + if (index == -1) { + object newArray = growArray(t, root(t, Machine::VirtualFiles)); + setRoot(t, Machine::VirtualFiles, newArray); + index = oldLength; + } + + object region = makeRegion(t, r, 0); + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + region); + + cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField) + = index + local::VirtualFileBase; + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, path); + } +} + +int64_t JNICALL +readByteFromFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= local::VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + if (r->length() > regionPosition(t, region)) { + return r->start()[regionPosition(t, region)++]; + } else { + return -1; + } + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IoExceptionType); + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + + return r ? intValue(t, r) : 0; + } +} + +int64_t JNICALL +readBytesFromFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + object dst = reinterpret_cast(arguments[1]); + int32_t offset = arguments[2]; + int32_t length = arguments[3]; + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= local::VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + int available = r->length() - regionPosition(t, region); + if (available == 0) { + return -1; + } + + if (length > available) { + length = available; + } + + memcpy(&byteArrayBody(t, dst, offset), + r->start() + regionPosition(t, region), + length); + + regionPosition(t, region) += length; + + return length; + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IoExceptionType); + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, dst, + offset, length); + + return r ? intValue(t, r) : 0; + } +} + +int64_t JNICALL +skipBytesInFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + int64_t count; memcpy(&count, arguments + 1, 8); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= local::VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + System::Region* r = static_cast + (regionRegion(t, region)); + + int available = r->length() - regionPosition(t, region); + if (count > available) { + count = available; + } + + regionPosition(t, region) += count; + + return count; + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IoExceptionType); + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, count); + + return r ? longValue(t, r) : 0; + } +} + +int64_t JNICALL +availableBytesInFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= local::VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + object region = arrayBody + (t, root(t, Machine::VirtualFiles), fd - VirtualFileBase); + + if (region) { + return static_cast(regionRegion(t, region))->length() + - regionPosition(t, region); + } else { + t->exception = t->m->classpath->makeThrowable + (t, Machine::IoExceptionType); + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + + return r ? intValue(t, r) : 0; + } +} + +void JNICALL +closeFile(Thread* t, object method, uintptr_t* arguments) +{ + object this_ = reinterpret_cast(arguments[0]); + + MyClasspath* cp = static_cast(t->m->classpath); + + int fd = cast + (cast + (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); + + if (fd >= local::VirtualFileBase) { + ACQUIRE(t, t->m->referenceLock); + + int index = fd - VirtualFileBase; + object region = arrayBody(t, root(t, Machine::VirtualFiles), index); + + if (region) { + static_cast(regionRegion(t, region))->dispose(); + } + + set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), + 0); + } else { + t->m->processor->invoke + (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + } +} + +// only safe to call during bootstrap when there's only one thread +// running: +void +intercept(Thread* t, object c, const char* name, const char* spec, + void* function) +{ + object m = findMethodOrNull(t, c, name, spec); + if (m) { + PROTECT(t, m); + + object clone = methodClone(t, m); + + // make clone private to prevent vtable updates at compilation + // time. Otherwise, our interception might be bypassed by calls + // through the vtable. + methodFlags(t, clone) |= ACC_PRIVATE; + + methodFlags(t, m) |= ACC_NATIVE; + + object native = makeNativeIntercept(t, function, true, clone); + + set(t, m, MethodCode, native); + } +} + +void +interceptFileOperations(Thread* t) +{ + MyClasspath* cp = static_cast(t->m->classpath); + + { object fileClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/File"); + if (fileClass == 0) return; + + object filePathField = findFieldInClass2 + (t, fileClass, "path", "Ljava/lang/String;"); + if (filePathField == 0) return; + + cp->filePathField = fieldOffset(t, filePathField); + } + + { object fileDescriptorClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/FileDescriptor"); + if (fileDescriptorClass == 0) return; + + object fileDescriptorFdField = findFieldInClass2 + (t, fileDescriptorClass, "fd", "I"); + if (fileDescriptorFdField == 0) return; + + cp->fileDescriptorFdField = fieldOffset(t, fileDescriptorFdField); + } + + { object fileInputStreamClass = resolveClass + (t, root(t, Machine::BootLoader), "java/io/FileInputStream"); + if (fileInputStreamClass == 0) return; + + object fileInputStreamFdField = findFieldInClass2 + (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); + if (fileInputStreamFdField == 0) return; + + cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); + + PROTECT(t, fileInputStreamClass); + + intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", + voidPointer(openFile)); + + intercept(t, fileInputStreamClass, "read", "()I", + voidPointer(readByteFromFile)); + + intercept(t, fileInputStreamClass, "readBytes", "([BII)I", + voidPointer(readBytesFromFile)); + + intercept(t, fileInputStreamClass, "skip", "(J)J", + voidPointer(skipBytesInFile)); + + intercept(t, fileInputStreamClass, "available", "()I", + voidPointer(availableBytesInFile)); + + intercept(t, fileInputStreamClass, "close0", "()V", + voidPointer(closeFile)); + } + + { +#ifdef PLATFORM_WINDOWS + const char* const fsClassName = "java/io/WinNTFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes"; +#else + const char* const fsClassName = "java/io/UnixFileSystem"; + const char* const gbaMethodName = "getBooleanAttributes0"; +#endif + + object fsClass = resolveClass + (t, root(t, Machine::BootLoader), fsClassName, false); + if (fsClass == 0) return; + + PROTECT(t, fsClass); + + intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", + voidPointer(getFileAttributes)); + + intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", + voidPointer(getLength)); + } +} + unsigned countMethods(Thread* t, object c, bool publicOnly) { @@ -1325,13 +1645,13 @@ Avian_sun_misc_Unsafe_ensureClassInitialized } extern "C" JNIEXPORT jint JNICALL -JVM_GetInterfaceVersion() +EXPORT(JVM_GetInterfaceVersion)() { return local::InterfaceVersion; } extern "C" JNIEXPORT jint JNICALL -JVM_IHashCode(Thread* t, jobject o) +EXPORT(JVM_IHashCode)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); @@ -1339,7 +1659,7 @@ JVM_IHashCode(Thread* t, jobject o) } extern "C" JNIEXPORT void JNICALL -JVM_MonitorWait(Thread* t, jobject o, jlong milliseconds) +EXPORT(JVM_MonitorWait)(Thread* t, jobject o, jlong milliseconds) { ENTER(t, Thread::ActiveState); @@ -1347,7 +1667,7 @@ JVM_MonitorWait(Thread* t, jobject o, jlong milliseconds) } extern "C" JNIEXPORT void JNICALL -JVM_MonitorNotify(Thread* t, jobject o) +EXPORT(JVM_MonitorNotify)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); @@ -1355,7 +1675,7 @@ JVM_MonitorNotify(Thread* t, jobject o) } extern "C" JNIEXPORT void JNICALL -JVM_MonitorNotifyAll(Thread* t, jobject o) +EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); @@ -1363,7 +1683,7 @@ JVM_MonitorNotifyAll(Thread* t, jobject o) } extern "C" JNIEXPORT jobject JNICALL -JVM_Clone(Thread* t, jobject o) +EXPORT(JVM_Clone)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); @@ -1371,7 +1691,7 @@ JVM_Clone(Thread* t, jobject o) } extern "C" JNIEXPORT jstring JNICALL -JVM_InternString(Thread* t, jstring s) +EXPORT(JVM_InternString)(Thread* t, jstring s) { ENTER(t, Thread::ActiveState); @@ -1379,20 +1699,20 @@ JVM_InternString(Thread* t, jstring s) } extern "C" JNIEXPORT jlong JNICALL -JVM_CurrentTimeMillis(Thread* t, jclass) +EXPORT(JVM_CurrentTimeMillis)(Thread* t, jclass) { return t->m->system->now(); } extern "C" JNIEXPORT jlong JNICALL -JVM_NanoTime(Thread* t, jclass) +EXPORT(JVM_NanoTime)(Thread* t, jclass) { return t->m->system->now() * 1000 * 1000; } extern "C" JNIEXPORT void JNICALL -JVM_ArrayCopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, - jint dstOffset, jint length) +EXPORT(JVM_ArrayCopy)(Thread* t, jclass, jobject src, jint srcOffset, + jobject dst, jint dstOffset, jint length) { ENTER(t, Thread::ActiveState); @@ -1400,7 +1720,7 @@ JVM_ArrayCopy(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, } extern "C" JNIEXPORT jobject JNICALL -JVM_InitProperties(Thread* t, jobject properties) +EXPORT(JVM_InitProperties)(Thread* t, jobject properties) { ENTER(t, Thread::ActiveState); @@ -1486,22 +1806,22 @@ JVM_InitProperties(Thread* t, jobject properties) } extern "C" JNIEXPORT void JNICALL -JVM_OnExit(void (*)(void)) { abort(); } +EXPORT(JVM_OnExit)(void (*)(void)) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_Exit(jint code) +EXPORT(JVM_Exit)(jint code) { exit(code); } extern "C" JNIEXPORT void JNICALL -JVM_Halt(jint code) +EXPORT(JVM_Halt)(jint code) { exit(code); } extern "C" JNIEXPORT void JNICALL -JVM_GC() +EXPORT(JVM_GC)() { Thread* t = static_cast(local::globalMachine->localThread->get()); @@ -1511,37 +1831,37 @@ JVM_GC() } extern "C" JNIEXPORT jlong JNICALL -JVM_MaxObjectInspectionAge(void) { abort(); } +EXPORT(JVM_MaxObjectInspectionAge)(void) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_TraceInstructions(jboolean) { abort(); } +EXPORT(JVM_TraceInstructions)(jboolean) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_TraceMethodCalls(jboolean) { abort(); } +EXPORT(JVM_TraceMethodCalls)(jboolean) { abort(); } extern "C" JNIEXPORT jlong JNICALL -JVM_TotalMemory() +EXPORT(JVM_TotalMemory)() { return 0; } extern "C" JNIEXPORT jlong JNICALL -JVM_FreeMemory() +EXPORT(JVM_FreeMemory)() { return 0; } extern "C" JNIEXPORT jlong JNICALL -JVM_MaxMemory() +EXPORT(JVM_MaxMemory)() { return 0; } extern "C" JNIEXPORT jint JNICALL -JVM_ActiveProcessorCount(void) { abort(); } +EXPORT(JVM_ActiveProcessorCount)(void) { abort(); } extern "C" JNIEXPORT void* JNICALL -JVM_LoadLibrary(const char* path) +EXPORT(JVM_LoadLibrary)(const char* path) { Thread* t = static_cast(local::globalMachine->localThread->get()); @@ -1565,10 +1885,10 @@ JVM_LoadLibrary(const char* path) } extern "C" JNIEXPORT void JNICALL -JVM_UnloadLibrary(void*) { abort(); } +EXPORT(JVM_UnloadLibrary)(void*) { abort(); } extern "C" JNIEXPORT void* JNICALL -JVM_FindLibraryEntry(void* library, const char* name) +EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) { Thread* t = static_cast(local::globalMachine->localThread->get()); @@ -1578,16 +1898,16 @@ JVM_FindLibraryEntry(void* library, const char* name) } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsSupportedJNIVersion(jint version) +EXPORT(JVM_IsSupportedJNIVersion)(jint version) { return version <= JNI_VERSION_1_4; } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsNaN(jdouble) { abort(); } +EXPORT(JVM_IsNaN)(jdouble) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_FillInStackTrace(Thread* t, jobject throwable) +EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) { ENTER(t, Thread::ActiveState); @@ -1596,10 +1916,10 @@ JVM_FillInStackTrace(Thread* t, jobject throwable) } extern "C" JNIEXPORT void JNICALL -JVM_PrintStackTrace(Thread*, jobject, jobject) { abort(); } +EXPORT(JVM_PrintStackTrace)(Thread*, jobject, jobject) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetStackTraceDepth(Thread* t, jobject throwable) +EXPORT(JVM_GetStackTraceDepth)(Thread* t, jobject throwable) { ENTER(t, Thread::ActiveState); @@ -1607,7 +1927,7 @@ JVM_GetStackTraceDepth(Thread* t, jobject throwable) } extern "C" JNIEXPORT jobject JNICALL -JVM_GetStackTraceElement(Thread* t, jobject throwable, jint index) +EXPORT(JVM_GetStackTraceElement)(Thread* t, jobject throwable, jint index) { ENTER(t, Thread::ActiveState); @@ -1617,28 +1937,28 @@ JVM_GetStackTraceElement(Thread* t, jobject throwable, jint index) } extern "C" JNIEXPORT void JNICALL -JVM_InitializeCompiler (Thread*, jclass) { abort(); } +EXPORT(JVM_InitializeCompiler) (Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsSilentCompiler(Thread*, jclass) { abort(); } +EXPORT(JVM_IsSilentCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_CompileClass(Thread*, jclass, jclass) { abort(); } +EXPORT(JVM_CompileClass)(Thread*, jclass, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_CompileClasses(Thread*, jclass, jstring) { abort(); } +EXPORT(JVM_CompileClasses)(Thread*, jclass, jstring) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_CompilerCommand(Thread*, jclass, jobject) { abort(); } +EXPORT(JVM_CompilerCommand)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_EnableCompiler(Thread*, jclass) { abort(); } +EXPORT(JVM_EnableCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_DisableCompiler(Thread*, jclass) { abort(); } +EXPORT(JVM_DisableCompiler)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_StartThread(Thread* t, jobject thread) +EXPORT(JVM_StartThread)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); @@ -1646,10 +1966,10 @@ JVM_StartThread(Thread* t, jobject thread) } extern "C" JNIEXPORT void JNICALL -JVM_StopThread(Thread*, jobject, jobject) { abort(); } +EXPORT(JVM_StopThread)(Thread*, jobject, jobject) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsThreadAlive(Thread* t, jobject thread) +EXPORT(JVM_IsThreadAlive)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); @@ -1658,19 +1978,19 @@ JVM_IsThreadAlive(Thread* t, jobject thread) } extern "C" JNIEXPORT void JNICALL -JVM_SuspendThread(Thread*, jobject) { abort(); } +EXPORT(JVM_SuspendThread)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_ResumeThread(Thread*, jobject) { abort(); } +EXPORT(JVM_ResumeThread)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_SetThreadPriority(Thread*, jobject, jint) +EXPORT(JVM_SetThreadPriority)(Thread*, jobject, jint) { // ignore } extern "C" JNIEXPORT void JNICALL -JVM_Yield(Thread*, jclass) +EXPORT(JVM_Yield)(Thread*, jclass) { #ifdef PLATFORM_WINDOWS SwitchToThread(); @@ -1680,7 +2000,7 @@ JVM_Yield(Thread*, jclass) } extern "C" JNIEXPORT void JNICALL -JVM_Sleep(Thread* t, jclass, jlong milliseconds) +EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) { ENTER(t, Thread::ActiveState); @@ -1695,7 +2015,7 @@ JVM_Sleep(Thread* t, jclass, jlong milliseconds) } extern "C" JNIEXPORT jobject JNICALL -JVM_CurrentThread(Thread* t, jclass) +EXPORT(JVM_CurrentThread)(Thread* t, jclass) { ENTER(t, Thread::ActiveState); @@ -1703,10 +2023,10 @@ JVM_CurrentThread(Thread* t, jclass) } extern "C" JNIEXPORT jint JNICALL -JVM_CountStackFrames(Thread*, jobject) { abort(); } +EXPORT(JVM_CountStackFrames)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_Interrupt(Thread* t, jobject thread) +EXPORT(JVM_Interrupt)(Thread* t, jobject thread) { ENTER(t, Thread::ActiveState); @@ -1721,7 +2041,7 @@ JVM_Interrupt(Thread* t, jobject thread) } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) +EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) { ENTER(t, Thread::ActiveState); @@ -1736,25 +2056,25 @@ JVM_IsInterrupted(Thread* t, jobject thread, jboolean clear) } extern "C" JNIEXPORT jboolean JNICALL -JVM_HoldsLock(Thread*, jclass, jobject) { abort(); } +EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_DumpAllStacks(Thread*, jclass) { abort(); } +EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetAllThreads(Thread*, jclass) { abort(); } +EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_DumpThreads(Thread*, jclass, jobjectArray) { abort(); } +EXPORT(JVM_DumpThreads)(Thread*, jclass, jobjectArray) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_CurrentLoadedClass(Thread*) { abort(); } +EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_CurrentClassLoader(Thread*) { abort(); } +EXPORT(JVM_CurrentClassLoader)(Thread*) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassContext(Thread* t) +EXPORT(JVM_GetClassContext)(Thread* t) { ENTER(t, Thread::ActiveState); @@ -1776,37 +2096,37 @@ JVM_GetClassContext(Thread* t) } extern "C" JNIEXPORT jint JNICALL -JVM_ClassDepth(Thread*, jstring) { abort(); } +EXPORT(JVM_ClassDepth)(Thread*, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_ClassLoaderDepth(Thread*) { abort(); } +EXPORT(JVM_ClassLoaderDepth)(Thread*) { abort(); } extern "C" JNIEXPORT jstring JNICALL -JVM_GetSystemPackage(Thread*, jstring) +EXPORT(JVM_GetSystemPackage)(Thread*, jstring) { return 0; } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetSystemPackages(Thread*) { abort(); } +EXPORT(JVM_GetSystemPackages)(Thread*) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_AllocateNewObject(Thread*, jobject, jclass, +EXPORT(JVM_AllocateNewObject)(Thread*, jobject, jclass, jclass) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_AllocateNewArray(Thread*, jobject, jclass, +EXPORT(JVM_AllocateNewArray)(Thread*, jobject, jclass, jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_LatestUserDefinedLoader(Thread*) { abort(); } +EXPORT(JVM_LatestUserDefinedLoader)(Thread*) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_LoadClass0(Thread*, jobject, jclass, +EXPORT(JVM_LoadClass0)(Thread*, jobject, jclass, jstring) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetArrayLength(Thread* t, jobject array) +EXPORT(JVM_GetArrayLength)(Thread* t, jobject array) { ENTER(t, Thread::ActiveState); @@ -1814,7 +2134,7 @@ JVM_GetArrayLength(Thread* t, jobject array) } extern "C" JNIEXPORT jobject JNICALL -JVM_GetArrayElement(Thread* t, jobject array, jint index) +EXPORT(JVM_GetArrayElement)(Thread* t, jobject array, jint index) { ENTER(t, Thread::ActiveState); @@ -1822,10 +2142,11 @@ JVM_GetArrayElement(Thread* t, jobject array, jint index) } extern "C" JNIEXPORT jvalue JNICALL -JVM_GetPrimitiveArrayElement(Thread*, jobject, jint, jint) { abort(); } +EXPORT(JVM_GetPrimitiveArrayElement)(Thread*, jobject, jint, jint) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_SetArrayElement(Thread* t, jobject array, jint index, jobject value) +EXPORT(JVM_SetArrayElement)(Thread* t, jobject array, jint index, + jobject value) { ENTER(t, Thread::ActiveState); @@ -1833,11 +2154,11 @@ JVM_SetArrayElement(Thread* t, jobject array, jint index, jobject value) } extern "C" JNIEXPORT void JNICALL -JVM_SetPrimitiveArrayElement(Thread*, jobject, jint, jvalue, +EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, unsigned char) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_NewArray(Thread* t, jclass elementClass, jint length) +EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) { ENTER(t, Thread::ActiveState); @@ -1868,10 +2189,10 @@ JVM_NewArray(Thread* t, jclass elementClass, jint length) } extern "C" JNIEXPORT jobject JNICALL -JVM_NewMultiArray(Thread*, jclass, jintArray) { abort(); } +EXPORT(JVM_NewMultiArray)(Thread*, jclass, jintArray) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_GetCallerClass(Thread* t, int target) +EXPORT(JVM_GetCallerClass)(Thread* t, int target) { ENTER(t, Thread::ActiveState); @@ -1880,7 +2201,7 @@ JVM_GetCallerClass(Thread* t, int target) } extern "C" JNIEXPORT jclass JNICALL -JVM_FindPrimitiveClass(Thread* t, const char* name) +EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) { ENTER(t, Thread::ActiveState); @@ -1922,11 +2243,12 @@ JVM_FindPrimitiveClass(Thread* t, const char* name) } extern "C" JNIEXPORT void JNICALL -JVM_ResolveClass(Thread*, jclass) { abort(); } +EXPORT(JVM_ResolveClass)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, - jobject loader, jboolean throwError) +EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, + jboolean init, jobject loader, + jboolean throwError) { ENTER(t, Thread::ActiveState); @@ -1953,17 +2275,18 @@ JVM_FindClassFromClassLoader(Thread* t, const char* name, jboolean init, } extern "C" JNIEXPORT jclass JNICALL -JVM_FindClassFromBootLoader(Thread* t, const char* name, jboolean throwError) +EXPORT(JVM_FindClassFromBootLoader)(Thread* t, const char* name, + jboolean throwError) { - return JVM_FindClassFromClassLoader(t, name, false, 0, throwError); + return EXPORT(JVM_FindClassFromClassLoader)(t, name, false, 0, throwError); } extern "C" JNIEXPORT jclass JNICALL -JVM_FindClassFromClass(Thread*, const char*, jboolean, +EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) +EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) { ENTER(t, Thread::ActiveState); @@ -1980,8 +2303,8 @@ JVM_FindLoadedClass(Thread* t, jobject loader, jstring name) } extern "C" JNIEXPORT jclass JNICALL -JVM_DefineClass(Thread* t, const char*, jobject loader, const uint8_t* data, - jsize length, jobject) +EXPORT(JVM_DefineClass)(Thread* t, const char*, jobject loader, + const uint8_t* data, jsize length, jobject) { ENTER(t, Thread::ActiveState); @@ -1991,15 +2314,15 @@ JVM_DefineClass(Thread* t, const char*, jobject loader, const uint8_t* data, } extern "C" JNIEXPORT jclass JNICALL -JVM_DefineClassWithSource(Thread* t, const char*, jobject loader, +EXPORT(JVM_DefineClassWithSource)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject, const char*) { - return JVM_DefineClass(t, 0, loader, data, length, 0); + return EXPORT(JVM_DefineClass)(t, 0, loader, data, length, 0); } extern "C" JNIEXPORT jstring JNICALL -JVM_GetClassName(Thread* t, jclass c) +EXPORT(JVM_GetClassName)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2007,7 +2330,7 @@ JVM_GetClassName(Thread* t, jclass c) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassInterfaces(Thread* t, jclass c) +EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2033,7 +2356,7 @@ JVM_GetClassInterfaces(Thread* t, jclass c) } extern "C" JNIEXPORT jobject JNICALL -JVM_GetClassLoader(Thread* t, jclass c) +EXPORT(JVM_GetClassLoader)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2059,7 +2382,7 @@ JVM_GetClassLoader(Thread* t, jclass c) } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsInterface(Thread* t, jclass c) +EXPORT(JVM_IsInterface)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2067,13 +2390,13 @@ JVM_IsInterface(Thread* t, jclass c) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassSigners(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassSigners)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_SetClassSigners(Thread*, jclass, jobjectArray) { abort(); } +EXPORT(JVM_SetClassSigners)(Thread*, jclass, jobjectArray) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_GetProtectionDomain(Thread* t, jclass) +EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) { ENTER(t, Thread::ActiveState); @@ -2089,10 +2412,10 @@ JVM_GetProtectionDomain(Thread* t, jclass) } extern "C" JNIEXPORT void JNICALL -JVM_SetProtectionDomain(Thread*, jclass, jobject) { abort(); } +EXPORT(JVM_SetProtectionDomain)(Thread*, jclass, jobject) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsArrayClass(Thread* t, jclass c) +EXPORT(JVM_IsArrayClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2100,7 +2423,7 @@ JVM_IsArrayClass(Thread* t, jclass c) } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsPrimitiveClass(Thread* t, jclass c) +EXPORT(JVM_IsPrimitiveClass)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2108,7 +2431,7 @@ JVM_IsPrimitiveClass(Thread* t, jclass c) } extern "C" JNIEXPORT jclass JNICALL -JVM_GetComponentType(Thread* t, jclass c) +EXPORT(JVM_GetComponentType)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2122,7 +2445,7 @@ JVM_GetComponentType(Thread* t, jclass c) } extern "C" JNIEXPORT jint JNICALL -JVM_GetClassModifiers(Thread* t, jclass c) +EXPORT(JVM_GetClassModifiers)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2130,16 +2453,16 @@ JVM_GetClassModifiers(Thread* t, jclass c) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetDeclaredClasses(Thread*, jclass) { abort(); } +EXPORT(JVM_GetDeclaredClasses)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_GetDeclaringClass(Thread*, jclass) { abort(); } +EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jstring JNICALL -JVM_GetClassSignature(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassSignature)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jbyteArray JNICALL -JVM_GetClassAnnotations(Thread* t, jclass c) +EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2148,7 +2471,7 @@ JVM_GetClassAnnotations(Thread* t, jclass c) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) +EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) { ENTER(t, Thread::ActiveState); @@ -2233,7 +2556,7 @@ JVM_GetClassDeclaredMethods(Thread* t, jclass c, jboolean publicOnly) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) +EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) { ENTER(t, Thread::ActiveState); @@ -2303,7 +2626,8 @@ JVM_GetClassDeclaredFields(Thread* t, jclass c, jboolean publicOnly) } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) +EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, + jboolean publicOnly) { ENTER(t, Thread::ActiveState); @@ -2374,13 +2698,13 @@ JVM_GetClassDeclaredConstructors(Thread* t, jclass c, jboolean publicOnly) } extern "C" JNIEXPORT jint JNICALL -JVM_GetClassAccessFlags(Thread* t, jclass c) +EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c) { - return JVM_GetClassModifiers(t, c); + return EXPORT(JVM_GetClassModifiers)(t, c); } extern "C" JNIEXPORT jobject JNICALL -JVM_InvokeMethod(Thread* t, jobject method, jobject instance, +EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, jobjectArray arguments) { ENTER(t, Thread::ActiveState); @@ -2406,7 +2730,7 @@ JVM_InvokeMethod(Thread* t, jobject method, jobject instance, } extern "C" JNIEXPORT jobject JNICALL -JVM_NewInstanceFromConstructor(Thread* t, jobject constructor, +EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, jobjectArray arguments) { ENTER(t, Thread::ActiveState); @@ -2434,7 +2758,7 @@ JVM_NewInstanceFromConstructor(Thread* t, jobject constructor, } extern "C" JNIEXPORT jobject JNICALL -JVM_GetClassConstantPool(Thread* t, jclass c) +EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); @@ -2444,7 +2768,7 @@ JVM_GetClassConstantPool(Thread* t, jclass c) } extern "C" JNIEXPORT jint JNICALL -JVM_ConstantPoolGetSize(Thread* t, jobject, jobject pool) +EXPORT(JVM_ConstantPoolGetSize)(Thread* t, jobject, jobject pool) { if (pool == 0) return 0; @@ -2454,28 +2778,35 @@ JVM_ConstantPoolGetSize(Thread* t, jobject, jobject pool) } extern "C" JNIEXPORT jclass JNICALL -JVM_ConstantPoolGetClassAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetClassAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jclass JNICALL -JVM_ConstantPoolGetClassAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetClassAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_ConstantPoolGetMethodAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetMethodAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_ConstantPoolGetMethodAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetMethodAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_ConstantPoolGetFieldAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetFieldAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_ConstantPoolGetFieldAtIfLoaded(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetFieldAtIfLoaded)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_ConstantPoolGetMemberRefInfoAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetMemberRefInfoAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_ConstantPoolGetIntAt(Thread* t, jobject, jobject pool, jint index) +EXPORT(JVM_ConstantPoolGetIntAt)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); @@ -2483,19 +2814,23 @@ JVM_ConstantPoolGetIntAt(Thread* t, jobject, jobject pool, jint index) } extern "C" JNIEXPORT jlong JNICALL -JVM_ConstantPoolGetLongAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetLongAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jfloat JNICALL -JVM_ConstantPoolGetFloatAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetFloatAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jdouble JNICALL -JVM_ConstantPoolGetDoubleAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetDoubleAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jstring JNICALL -JVM_ConstantPoolGetStringAt(Thread*, jobject, jobject, jint) { abort(); } +EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) +{ abort(); } extern "C" JNIEXPORT jstring JNICALL -JVM_ConstantPoolGetUTF8At(Thread* t, jobject, jobject pool, jint index) +EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) { ENTER(t, Thread::ActiveState); @@ -2507,7 +2842,7 @@ JVM_ConstantPoolGetUTF8At(Thread* t, jobject, jobject pool, jint index) } extern "C" JNIEXPORT jobject JNICALL -JVM_DoPrivileged +EXPORT(JVM_DoPrivileged) (Thread* t, jclass, jobject action, jobject, jboolean wrapException) { ENTER(t, Thread::ActiveState); @@ -2585,381 +2920,211 @@ JVM_DoPrivileged } extern "C" JNIEXPORT jobject JNICALL -JVM_GetInheritedAccessControlContext(Thread*, jclass) { abort(); } +EXPORT(JVM_GetInheritedAccessControlContext)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_GetStackAccessControlContext(Thread*, jclass) +EXPORT(JVM_GetStackAccessControlContext)(Thread*, jclass) { return 0; } extern "C" JNIEXPORT void* JNICALL -JVM_RegisterSignal(jint, void*) { abort(); } +EXPORT(JVM_RegisterSignal)(jint, void*) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_RaiseSignal(jint) { abort(); } +EXPORT(JVM_RaiseSignal)(jint) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_FindSignal(const char*) +EXPORT(JVM_FindSignal)(const char*) { return -1; } extern "C" JNIEXPORT jboolean JNICALL -JVM_DesiredAssertionStatus(Thread*, jclass, jclass) +EXPORT(JVM_DesiredAssertionStatus)(Thread*, jclass, jclass) { return false; } extern "C" JNIEXPORT jobject JNICALL -JVM_AssertionStatusDirectives(Thread*, jclass) { abort(); } +EXPORT(JVM_AssertionStatusDirectives)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_SupportsCX8() +EXPORT(JVM_SupportsCX8)() { return true; } extern "C" JNIEXPORT const char* JNICALL -JVM_GetClassNameUTF(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassNameUTF)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_GetClassCPTypes(Thread*, jclass, unsigned char*) { abort(); } +EXPORT(JVM_GetClassCPTypes)(Thread*, jclass, unsigned char*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetClassCPEntriesCount(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassCPEntriesCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetClassFieldsCount(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassFieldsCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetClassMethodsCount(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassMethodsCount)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_GetMethodIxExceptionIndexes(Thread*, jclass, jint, +EXPORT(JVM_GetMethodIxExceptionIndexes)(Thread*, jclass, jint, unsigned short*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxExceptionsCount(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetMethodIxExceptionsCount)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_GetMethodIxByteCode(Thread*, jclass, jint, +EXPORT(JVM_GetMethodIxByteCode)(Thread*, jclass, jint, unsigned char*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxByteCodeLength(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetMethodIxByteCodeLength)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_GetMethodIxExceptionTableEntry(Thread*, jclass, jint, +EXPORT(JVM_GetMethodIxExceptionTableEntry)(Thread*, jclass, jint, jint, local::JVM_ExceptionTableEntryType*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxExceptionTableLength(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetMethodIxExceptionTableLength)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetFieldIxModifiers(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetFieldIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxModifiers(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetMethodIxModifiers)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxLocalsCount(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetMethodIxLocalsCount)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxArgsSize(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetMethodIxArgsSize)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetMethodIxMaxStack(Thread*, jclass, int) { abort(); } +EXPORT(JVM_GetMethodIxMaxStack)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsConstructorIx(Thread*, jclass, int) { abort(); } +EXPORT(JVM_IsConstructorIx)(Thread*, jclass, int) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetMethodIxNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetMethodIxNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetMethodIxSignatureUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetMethodIxSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPFieldNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPFieldNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPMethodNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPMethodNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPMethodSignatureUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPMethodSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPFieldSignatureUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPFieldSignatureUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPClassNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPFieldClassNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPFieldClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT const char* JNICALL -JVM_GetCPMethodClassNameUTF(Thread*, jclass, jint) { abort(); } +EXPORT(JVM_GetCPMethodClassNameUTF)(Thread*, jclass, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetCPFieldModifiers(Thread*, jclass, int, jclass) { abort(); } +EXPORT(JVM_GetCPFieldModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetCPMethodModifiers(Thread*, jclass, int, jclass) { abort(); } +EXPORT(JVM_GetCPMethodModifiers)(Thread*, jclass, int, jclass) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_ReleaseUTF(const char*) { abort(); } +EXPORT(JVM_ReleaseUTF)(const char*) { abort(); } extern "C" JNIEXPORT jboolean JNICALL -JVM_IsSameClassPackage(Thread*, jclass, jclass) { abort(); } +EXPORT(JVM_IsSameClassPackage)(Thread*, jclass, jclass) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetLastErrorString(char* dst, int length) +EXPORT(JVM_GetLastErrorString)(char* dst, int length) { strncpy(dst, strerror(errno), length); return strlen(dst); } extern "C" JNIEXPORT char* JNICALL -JVM_NativePath(char* path) +EXPORT(JVM_NativePath)(char* path) { return path; } extern "C" JNIEXPORT jint JNICALL -JVM_Open(const char* path, jint flags, jint mode) +EXPORT(JVM_Open)(const char* path, jint flags, jint mode) { - Thread* t = static_cast(local::globalMachine->localThread->get()); - local::MyClasspath* cp = static_cast(t->m->classpath); - - unsigned length = strlen(path); - - RUNTIME_ARRAY(char, p, length + 1); - replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); - - local::EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), length); - if (ef.jar) { - if (flags != O_RDONLY) { - errno = EACCES; - return -1; - } - - if (ef.jarLength == 0 or ef.pathLength == 0) { - errno = ENOENT; - return -1; - } - - Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); - if (finder == 0) { - errno = ENOENT; - return -1; - } - - System::Region* r = finder->find(ef.path); - if (r == 0) { - errno = ENOENT; - return -1; - } - - ENTER(t, Thread::ActiveState); - - ACQUIRE(t, t->m->referenceLock); - - int index = -1; - unsigned oldLength = root(t, Machine::VirtualFiles) - ? arrayLength(t, root(t, Machine::VirtualFiles)) : 0; - - for (unsigned i = 0; i < oldLength; ++i) { - if (arrayBody(t, root(t, Machine::VirtualFiles), i) == 0) { - index = i; - break; - } - } - - if (index == -1) { - object newArray = growArray(t, root(t, Machine::VirtualFiles)); - setRoot(t, Machine::VirtualFiles, newArray); - index = oldLength; - } - - object region = makeRegion(t, r, 0); - set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), - region); - - return index + local::VirtualFileBase; - } else { - int r = OPEN(RUNTIME_ARRAY_BODY(p), flags, mode); - expect(t, r < local::VirtualFileBase); - return r; - } + return OPEN(path, flags, mode); } extern "C" JNIEXPORT jint JNICALL -JVM_Close(jint fd) +EXPORT(JVM_Close)(jint fd) { - if (fd >= local::VirtualFileBase) { - Thread* t = static_cast(local::globalMachine->localThread->get()); - unsigned index = fd - local::VirtualFileBase; - - ENTER(t, Thread::ActiveState); - - ACQUIRE(t, t->m->referenceLock); - - object region = arrayBody(t, root(t, Machine::VirtualFiles), index); - if (region) { - static_cast(regionRegion(t, region))->dispose(); - } - - set(t, root(t, Machine::VirtualFiles), ArrayBody + (index * BytesPerWord), - 0); - - return 0; - } else { - return CLOSE(fd); - } + return CLOSE(fd); } extern "C" JNIEXPORT jint JNICALL -JVM_Read(jint fd, char* dst, jint length) +EXPORT(JVM_Read)(jint fd, char* dst, jint length) { - if (fd >= local::VirtualFileBase) { - Thread* t = static_cast(local::globalMachine->localThread->get()); - unsigned index = fd - local::VirtualFileBase; - - ENTER(t, Thread::ActiveState); - - ACQUIRE(t, t->m->referenceLock); - - object region = arrayBody(t, root(t, Machine::VirtualFiles), index); - if (region) { - System::Region* r = static_cast - (regionRegion(t, region)); - - int available = r->length() - regionPosition(t, region); - if (length > available) { - length = available; - } - - memcpy(dst, r->start(), length); - - regionPosition(t, region) += length; - - return length; - } else { - errno = EINVAL; - return -1; - } - } else { - return READ(fd, dst, length); - } + return READ(fd, dst, length); } extern "C" JNIEXPORT jint JNICALL -JVM_Write(jint fd, char* src, jint length) +EXPORT(JVM_Write)(jint fd, char* src, jint length) { return WRITE(fd, src, length); } extern "C" JNIEXPORT jint JNICALL -JVM_Available(jint fd, jlong* result) +EXPORT(JVM_Available)(jint fd, jlong* result) { - if (fd >= local::VirtualFileBase) { - Thread* t = static_cast(local::globalMachine->localThread->get()); - unsigned index = fd - local::VirtualFileBase; - - ENTER(t, Thread::ActiveState); - - ACQUIRE(t, t->m->referenceLock); - - object region = arrayBody(t, root(t, Machine::VirtualFiles), index); - if (region) { - return static_cast(regionRegion(t, region))->length() - - regionPosition(t, region); - } else { - return 0; - } - } else { - struct STAT buffer; - int n; - if (FSTAT(fd, &buffer) >= 0 - and (S_ISCHR(buffer.st_mode) - or S_ISFIFO(buffer.st_mode) - or S_ISSOCK(buffer.st_mode)) - and local::pipeAvailable(fd, &n)) - { - *result = n; - return 1; - } - - int current = LSEEK(fd, 0, SEEK_CUR); - if (current == -1) return 0; - - int end = LSEEK(fd, 0, SEEK_END); - if (end == -1) return 0; - - if (LSEEK(fd, current, SEEK_SET) == -1) return 0; - - *result = end - current; + struct STAT buffer; + int n; + if (FSTAT(fd, &buffer) >= 0 + and (S_ISCHR(buffer.st_mode) + or S_ISFIFO(buffer.st_mode) + or S_ISSOCK(buffer.st_mode)) + and local::pipeAvailable(fd, &n)) + { + *result = n; return 1; } + + int current = LSEEK(fd, 0, SEEK_CUR); + if (current == -1) return 0; + + int end = LSEEK(fd, 0, SEEK_END); + if (end == -1) return 0; + + if (LSEEK(fd, current, SEEK_SET) == -1) return 0; + + *result = end - current; + return 1; } extern "C" JNIEXPORT jlong JNICALL -JVM_Lseek(jint fd, jlong offset, jint seek) +EXPORT(JVM_Lseek)(jint fd, jlong offset, jint seek) { - if (fd >= local::VirtualFileBase) { - Thread* t = static_cast(local::globalMachine->localThread->get()); - unsigned index = fd - local::VirtualFileBase; - - ENTER(t, Thread::ActiveState); - - ACQUIRE(t, t->m->referenceLock); - - object region = arrayBody(t, root(t, Machine::VirtualFiles), index); - if (region) { - System::Region* r = static_cast - (regionRegion(t, region)); - - switch (seek) { - case SEEK_SET: - break; - - case SEEK_CUR: - offset += regionPosition(t, region); - break; - - case SEEK_END: - offset += r->length(); - break; - - default: - errno = EINVAL; - return -1; - } - - if (offset >= 0 and offset <= static_cast(r->length())) { - regionPosition(t, region) = offset; - return offset; - } else { - errno = EINVAL; - return -1; - } - } else { - errno = EINVAL; - return -1; - } - } else { - return LSEEK(fd, offset, seek); - } + return LSEEK(fd, offset, seek); } extern "C" JNIEXPORT jint JNICALL -JVM_SetLength(jint, jlong) { abort(); } +EXPORT(JVM_SetLength)(jint, jlong) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Sync(jint fd) +EXPORT(JVM_Sync)(jint fd) { #ifdef PLATFORM_WINDOWS HANDLE h = reinterpret_cast(_get_osfhandle(fd)); @@ -2980,7 +3145,7 @@ JVM_Sync(jint fd) } extern "C" JNIEXPORT jint JNICALL -JVM_InitializeSocketLibrary() +EXPORT(JVM_InitializeSocketLibrary)() { #ifdef PLATFORM_WINDOWS static bool wsaInitialized = false; @@ -2998,13 +3163,13 @@ JVM_InitializeSocketLibrary() } extern "C" JNIEXPORT jint JNICALL -JVM_Socket(jint domain, jint type, jint protocol) +EXPORT(JVM_Socket)(jint domain, jint type, jint protocol) { return socket(domain, type, protocol); } extern "C" JNIEXPORT jint JNICALL -JVM_SocketClose(jint socket) +EXPORT(JVM_SocketClose)(jint socket) { #ifdef PLATFORM_WINDOWS return closesocket(socket); @@ -3014,43 +3179,43 @@ JVM_SocketClose(jint socket) } extern "C" JNIEXPORT jint JNICALL -JVM_SocketShutdown(jint socket, jint how) +EXPORT(JVM_SocketShutdown)(jint socket, jint how) { return shutdown(socket, how); } extern "C" JNIEXPORT jint JNICALL -JVM_Recv(jint socket, char* dst, jint count, jint flags) +EXPORT(JVM_Recv)(jint socket, char* dst, jint count, jint flags) { return recv(socket, dst, count, flags); } extern "C" JNIEXPORT jint JNICALL -JVM_Send(jint socket, char* src, jint count, jint flags) +EXPORT(JVM_Send)(jint socket, char* src, jint count, jint flags) { return send(socket, src, count, flags); } extern "C" JNIEXPORT jint JNICALL -JVM_Timeout(int, long) { abort(); } +EXPORT(JVM_Timeout)(int, long) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Listen(jint socket, jint count) +EXPORT(JVM_Listen)(jint socket, jint count) { return listen(socket, count); } extern "C" JNIEXPORT jint JNICALL -JVM_Connect(jint socket, sockaddr* address, jint addressLength) +EXPORT(JVM_Connect)(jint socket, sockaddr* address, jint addressLength) { return connect(socket, address, addressLength); } extern "C" JNIEXPORT jint JNICALL -JVM_Bind(jint, struct sockaddr*, jint) { abort(); } +EXPORT(JVM_Bind)(jint, struct sockaddr*, jint) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_Accept(jint socket, struct sockaddr* address, jint* addressLength) +EXPORT(JVM_Accept)(jint socket, struct sockaddr* address, jint* addressLength) { socklen_t length = *addressLength; int r = accept(socket, address, &length); @@ -3059,18 +3224,19 @@ JVM_Accept(jint socket, struct sockaddr* address, jint* addressLength) } extern "C" JNIEXPORT jint JNICALL -JVM_RecvFrom(jint, char*, int, +EXPORT(JVM_RecvFrom)(jint, char*, int, int, struct sockaddr*, int*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_SendTo(jint, char*, int, +EXPORT(JVM_SendTo)(jint, char*, int, int, struct sockaddr*, int) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_SocketAvailable(jint, jint*) { abort(); } +EXPORT(JVM_SocketAvailable)(jint, jint*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_GetSockName(jint socket, struct sockaddr* address, int* addressLength) +EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, + int* addressLength) { socklen_t length = *addressLength; int r = getsockname(socket, address, &length); @@ -3079,28 +3245,28 @@ JVM_GetSockName(jint socket, struct sockaddr* address, int* addressLength) } extern "C" JNIEXPORT jint JNICALL -JVM_GetSockOpt(jint, int, int, char*, int*) { abort(); } +EXPORT(JVM_GetSockOpt)(jint, int, int, char*, int*) { abort(); } extern "C" JNIEXPORT jint JNICALL -JVM_SetSockOpt(jint, int, int, const char*, int) { abort(); } +EXPORT(JVM_SetSockOpt)(jint, int, int, const char*, int) { abort(); } extern "C" JNIEXPORT struct protoent* JNICALL -JVM_GetProtoByName(char*) { abort(); } +EXPORT(JVM_GetProtoByName)(char*) { abort(); } extern "C" JNIEXPORT struct hostent* JNICALL -JVM_GetHostByAddr(const char*, int, int) { abort(); } +EXPORT(JVM_GetHostByAddr)(const char*, int, int) { abort(); } extern "C" JNIEXPORT struct hostent* JNICALL -JVM_GetHostByName(char*) { abort(); } +EXPORT(JVM_GetHostByName)(char*) { abort(); } extern "C" JNIEXPORT int JNICALL -JVM_GetHostName(char* name, int length) +EXPORT(JVM_GetHostName)(char* name, int length) { return gethostname(name, length); } extern "C" JNIEXPORT void* JNICALL -JVM_RawMonitorCreate(void) +EXPORT(JVM_RawMonitorCreate)(void) { System* s = local::globalMachine->system; System::Monitor* lock; @@ -3112,13 +3278,13 @@ JVM_RawMonitorCreate(void) } extern "C" JNIEXPORT void JNICALL -JVM_RawMonitorDestroy(void* lock) +EXPORT(JVM_RawMonitorDestroy)(void* lock) { static_cast(lock)->dispose(); } extern "C" JNIEXPORT jint JNICALL -JVM_RawMonitorEnter(void* lock) +EXPORT(JVM_RawMonitorEnter)(void* lock) { static_cast(lock)->acquire (static_cast @@ -3128,7 +3294,7 @@ JVM_RawMonitorEnter(void* lock) } extern "C" JNIEXPORT void JNICALL -JVM_RawMonitorExit(void* lock) +EXPORT(JVM_RawMonitorExit)(void* lock) { static_cast(lock)->release (static_cast @@ -3136,22 +3302,27 @@ JVM_RawMonitorExit(void* lock) } extern "C" JNIEXPORT void* JNICALL -JVM_GetManagement(jint) { abort(); } +EXPORT(JVM_GetManagement)(jint) { abort(); } extern "C" JNIEXPORT jobject JNICALL -JVM_InitAgentProperties(Thread*, jobject) { abort(); } +EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetEnclosingMethodInfo(JNIEnv*, jclass) { abort(); } +EXPORT(JVM_GetEnclosingMethodInfo)(JNIEnv*, jclass) { abort(); } extern "C" JNIEXPORT jintArray JNICALL -JVM_GetThreadStateValues(JNIEnv*, jint) { abort(); } +EXPORT(JVM_GetThreadStateValues)(JNIEnv*, jint) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -JVM_GetThreadStateNames(JNIEnv*, jint, jintArray) { abort(); } +EXPORT(JVM_GetThreadStateNames)(JNIEnv*, jint, jintArray) { abort(); } extern "C" JNIEXPORT void JNICALL -JVM_GetVersionInfo(JNIEnv*, local::jvm_version_info*, size_t) { abort(); } +EXPORT(JVM_GetVersionInfo)(JNIEnv*, local::jvm_version_info*, size_t) +{ abort(); } + +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) +{ abort(); } extern "C" JNIEXPORT int jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) @@ -3159,39 +3330,43 @@ jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) return vm::vsnprintf(dst, size, format, a); } -// extern "C" JNIEXPORT int -// jio_snprintf(char* dst, size_t size, const char* format, ...) -// { -// va_list a; -// va_start(a, format); - -// int r = jio_vsnprintf(dst, size, format, a); - -// va_end(a); - -// return r; -// } - extern "C" JNIEXPORT int jio_vfprintf(FILE* stream, const char* format, va_list a) { return vfprintf(stream, format, a); } -// extern "C" JNIEXPORT int -// jio_fprintf(FILE* stream, const char* format, ...) -// { -// va_list a; -// va_start(a, format); - -// int r = jio_vfprintf(stream, format, a); - -// va_end(a); - -// return r; -// } - #ifdef PLATFORM_WINDOWS +extern "C" JNIEXPORT int +jio_snprintf(char* dst, size_t size, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vsnprintf(dst, size, format, a); + + va_end(a); + + return r; +} + +extern "C" JNIEXPORT int +jio_fprintf(FILE* stream, const char* format, ...) +{ + va_list a; + va_start(a, format); + + int r = jio_vfprintf(stream, format, a); + + va_end(a); + + return r; +} + +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_GetThreadInterruptEvent)() +{ abort(); } + namespace { HMODULE jvmHandle = 0; } extern "C" int JDK_InitJvmHandle() diff --git a/src/types.def b/src/types.def index 1cb88bcf86..68db65d187 100644 --- a/src/types.def +++ b/src/types.def @@ -239,6 +239,10 @@ (type exceptionInInitializerError java/lang/ExceptionInInitializerError) +(type ioException java/io/IOException) + +(type fileNotFoundException java/io/FileNotFoundException) + (type incompatibleContinuationException avian/IncompatibleContinuationException) diff --git a/src/windows.cpp b/src/windows.cpp index 3e32a15503..e601b70f33 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -485,7 +485,7 @@ class MySystem: public System { virtual void disposeAll() { if (Verbose) { - fprintf(stderr, "close %p\n", handle); + fprintf(stderr, "close %p\n", handle); fflush(stderr); } if (name_) { @@ -736,7 +736,7 @@ class MySystem: public System { if (handle) { if (Verbose) { - fprintf(stderr, "open %s as %p\n", name, handle); + fprintf(stderr, "open %s as %p\n", name, handle); fflush(stderr); } char* n; @@ -751,6 +751,11 @@ class MySystem: public System { return 0; } else { + if (Verbose) { + fprintf(stderr, "unable to open %s: %ld\n", name, GetLastError()); + fflush(stderr); + } + return 1; } } From 6cf3666ed9c9c122457c364e663b1eef49292e38 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 12:24:40 -0700 Subject: [PATCH 083/274] fix timezone lookup for Windows openjdk-src build --- src/classpath-openjdk.cpp | 154 +++++++++++++++++++++++++++++++------- src/common.h | 10 +++ 2 files changed, 135 insertions(+), 29 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index ab9c6acd3a..a27c4ac9f4 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -12,8 +12,6 @@ #include "classpath-common.h" #include "util.h" -// todo: move platform-specific stuff into system.h and implementations - #ifdef PLATFORM_WINDOWS # include @@ -48,7 +46,11 @@ # define O_RDONLY _O_RDONLY -# define EXPORT(x) _##x +# ifdef AVIAN_OPENJDK_SRC +# define EXPORT(x) x +# else +# define EXPORT(x) _##x +# endif # define LIBRARY_PREFIX "" # define LIBRARY_SUFFIX ".dll" @@ -247,6 +249,12 @@ class MyClasspath : public Classpath { sb.append("zip"); sb.append(LIBRARY_SUFFIX); sb.append('\0'); + + this->tzMappings = sb.pointer; + sb.append(javaHome); + sb.append("/lib/tzmappings"); + this->tzMappingsLength = sb.pointer - tzMappings; + sb.append('\0'); this->embedPrefix = sb.pointer; sb.append(embedPrefix); @@ -412,7 +420,9 @@ class MyClasspath : public Classpath { const char* classpath; const char* libraryPath; const char* zipLibrary; + const char* tzMappings; const char* embedPrefix; + unsigned tzMappingsLength; unsigned embedPrefixLength; unsigned filePathField; unsigned fileDescriptorFdField; @@ -646,7 +656,7 @@ openFile(Thread* t, object method, uintptr_t* arguments) stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); - local::EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { t->exception = t->m->classpath->makeThrowable @@ -654,7 +664,7 @@ openFile(Thread* t, object method, uintptr_t* arguments) return; } - Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); + Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { t->exception = t->m->classpath->makeThrowable (t, Machine::FileNotFoundExceptionType); @@ -696,7 +706,7 @@ openFile(Thread* t, object method, uintptr_t* arguments) cast (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField) - = index + local::VirtualFileBase; + = index + VirtualFileBase; } else { t->m->processor->invoke (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, path); @@ -714,7 +724,7 @@ readByteFromFile(Thread* t, object method, uintptr_t* arguments) (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); - if (fd >= local::VirtualFileBase) { + if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody @@ -756,7 +766,7 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); - if (fd >= local::VirtualFileBase) { + if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody @@ -808,7 +818,7 @@ skipBytesInFile(Thread* t, object method, uintptr_t* arguments) (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); - if (fd >= local::VirtualFileBase) { + if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody @@ -850,7 +860,7 @@ availableBytesInFile(Thread* t, object method, uintptr_t* arguments) (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); - if (fd >= local::VirtualFileBase) { + if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); object region = arrayBody @@ -883,7 +893,7 @@ closeFile(Thread* t, object method, uintptr_t* arguments) (cast (this_, cp->fileInputStreamFdField), cp->fileDescriptorFdField); - if (fd >= local::VirtualFileBase) { + if (fd >= VirtualFileBase) { ACQUIRE(t, t->m->referenceLock); int index = fd - VirtualFileBase; @@ -3337,6 +3347,108 @@ jio_vfprintf(FILE* stream, const char* format, va_list a) } #ifdef PLATFORM_WINDOWS +extern "C" JNIEXPORT void* JNICALL +EXPORT(JVM_GetThreadInterruptEvent)() +{ abort(); } + +namespace { HMODULE jvmHandle = 0; } + +extern "C" int JDK_InitJvmHandle() +{ + jvmHandle = GetModuleHandle(0); + return jvmHandle != 0; +} + +extern "C" void* JDK_FindJvmEntry(const char* name) +{ + return voidPointer(GetProcAddress(jvmHandle, name)); +} + +# ifdef AVIAN_OPENJDK_SRC + +extern "C" char* findJavaTZ_md(const char*, const char*); + +extern "C" JNIEXPORT int64_t JNICALL +Avian_java_util_TimeZone_getSystemTimeZoneID +(Thread* t, object, uintptr_t* arguments) +{ + // On Windows, findJavaTZ_md loads tzmappings from the filesystem + // using fopen, so we have no opportunity to make it read straight + // from the embedded JAR file as with files read from Java code. + // Therefore, we must extract tzmappings to a temporary location + // before calling findJavaTZ_md. We could avoid this by + // implementing findJavaTZ_md ourselves from scratch, but that would + // be a lot of code to implement and maintain. + + object country = reinterpret_cast(arguments[1]); + + RUNTIME_ARRAY(char, countryChars, stringLength(t, country) + 1); + stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars)); + + local::MyClasspath* cp = static_cast(t->m->classpath); + + local::EmbeddedFile ef(cp, cp->tzMappings, cp->tzMappingsLength); + if (ef.jar == 0 or ef.jarLength == 0 or ef.pathLength == 0) { + return 0; + } + + Finder* finder = local::getFinder(t, ef.jar, ef.jarLength); + if (finder == 0) { + return 0; + } + + System::Region* r = finder->find(ef.path); + if (r == 0) { + return 0; + } + + RESOURCE(System::Region*, r, r->dispose()); + + char tmpPath[MAX_PATH + 1]; + GetTempPathA(MAX_PATH, tmpPath); + + char tmpDir[MAX_PATH + 1]; + vm::snprintf(tmpDir, MAX_PATH, "%s/avian-tmp", tmpPath); + if (_mkdir(tmpDir) != 0 and errno != EEXIST) { + return 0; + } + + RESOURCE(char*, tmpDir, rmdir(tmpDir)); + + char libDir[MAX_PATH + 1]; + vm::snprintf(libDir, MAX_PATH, "%s/lib", tmpDir); + if (mkdir(libDir) != 0 and errno != EEXIST) { + return 0; + } + + RESOURCE(char*, libDir, rmdir(libDir)); + + char file[MAX_PATH + 1]; + vm::snprintf(file, MAX_PATH, "%s/tzmappings", libDir); + FILE* out = vm::fopen(file, "wb"); + if (out == 0) { + return 0; + } + + RESOURCE(char*, file, unlink(file)); + RESOURCE(FILE*, out, fclose(out)); + + if (fwrite(r->start(), 1, r->length(), out) != r->length() + or fflush(out) != 0) + { + return 0; + } + + char* javaTZ = findJavaTZ_md(tmpDir, RUNTIME_ARRAY_BODY(countryChars)); + if (javaTZ) { + object result = makeString(t, "%s", javaTZ); + free(javaTZ); + return reinterpret_cast(result); + } else { + return 0; + } +} +# else // not AVIAN_OPENJDK_SRC extern "C" JNIEXPORT int jio_snprintf(char* dst, size_t size, const char* format, ...) { @@ -3362,21 +3474,5 @@ jio_fprintf(FILE* stream, const char* format, ...) return r; } - -extern "C" JNIEXPORT void* JNICALL -EXPORT(JVM_GetThreadInterruptEvent)() -{ abort(); } - -namespace { HMODULE jvmHandle = 0; } - -extern "C" int JDK_InitJvmHandle() -{ - jvmHandle = GetModuleHandle(0); - return jvmHandle != 0; -} - -extern "C" void* JDK_FindJvmEntry(const char* name) -{ - return voidPointer(GetProcAddress(jvmHandle, name)); -} -#endif +# endif // not AVIAN_OPENJDK_SRC +#endif // PLATFORM_WINDOWS diff --git a/src/common.h b/src/common.h index 316eeef81c..6ab13f23ec 100644 --- a/src/common.h +++ b/src/common.h @@ -143,6 +143,16 @@ typedef uint64_t uintptr_t; #define MACRO_MakeNameXY(FX, LINE) MACRO_XY(FX, LINE) #define MAKE_NAME(FX) MACRO_MakeNameXY(FX, __LINE__) +#define RESOURCE(type, name, release) \ + class MAKE_NAME(Resource_) { \ + public: \ + MAKE_NAME(Resource_)(type name): name(name) { } \ + ~MAKE_NAME(Resource_)() { release; } \ + \ + private: \ + type name; \ + } MAKE_NAME(resource_)(name); + inline void* operator new(size_t, void* p) throw() { return p; } namespace vm { From 75de0a621bbbedbe4a46d0a1115a1924721f75f3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 12:35:31 -0700 Subject: [PATCH 084/274] fix windows.cpp MySystem::now --- src/windows.cpp | 25 +++++++------------------ test/Misc.java | 2 +- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/windows.cpp b/src/windows.cpp index e601b70f33..405d626d82 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -769,24 +769,13 @@ class MySystem: public System { } virtual int64_t now() { - static LARGE_INTEGER frequency; - static LARGE_INTEGER time; - static bool init = true; - - if (init) { - QueryPerformanceFrequency(&frequency); - - if (frequency.QuadPart == 0) { - return 0; - } - - init = false; - } - - QueryPerformanceCounter(&time); - return static_cast - (((static_cast(time.QuadPart)) * 1000.0) / - (static_cast(frequency.QuadPart))); + // We used to use _ftime here, but that only gives us 1-second + // resolution on Windows 7. _ftime_s might work better, but MinGW + // doesn't have it as of this writing. So we use this mess instead: + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((static_cast(time.dwHighDateTime) << 32) + | time.dwLowDateTime) / 10000) - 11644473600000LL; } virtual void exit(int code) { diff --git a/test/Misc.java b/test/Misc.java index c1a5a016d4..57bb0180e6 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -205,6 +205,6 @@ public class Misc { } } - System.out.println(java.util.Calendar.getInstance().toString()); + System.out.println(new java.util.Date().toString()); } } From 580e7e1b3f8a9850d5e175e83f44671fc9a25986 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 12:57:42 -0700 Subject: [PATCH 085/274] remove @Overload annotation since Java 1.5.0_19 chokes on it --- classpath/java/util/Collections.java | 1 - 1 file changed, 1 deletion(-) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index e790c4ed70..eb7c5d462c 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -393,7 +393,6 @@ public class Collections { this.cmp = cmp; } - @Override public int compare(T o1, T o2) { return - cmp.compare(o1, o2); } From 5d5dbd860b1b2cee5054b2c3d94bb4d73391e371 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 8 Nov 2010 00:41:44 +0000 Subject: [PATCH 086/274] fix ARM tails=true build This requires adding LinkRegister to the list of reserved registers, since it must be preserved in the thunk code generated by compileDirectInvoke. An alternative would be to explicitly preserve it in that special case, but that would complicate the code quite a bit. --- src/arm.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 6fca682e8f..13dc298032 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -171,7 +171,6 @@ const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int ThreadRegister = 8; -const int BaseRegister = 11; const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; @@ -914,7 +913,7 @@ moveAndUpdateRM(Context* c, unsigned srcSize UNUSED, Assembler::Register* src, assert(c, dst->offset == 0); assert(c, dst->scale == 1); - emit(c, str(src->low, dst->base, dst->index, dst->offset ? 1 : 0)); + emit(c, str(src->low, dst->base, dst->index, 1)); } } @@ -1599,6 +1598,7 @@ class MyArchitecture: public Assembler::Architecture { virtual bool reserved(int register_) { switch (register_) { + case LinkRegister: case StackRegister: case ThreadRegister: case ProgramCounter: @@ -1624,7 +1624,7 @@ class MyArchitecture: public Assembler::Architecture { virtual int argumentRegister(unsigned index) { assert(&c, index < argumentRegisterCount()); - return index + 0; + return index; } virtual unsigned stackAlignmentInWords() { @@ -1968,7 +1968,7 @@ class MyAssembler: public Assembler { } virtual void adjustFrame(unsigned footprint) { - Register nextStack(0); + Register nextStack(5); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); @@ -1993,23 +1993,25 @@ class MyAssembler: public Assembler { { if (TailCalls) { if (offset) { - Register tmp(0); - Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); - moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); + Register link(LinkRegister); + Memory returnAddressSrc + (StackRegister, BytesPerWord + (footprint * BytesPerWord)); + moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link); - emit(&c, mov(LinkRegister, tmp.low)); - + Register tmp(c.client->acquireTemporary()); Memory stackSrc(StackRegister, footprint * BytesPerWord); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + c.client->releaseTemporary(tmp.low); + if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); Register ras(returnAddressSurrogate); - Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + Memory dst(StackRegister, BytesPerWord + (offset * BytesPerWord)); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } @@ -2035,7 +2037,7 @@ class MyAssembler: public Assembler { assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (TailCalls and argumentFootprint > StackAlignmentInWords) { - Register tmp(0); + Register tmp(5); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); From 36a8ba28e5513c147121342cea91d5f4588001b6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 8 Nov 2010 04:15:31 +0000 Subject: [PATCH 087/274] disable debug logging in compile.cpp --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 7cf8cb700e..e5d7a7df2d 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -40,7 +40,7 @@ namespace { namespace local { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; From 0f0427f23b4c6731104f8f41f8f96353eb425256 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 8 Nov 2010 04:18:10 +0000 Subject: [PATCH 088/274] implement continuations support for ARM --- src/compile-arm.S | 159 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 12 deletions(-) diff --git a/src/compile-arm.S b/src/compile-arm.S index 3ac3310030..dcf1aec53b 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -8,17 +8,13 @@ There is NO WARRANTY for this software. See license.txt for details. */ -#ifdef AVIAN_CONTINUATIONS -# error "Continuations not yet supported on ARM port" -#endif - #include "types.h" .text #define BYTES_PER_WORD 4 -#define LOCAL(x) L##x +#define LOCAL(x) .L##x #ifdef __APPLE__ # define GLOBAL(x) _##x @@ -33,6 +29,15 @@ #define THREAD_EXCEPTION_OFFSET 2156 #define THREAD_EXCEPTION_HANDLER 2160 +#define CONTINUATION_NEXT 4 +#define CONTINUATION_ADDRESS 16 +#define CONTINUATION_RETURN_ADDRESS_OFFSET 20 +#define CONTINUATION_FRAME_POINTER_OFFSET 24 +#define CONTINUATION_LENGTH 28 +#define CONTINUATION_BODY 32 + +#define ARGUMENT_BASE (BYTES_PER_WORD * 2) + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): /* @@ -83,12 +88,8 @@ LOCAL(vmInvoke_argumentTest): // we use r8 to hold the thread pointer, by convention mov r8, r0 -.global GLOBAL(beforecall) -GLOBAL(beforecall): // load and call function address blx r1 -.global GLOBAL(aftercall) -GLOBAL(aftercall): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): @@ -99,6 +100,75 @@ GLOBAL(vmInvoke_returnAddress): .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): +#ifdef AVIAN_CONTINUATIONS + // call the next continuation, if any + ldr r5,[r8,#THREAD_CONTINUATION] + cmp r5,#0 + beq LOCAL(vmInvoke_exit) + + ldr r6,[r5,#CONTINUATION_LENGTH] + lsl r6,r6,#2 + neg r7,r6 + add r7,r7,#-80 + mov r4,sp + str r4,[sp,r7]! + + add r7,r5,#CONTINUATION_BODY + + mov r11,#0 + add r10,sp,#ARGUMENT_BASE + b LOCAL(vmInvoke_continuationTest) + +LOCAL(vmInvoke_continuationLoop): + ldr r9,[r7,r11] + str r9,[r10,r11] + add r11,r11,#4 + +LOCAL(vmInvoke_continuationTest): + cmp r11,r6 + ble LOCAL(vmInvoke_continuationLoop) + + ldr r7,[r5,#CONTINUATION_RETURN_ADDRESS_OFFSET] + ldr r10,LOCAL(vmInvoke_returnAddress_word) + ldr r11,LOCAL(vmInvoke_getAddress_word) +LOCAL(vmInvoke_getAddress): + add r11,pc,r11 + ldr r11,[r11,r10] + str r11,[sp,r7] + + ldr r7,[r5,#CONTINUATION_FRAME_POINTER_OFFSET] + ldr r11,[sp] + add r7,r7,sp + str r11,[r7] + str r7,[sp] + + ldr r7,[r5,#CONTINUATION_NEXT] + str r7,[r8,#THREAD_CONTINUATION] + + // call the continuation unless we're handling an exception + ldr r7,[r8,#THREAD_EXCEPTION] + cmp r7,#0 + bne LOCAL(vmInvoke_handleException) + ldr r7,[r5,#CONTINUATION_ADDRESS] + bx r7 + +LOCAL(vmInvoke_handleException): + // we're handling an exception - call the exception handler instead + mov r11,#0 + str r11,[r8,#THREAD_EXCEPTION] + ldr r11,[r8,#THREAD_EXCEPTION_STACK_ADJUSTMENT] + ldr r9,[sp] + neg r11,r11 + str r9,[sp,r11]! + ldr r11,[r8,#THREAD_EXCEPTION_OFFSET] + str r7,[sp,r11] + + ldr r7,[r8,#THREAD_EXCEPTION_HANDLER] + bx r7 + +LOCAL(vmInvoke_exit): +#endif // AVIAN_CONTINUATIONS + mov ip, #0 str ip, [r8, #THREAD_STACK] @@ -124,6 +194,71 @@ LOCAL(vmInvoke_return): .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): - // vmJumpAndInvoke should only be called when continuations are - // enabled - bkpt +#ifdef AVIAN_CONTINUATIONS + // r0: thread + // r1: address + // r2: (unused) + // r3: stack + // [sp,#0]: argumentFootprint + // [sp,#4]: arguments + // [sp,#8]: frameSize + + ldr r4,[sp] + ldr r5,[sp,#4] + ldr r6,[sp,#8] + + // restore (pseudo)-stack pointer (we don't want to touch the real + // stack pointer, since we haven't copied the arguments yet) + ldr r3,[r3] + + // make everything between sp and r3 one big stack frame while we + // shuffle things around + str r3,[sp] + + // allocate new frame, adding room for callee-saved registers + neg r10,r6 + add r10,r10,#-80 + mov r2,r3 + str r2,[r3,r10]! + + mov r8,r0 + + // copy arguments into place + mov r6,#0 + add r9,r3,#ARGUMENT_BASE + b LOCAL(vmJumpAndInvoke_argumentTest) + +LOCAL(vmJumpAndInvoke_argumentLoop): + ldr r12,[r5,r6] + str r12,[r9,r6] + add r6,r6,#4 + +LOCAL(vmJumpAndInvoke_argumentTest): + cmp r6,r4 + ble LOCAL(vmJumpAndInvoke_argumentLoop) + + // the arguments have been copied, so we can set the real stack + // pointer now + mov sp,r3 + + // set return address to vmInvoke_returnAddress + ldr r10,LOCAL(vmInvoke_returnAddress_word) + ldr r11,LOCAL(vmJumpAndInvoke_getAddress_word) +LOCAL(vmJumpAndInvoke_getAddress): + add r11,pc,r11 + ldr lr,[r11,r10] + + bx r1 +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + bkpt +#endif // not AVIAN_CONTINUATIONS + +LOCAL(vmInvoke_returnAddress_word): + .word GLOBAL(vmInvoke_returnAddress)(GOT) +LOCAL(vmInvoke_getAddress_word): + .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmInvoke_getAddress)+8) +LOCAL(vmJumpAndInvoke_getAddress_word): + .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8) + From 8ca5e9780e577e66dc50976c186c95d18146c23c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 21:23:25 -0700 Subject: [PATCH 089/274] fix OS X build --- makefile | 13 ++++++++++--- src/posix.cpp | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/makefile b/makefile index 1715391afd..fc3d9939c6 100644 --- a/makefile +++ b/makefile @@ -141,6 +141,10 @@ build-lflags = -lz -lpthread -ldl lflags = $(common-lflags) -lpthread -ldl +version-script-flag = -Wl,--version-script=openjdk.ld + +jvm-flags = -L$(build) -ljvm + build-system = posix system = posix @@ -168,7 +172,10 @@ ifeq ($(arch),arm) endif ifeq ($(platform),darwin) + version-script-flag = + jvm-flags = $(build)/libjvm.jnilib build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) + build-lflags += -framework CoreFoundation lflags = $(common-lflags) -ldl -framework CoreFoundation -framework CoreServices ifeq ($(bootimage),true) bootimage-lflags = -Wl,-segprot,__RWX,rwx,rwx @@ -736,8 +743,8 @@ ifdef msvc -IMPLIB:$(build)/$(name).lib -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);2" else - $(ld) $(^) -Wl,--version-script=openjdk.ld \ - $(shared) $(lflags) $(bootimage-lflags) -o $(@) + $(ld) $(^) $(version-script-flag) $(shared) $(lflags) $(bootimage-lflags) \ + -o $(@) endif $(strip) $(strip-all) $(@) @@ -748,7 +755,7 @@ ifdef msvc -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(<) -L$(build) -ljvm $(lflags) -o $(@) + $(ld) $(<) $(jvm-flags) $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/src/posix.cpp b/src/posix.cpp index 1c3e0c6d09..cf7d600bb5 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -8,14 +8,14 @@ There is NO WARRANTY for this software. See license.txt for details. */ +#define __STDC_CONSTANT_MACROS + #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" # undef assert # define _XOPEN_SOURCE #endif -#define __STDC_CONSTANT_MACROS - #include "sys/mman.h" #include "sys/types.h" #include "sys/stat.h" From 632e50efe61c6b82fcf290efa992f452a7255643 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 02:13:23 +0000 Subject: [PATCH 090/274] fix non-continuations ARM build --- src/compile-arm.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compile-arm.S b/src/compile-arm.S index dcf1aec53b..555c61476b 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -249,11 +249,6 @@ LOCAL(vmJumpAndInvoke_getAddress): ldr lr,[r11,r10] bx r1 -#else // not AVIAN_CONTINUATIONS - // vmJumpAndInvoke should only be called when continuations are - // enabled - bkpt -#endif // not AVIAN_CONTINUATIONS LOCAL(vmInvoke_returnAddress_word): .word GLOBAL(vmInvoke_returnAddress)(GOT) @@ -262,3 +257,8 @@ LOCAL(vmInvoke_getAddress_word): LOCAL(vmJumpAndInvoke_getAddress_word): .word _GLOBAL_OFFSET_TABLE_-(LOCAL(vmJumpAndInvoke_getAddress)+8) +#else // not AVIAN_CONTINUATIONS + // vmJumpAndInvoke should only be called when continuations are + // enabled + bkpt +#endif // not AVIAN_CONTINUATIONS From 51ba49def6dda47153a116523b830b2650983b65 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 8 Nov 2010 20:48:08 -0700 Subject: [PATCH 091/274] enable ARM cross builds --- makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index f0dcab31a5..9031e7a628 100644 --- a/makefile +++ b/makefile @@ -145,8 +145,9 @@ ifeq ($(arch),powerpc) pointer-size = 4 endif ifeq ($(arch),arm) - asm = arm - pointer-size = 4 + asm = arm + pointer-size = 4 + cflags += -Wno-psabi -march=armv5t endif ifeq ($(platform),darwin) @@ -179,6 +180,16 @@ ifeq ($(platform),darwin) endif endif +ifeq ($(arch),arm) + ifneq ($(arch),$(build-arch)) + cxx = arm-linux-gnueabi-g++ + cc = arm-linux-gnueabi-gcc + ar = arm-linux-gnueabi-ar + ranlib = arm-linux-gnueabi-ranlib + strip = arm-linux-gnueabi-strip + endif +endif + ifeq ($(platform),windows) inc = "$(root)/win32/include" lib = "$(root)/win32/lib" From 3d18f88ad9fbde26de928d63c235f116405433f4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 10:22:23 -0700 Subject: [PATCH 092/274] fix Runtime.exec bugs The first bug affected POSIX systems: if the app never called Process.waitFor, we'd never call waitpid on the child and thus leak a zombie process. This patch ensures that we always call waitpid by spawning a thread to handle it. The second bug affected Windows systems: we weren't closing the child's ends of the stdin, stdout, and stderr pipes after process creation, which lead to us blocking forever while reading from the child's stdout or stderr. --- classpath/java-lang.cpp | 31 ++---------- classpath/java/lang/Runtime.java | 87 ++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 48 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index ea37b2f275..e6751163ed 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -191,6 +191,10 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, BOOL success = CreateProcess(0, (LPSTR) RUNTIME_ARRAY_BODY(line), 0, 0, 1, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, 0, 0, &si, &pi); + + CloseHandle(in[1]); + CloseHandle(out[0]); + CloseHandle(err[1]); if (not success) { throwNew(e, "java/io/IOException", getErrorStr(GetLastError())); @@ -202,19 +206,6 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) -{ - DWORD exitCode; - BOOL success = GetExitCodeProcess(reinterpret_cast(pid), &exitCode); - if(not success){ - throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); - } else if(exitCode == STILL_ACTIVE){ - throwNew(e, "java/lang/IllegalThreadStateException", "Process is still active"); - } - return exitCode; -} - extern "C" JNIEXPORT jint JNICALL Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) { @@ -317,20 +308,6 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, fcntl(err[0], F_SETFD, FD_CLOEXEC); } -extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_exitValue(JNIEnv* e, jclass, jlong pid) -{ - int status; - pid_t returned = waitpid(pid, &status, WNOHANG); - if(returned == 0){ - throwNewErrno(e, "java/lang/IllegalThreadStateException"); - } else if(returned == -1){ - throwNewErrno(e, "java/lang/Exception"); - } - - return WEXITSTATUS(status); -} - extern "C" JNIEXPORT jint JNICALL Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) { diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index d1accb33fd..341d0ed143 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -43,27 +43,71 @@ public class Runtime { } } - public Process exec(String command) throws IOException { - long[] process = new long[4]; + public Process exec(String command) { StringTokenizer t = new StringTokenizer(command); String[] cmd = new String[t.countTokens()]; for (int i = 0; i < cmd.length; i++) cmd[i] = t.nextToken(); - exec(cmd, process); - return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); + + return exec(cmd); } - public Process exec(String[] command) { - long[] process = new long[4]; - exec(command, process); - return new MyProcess(process[0], (int) process[1], (int) process[2], (int) process[3]); + public MyProcess exec(final String[] command) { + final MyProcess[] process = new MyProcess[1]; + final Throwable[] exception = new Throwable[1]; + + synchronized (process) { + Thread t = new Thread() { + public void run() { + synchronized (process) { + try { + long[] info = new long[4]; + exec(command, info); + process[0] = new MyProcess + (info[0], (int) info[1], (int) info[2], (int) info[3]); + + MyProcess p = process[0]; + synchronized (p) { + try { + if (p.pid != 0) { + p.exitCode = Runtime.waitFor(p.pid); + p.pid = 0; + } + } finally { + p.notifyAll(); + } + } + } catch (Throwable e) { + exception[0] = e; + } finally { + process.notifyAll(); + } + } + } + }; + t.setDaemon(true); + t.start(); + + while (process[0] == null && exception[0] == null) { + try { + process.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + if (exception[0] != null) { + throw new RuntimeException(exception[0]); + } + + return process[0]; } public native void addShutdownHook(Thread t); - private static native void exec(String[] command, long[] process); - - private static native int exitValue(long pid); + private static native void exec(String[] command, long[] process) + throws IOException; private static native int waitFor(long pid); @@ -95,13 +139,6 @@ public class Runtime { throw new RuntimeException("not implemented"); } - public int exitValue() { - if (pid != 0) { - exitCode = Runtime.exitValue(pid); - } - return exitCode; - } - public InputStream getInputStream() { return new FileInputStream(new FileDescriptor(in)); } @@ -114,11 +151,19 @@ public class Runtime { return new FileInputStream(new FileDescriptor(err)); } - public int waitFor() throws InterruptedException { + public synchronized int exitValue() { if (pid != 0) { - exitCode = Runtime.waitFor(pid); - pid = 0; + throw new IllegalThreadStateException(); } + + return exitCode; + } + + public synchronized int waitFor() throws InterruptedException { + while (pid != 0) { + wait(); + } + return exitCode; } } From ababc5748dc1f267f93e5c7d7bcb62cfcedcec20 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 11:21:55 -0700 Subject: [PATCH 093/274] fix regression in last commit My last commit unintentionally changed the return type of Runtime.exec to Runtime.MyProcess instead of Process. --- classpath/java/lang/Runtime.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 341d0ed143..a59339bfcb 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -52,7 +52,7 @@ public class Runtime { return exec(cmd); } - public MyProcess exec(final String[] command) { + public Process exec(final String[] command) { final MyProcess[] process = new MyProcess[1]; final Throwable[] exception = new Throwable[1]; From 110f41b7a07e71d66858e812bdfe99719da2ff02 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 11:28:58 -0700 Subject: [PATCH 094/274] ARM makefile tweaks --- makefile | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/makefile b/makefile index 9031e7a628..8c2f666220 100644 --- a/makefile +++ b/makefile @@ -147,7 +147,15 @@ endif ifeq ($(arch),arm) asm = arm pointer-size = 4 - cflags += -Wno-psabi -march=armv5t + cflags += -Wno-psabi + + ifneq ($(arch),$(build-arch)) + cxx = arm-linux-gnueabi-g++ + cc = arm-linux-gnueabi-gcc + ar = arm-linux-gnueabi-ar + ranlib = arm-linux-gnueabi-ranlib + strip = arm-linux-gnueabi-strip + endif endif ifeq ($(platform),darwin) @@ -180,16 +188,6 @@ ifeq ($(platform),darwin) endif endif -ifeq ($(arch),arm) - ifneq ($(arch),$(build-arch)) - cxx = arm-linux-gnueabi-g++ - cc = arm-linux-gnueabi-gcc - ar = arm-linux-gnueabi-ar - ranlib = arm-linux-gnueabi-ranlib - strip = arm-linux-gnueabi-strip - endif -endif - ifeq ($(platform),windows) inc = "$(root)/win32/include" lib = "$(root)/win32/lib" From 70fcbc2788f6304bcc99b5761d1f92b7ca165414 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 11:34:56 -0700 Subject: [PATCH 095/274] freeze index site in BoundsCheckEvent::compile This ensures we don't use it as a temporary register when generating the comparison. --- src/compiler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compiler.cpp b/src/compiler.cpp index 44217336a2..dcfd325d42 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4885,10 +4885,14 @@ class BoundsCheckEvent: public Event { lengthOffset, NoRegister, 1); length.acquired = true; + index->source->freeze(c, index); + ConstantSite next(nextPromise); apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, &length, BytesPerWord, &next, &next); + index->source->thaw(c, index); + if (constant == 0) { outOfBoundsPromise->offset = a->offset(); } From 7978102cb6e3dbe00435183cadaa13ee82f1ba9c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 11:36:38 -0700 Subject: [PATCH 096/274] use register for indexing if constant offset is too large (or too small) Immediate indexes on ARM must be no more than 12 bits, so we must use a temporary register for values which don't fit. --- src/arm.cpp | 26 ++++++++++++++++++++++++-- test/Arrays.java | 6 ++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 13dc298032..fd3ce34ee6 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -866,7 +866,7 @@ store(Context* c, unsigned size, Assembler::Register* src, } if (release) c->client->releaseTemporary(normalized); - } else { + } else if (size == 8 or abs(offset) == (abs(offset) & 0xFFF)) { switch (size) { case 1: emit(c, strbi(src->low, base, offset)); @@ -888,6 +888,15 @@ store(Context* c, unsigned size, Assembler::Register* src, default: abort(c); } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + ResolvedPromise offsetPromise(offset); + Assembler::Constant offsetConstant(&offsetPromise); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + + store(c, size, src, base, 0, tmp.low, 1, false); + + c->client->releaseTemporary(tmp.low); } } @@ -962,7 +971,9 @@ load(Context* c, unsigned srcSize, int base, int offset, int index, } if (release) c->client->releaseTemporary(normalized); - } else { + } else if ((srcSize == 8 and dstSize == 8) + or abs(offset) == (abs(offset) & 0xFFF)) + { switch (srcSize) { case 1: if (signExtend) { @@ -996,6 +1007,15 @@ load(Context* c, unsigned srcSize, int base, int offset, int index, default: abort(c); } + } else { + Assembler::Register tmp(c->client->acquireTemporary()); + ResolvedPromise offsetPromise(offset); + Assembler::Constant offsetConstant(&offsetPromise); + moveCR(c, BytesPerWord, &offsetConstant, BytesPerWord, &tmp); + + load(c, srcSize, base, 0, tmp.low, 1, dstSize, dst, false, signExtend); + + c->client->releaseTemporary(tmp.low); } } @@ -1115,6 +1135,8 @@ compareRR(Context* c, unsigned aSize UNUSED, Assembler::Register* a, unsigned bSize UNUSED, Assembler::Register* b) { assert(c, aSize == 4 and bSize == 4); + assert(c, b->low != a->low); + emit(c, cmp(b->low, a->low)); } diff --git a/test/Arrays.java b/test/Arrays.java index 2dd2bcfc30..1c620d17b3 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -54,5 +54,11 @@ public class Arrays { p = false; expect(array[1] == array[p ? 0 : 1]); } + + { int[] array = new int[1024]; + array[1023] = -1; + expect(array[1023] == -1); + expect(array[1022] == 0); + } } } From 2d60398e63efd6b6e5deedfef9e233549aab5083 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 12:38:23 -0700 Subject: [PATCH 097/274] fix bug which caused Runtime.exec to block until process exits --- classpath/java/lang/Runtime.java | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index a59339bfcb..777e54398b 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -65,24 +65,26 @@ public class Runtime { exec(command, info); process[0] = new MyProcess (info[0], (int) info[1], (int) info[2], (int) info[3]); - - MyProcess p = process[0]; - synchronized (p) { - try { - if (p.pid != 0) { - p.exitCode = Runtime.waitFor(p.pid); - p.pid = 0; - } - } finally { - p.notifyAll(); - } - } } catch (Throwable e) { exception[0] = e; } finally { process.notifyAll(); } } + + MyProcess p = process[0]; + if (p != null) { + synchronized (p) { + try { + if (p.pid != 0) { + p.exitCode = Runtime.waitFor(p.pid); + p.pid = 0; + } + } finally { + p.notifyAll(); + } + } + } } }; t.setDaemon(true); From 44f55673d683be254e684cfd0f0fca27a5f4446d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 14:56:26 -0700 Subject: [PATCH 098/274] fix handle leaks in Windows Process implementation --- classpath/java-lang.cpp | 23 ++++++++++++++--------- classpath/java/lang/Runtime.java | 24 ++++++++++++++++-------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index e6751163ed..ee8a6456d4 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -165,17 +165,17 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, SetHandleInformation(in[0], HANDLE_FLAG_INHERIT, 0); jlong inDescriptor = static_cast(descriptor(e, in[0])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 1, 1, &inDescriptor); + e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); SetHandleInformation(out[1], HANDLE_FLAG_INHERIT, 0); jlong outDescriptor = static_cast(descriptor(e, out[1])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 2, 1, &outDescriptor); + e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); SetHandleInformation(err[0], HANDLE_FLAG_INHERIT, 0); jlong errDescriptor = static_cast(descriptor(e, err[0])); if(e->ExceptionCheck()) return; - e->SetLongArrayRegion(process, 3, 1, &errDescriptor); + e->SetLongArrayRegion(process, 4, 1, &errDescriptor); PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); @@ -203,11 +203,12 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jlong pid = reinterpret_cast(pi.hProcess); e->SetLongArrayRegion(process, 0, 1, &pid); - + jlong tid = reinterpret_cast(pi.hThread); + e->SetLongArrayRegion(process, 1, 1, &tid); } extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) +Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid, jlong tid) { DWORD exitCode; WaitForSingleObject(reinterpret_cast(pid), INFINITE); @@ -215,6 +216,10 @@ Java_java_lang_Runtime_waitFor(JNIEnv* e, jclass, jlong pid) if(not success){ throwNew(e, "java/lang/Exception", getErrorStr(GetLastError())); } + + CloseHandle(reinterpret_cast(pid)); + CloseHandle(reinterpret_cast(tid)); + return exitCode; } #else @@ -240,15 +245,15 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, makePipe(e, in); if(e->ExceptionCheck()) return; jlong inDescriptor = static_cast(in[0]); - e->SetLongArrayRegion(process, 1, 1, &inDescriptor); + e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast(out[1]); - e->SetLongArrayRegion(process, 2, 1, &outDescriptor); + e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast(err[0]); - e->SetLongArrayRegion(process, 3, 1, &errDescriptor); + e->SetLongArrayRegion(process, 4, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { @@ -309,7 +314,7 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, } extern "C" JNIEXPORT jint JNICALL -Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid) +Java_java_lang_Runtime_waitFor(JNIEnv*, jclass, jlong pid, jlong) { bool finished = false; int status; diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 777e54398b..55f16cd456 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -43,7 +43,7 @@ public class Runtime { } } - public Process exec(String command) { + public Process exec(String command) throws IOException { StringTokenizer t = new StringTokenizer(command); String[] cmd = new String[t.countTokens()]; for (int i = 0; i < cmd.length; i++) @@ -52,7 +52,7 @@ public class Runtime { return exec(cmd); } - public Process exec(final String[] command) { + public Process exec(final String[] command) throws IOException { final MyProcess[] process = new MyProcess[1]; final Throwable[] exception = new Throwable[1]; @@ -61,10 +61,11 @@ public class Runtime { public void run() { synchronized (process) { try { - long[] info = new long[4]; + long[] info = new long[5]; exec(command, info); process[0] = new MyProcess - (info[0], (int) info[1], (int) info[2], (int) info[3]); + (info[0], info[1], (int) info[2], (int) info[3], + (int) info[4]); } catch (Throwable e) { exception[0] = e; } finally { @@ -77,8 +78,9 @@ public class Runtime { synchronized (p) { try { if (p.pid != 0) { - p.exitCode = Runtime.waitFor(p.pid); + p.exitCode = Runtime.waitFor(p.pid, p.tid); p.pid = 0; + p.tid = 0; } } finally { p.notifyAll(); @@ -100,7 +102,11 @@ public class Runtime { } if (exception[0] != null) { - throw new RuntimeException(exception[0]); + if (exception[0] instanceof IOException) { + throw new IOException(exception[0]); + } else { + throw new RuntimeException(exception[0]); + } } return process[0]; @@ -111,7 +117,7 @@ public class Runtime { private static native void exec(String[] command, long[] process) throws IOException; - private static native int waitFor(long pid); + private static native int waitFor(long pid, long tid); private static native void load(String name, boolean mapName); @@ -125,13 +131,15 @@ public class Runtime { private static class MyProcess extends Process { private long pid; + private long tid; private final int in; private final int out; private final int err; private int exitCode; - public MyProcess(long pid, int in, int out, int err) { + public MyProcess(long pid, long tid, int in, int out, int err) { this.pid = pid; + this.tid = tid; this.in = in; this.out = out; this.err = err; From f64d6c857bde9c525f3f49bdac5ae9bcbd2e63ac Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 15:46:16 -0700 Subject: [PATCH 099/274] clean up OS resources immediately upon thread exit Previously, we waited until the next GC to do this, but that can be too long for workloads which create a lot of short-lived threads but don't do much allocation. --- src/machine.cpp | 16 ++++++++++++++-- src/machine.h | 6 +++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 01b766de93..fedbf9c35f 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -45,7 +45,11 @@ void join(Thread* t, Thread* o) { if (t != o) { - o->systemThread->join(); + if (o->state != Thread::ZombieState + and o->state != Thread::JoinedState) + { + o->systemThread->join(); + } o->state = Thread::JoinedState; } } @@ -2281,6 +2285,12 @@ Thread::exit() } else { threadPeer(this, javaThread) = 0; enter(this, Thread::ZombieState); + + lock->dispose(); + lock = 0; + + systemThread->dispose(); + systemThread = 0; } } } @@ -2288,7 +2298,9 @@ Thread::exit() void Thread::dispose() { - lock->dispose(); + if (lock) { + lock->dispose(); + } if (systemThread) { systemThread->dispose(); diff --git a/src/machine.h b/src/machine.h index 4bdfccfc24..8d861717ef 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2746,7 +2746,11 @@ notifyAll(Thread* t, object o) inline void interrupt(Thread*, Thread* target) { - target->systemThread->interrupt(); + if (target->state != Thread::ZombieState + and target->state != Thread::JoinedState) + { + target->systemThread->interrupt(); + } } inline void From 6f555d42026af74feed5b0a61a47eafd6d7809c8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 17:31:42 -0700 Subject: [PATCH 100/274] minor code cleanup in compile.cpp --- src/compile.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index e5d7a7df2d..2b1688e63a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5995,14 +5995,6 @@ compileMethod2(MyThread* t, void* ip) t->trace->targetMethod = 0; } - if (false) { - compile(t, codeAllocator(t), 0, resolveMethod - (t, t->m->loader, - "org/eclipse/swt/widgets/TableItem", - "getBounds", - "(IIZZZZJ)Lorg/eclipse/swt/internal/win32/RECT;")); - } - if (UNLIKELY(t->exception)) { return 0; } else { @@ -7485,12 +7477,11 @@ class MyProcessor: public Processor { if (false) { compile(static_cast(t), - local::codeAllocator(static_cast(t)), 0, - resolveMethod(t, t->m->loader, - "com/ecovate/nat/logic/Cache", - "findInCache", - "(Ljava/lang/String;Ljava/lang/String;JZ)Lcom/ecovate/shared/xmlrpc/Resource;")); - trap(); + local::codeAllocator(static_cast(t)), 0, resolveMethod + (t, t->m->loader, + "org/eclipse/swt/widgets/Display", + "runSettings", + "()Z")); } compile(static_cast(t), From f21d2b68b8a0dfbef4013fa9cf04d9dbc87de7d0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 9 Nov 2010 17:31:52 -0700 Subject: [PATCH 101/274] fix another ARM immediate offset bug Some memory operations can only handle 8-bit immediate values, so we need to use a temporary register for those which don't fit. --- src/arm.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index fd3ce34ee6..ea7b458531 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -44,7 +44,7 @@ inline int XFERI(int cond, int P, int U, int B, int W, int L, int Rn, int Rd, in inline int XFER2(int cond, int P, int U, int W, int L, int Rn, int Rd, int S, int H, int Rm) { return cond<<28 | P<<24 | U<<23 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | 1<<7 | S<<6 | H<<5 | 1<<4 | Rm; } inline int XFER2I(int cond, int P, int U, int W, int L, int Rn, int Rd, int offsetH, int S, int H, int offsetL) -{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | offsetL; } +{ return cond<<28 | P<<24 | U<<23 | 1<<22 | W<<21 | L<<20 | Rn<<16 | Rd<<12 | offsetH<<8 | 1<<7 | S<<6 | H<<5 | 1<<4 | (offsetL&0xf); } inline int BLOCKXFER(int cond, int P, int U, int S, int W, int L, int Rn, int rlist) { return cond<<28 | 4<<25 | P<<24 | U<<23 | S<<22 | W<<21 | L<<20 | Rn<<16 | rlist; } inline int SWI(int cond, int imm) @@ -866,7 +866,10 @@ store(Context* c, unsigned size, Assembler::Register* src, } if (release) c->client->releaseTemporary(normalized); - } else if (size == 8 or abs(offset) == (abs(offset) & 0xFFF)) { + } else if (size == 8 + or abs(offset) == (abs(offset) & 0xFF) + or (size != 2 and abs(offset) == (abs(offset) & 0xFFF))) + { switch (size) { case 1: emit(c, strbi(src->low, base, offset)); @@ -972,7 +975,10 @@ load(Context* c, unsigned srcSize, int base, int offset, int index, if (release) c->client->releaseTemporary(normalized); } else if ((srcSize == 8 and dstSize == 8) - or abs(offset) == (abs(offset) & 0xFFF)) + or abs(offset) == (abs(offset) & 0xFF) + or (srcSize != 2 + and (srcSize != 1 or not signExtend) + and abs(offset) == (abs(offset) & 0xFFF))) { switch (srcSize) { case 1: From 26a59612bbc57814dd4b31a3c2f04d865dbf6990 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 12 Nov 2010 16:53:16 -0700 Subject: [PATCH 102/274] fix native Windows GCC 3.4 build --- makefile | 2 +- src/compile.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/makefile b/makefile index fc3d9939c6..ff4de6b9ec 100644 --- a/makefile +++ b/makefile @@ -233,7 +233,7 @@ ifeq ($(platform),windows) # ranlib = i586-mingw32msvc-ranlib # strip = i586-mingw32msvc-strip else - build-platform = windows + build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" build-cflags = $(common-cflags) -I$(src) -mthreads ifeq ($(build-platform),cygwin) diff --git a/src/compile.cpp b/src/compile.cpp index b9858a1b71..5c80c8de8f 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6134,11 +6134,11 @@ compileVirtualMethod(MyThread* t) uint64_t invokeNativeFast(MyThread* t, object method, void* function) { - return reinterpret_cast(function) - (t, method, - static_cast(t->stack) - + t->arch->frameFooterSize() - + t->arch->frameReturnAddressSize()); + FastNativeFunction f; memcpy(&f, &function, sizeof(void*)); + return f(t, method, + static_cast(t->stack) + + t->arch->frameFooterSize() + + t->arch->frameReturnAddressSize()); } uint64_t From 0ca6c3ed53358b39905f73c831824fd59700ba56 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 12 Nov 2010 18:29:12 -0700 Subject: [PATCH 103/274] fix native Windows GCC 3.4 OpenJDK build --- makefile | 21 +++++++++++++++------ src/classpath-openjdk.cpp | 24 ++++++++++++------------ src/x86.h | 13 +++++++++++++ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/makefile b/makefile index ff4de6b9ec..8a2ea85182 100644 --- a/makefile +++ b/makefile @@ -54,6 +54,18 @@ test-executable = $(executable) boot-classpath = $(classpath-build) embed-prefix = /avian-embedded +native-path = echo + +ifeq ($(build-platform),cygwin) + native-path = cygpath -m +endif + +path-separator = : + +ifneq (,$(filter mingw32 cygwin,$(build-platform))) + path-separator = ; +endif + ifdef openjdk ifdef openjdk-src include openjdk-src.mk @@ -72,11 +84,11 @@ ifdef openjdk options := $(options)-openjdk test-executable = $(executable-dynamic) library-path = LD_LIBRARY_PATH=$(build) - javahome = $(openjdk)/jre + javahome = "$$($(native-path) "$(openjdk)/jre")" endif classpath = openjdk - boot-classpath := $(boot-classpath):$(openjdk)/jre/lib/rt.jar + boot-classpath := "$(boot-classpath)$(path-separator)$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" build-javahome = $(openjdk)/jre endif @@ -127,7 +139,7 @@ warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ - -DUSE_ATOMIC_OPERATIONS "-DAVIAN_JAVA_HOME=\"$(javahome)\"" \ + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ @@ -157,8 +169,6 @@ so-suffix = .so shared = -shared -native-path = echo - ifeq ($(arch),i386) pointer-size = 4 endif @@ -241,7 +251,6 @@ ifeq ($(platform),windows) build-cflags += -mno-cygwin lflags += -mno-cygwin cflags += -mno-cygwin - native-path = cygpath -m endif endif diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index a27c4ac9f4..13cab76928 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1528,11 +1528,11 @@ Avian_sun_misc_Unsafe_compareAndSwapInt { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); - int32_t expect = arguments[4]; - int32_t update = arguments[5]; + uint32_t expect = arguments[4]; + uint32_t update = arguments[5]; - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); + return atomicCompareAndSwap32 + (&cast(target, offset), expect, update); } extern "C" JNIEXPORT int64_t JNICALL @@ -1541,11 +1541,11 @@ Avian_sun_misc_Unsafe_compareAndSwapObject { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); - intptr_t expect = arguments[4]; - intptr_t update = arguments[5]; + uintptr_t expect = arguments[4]; + uintptr_t update = arguments[5]; - bool success = __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); + bool success = atomicCompareAndSwap + (&cast(target, offset), expect, update); if (success) { mark(t, target, offset); @@ -1560,11 +1560,11 @@ Avian_sun_misc_Unsafe_compareAndSwapLong { object target = reinterpret_cast(arguments[1]); int64_t offset; memcpy(&offset, arguments + 2, 8); - int64_t expect; memcpy(&expect, arguments + 4, 8); - int64_t update; memcpy(&update, arguments + 6, 8); + uint64_t expect; memcpy(&expect, arguments + 4, 8); + uint64_t update; memcpy(&update, arguments + 6, 8); - return __sync_bool_compare_and_swap - (&cast(target, offset), expect, update); + return atomicCompareAndSwap64 + (&cast(target, offset), expect, update); } extern "C" JNIEXPORT int64_t JNICALL diff --git a/src/x86.h b/src/x86.h index 93278cdd7d..f5602b8015 100644 --- a/src/x86.h +++ b/src/x86.h @@ -223,6 +223,19 @@ atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_) (reinterpret_cast(p), new_, old); #elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) return __sync_bool_compare_and_swap(p, old, new_); +#elif defined ARCH_x86_32 + uint8_t result; + + __asm__ __volatile__("lock; cmpxchg8b %0; setz %1" + : "=m"(*p), "=q"(result) + : "a"(static_cast(old)), + "d"(static_cast(old >> 32)), + "b"(static_cast(new_)), + "c"(static_cast(new_ >> 32)), + "m"(*p) + : "memory"); + + return result != 0; #else uint8_t result; From 46be43a0e37e9480db5c837071224c3849c63022 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 12 Nov 2010 19:04:17 -0700 Subject: [PATCH 104/274] fix MSYS OpenJDK build --- makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 8a2ea85182..0fe5c503da 100644 --- a/makefile +++ b/makefile @@ -245,7 +245,8 @@ ifeq ($(platform),windows) else build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" - build-cflags = $(common-cflags) -I$(src) -mthreads + build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads + build-lflags = -L$(lib) $(common-lflags) ifeq ($(build-platform),cygwin) build-lflags += -mno-cygwin build-cflags += -mno-cygwin From 6bf74bf380d1fc2d89a24a4620c13e962c62a5a9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 13 Nov 2010 19:28:05 -0700 Subject: [PATCH 105/274] optimize loads of constant values by using PC-relative addressing on ARM Previously, loading an arbitrary 32-bit constant required up to four instructions (128 bytes), since we did so one byte at a time via immediate-mode operations. The preferred way to load constants on ARM is via PC-relative addressing, but this is challenging because immediate memory offsets are limited to 4096 bytes in either direction. We frequently need to compile methods which are larger than 4096, or even 8192, bytes, so we must intersperse code and data if we want to use PC-relative loads everywhere. This commit enables pervasive PC-relative loads by handling the following cases: 1. Method is shorter than 4096 bytes: append data table to end 2. Method is longer than 4096 bytes, but no basic block is longer than 4096 bytes: insert data tables as necessary after blocks, taking care to minimize the total number of tables 3. Method is longer than 4096 bytes, and some blocks are longer than 4096 bytes: split large basic blocks and insert data tables as above --- src/arm.cpp | 507 +++++++++++++++++++++++++++++------------------ src/assembler.h | 4 +- src/compile.cpp | 44 ++-- src/compiler.cpp | 4 +- src/posix.cpp | 1 + src/powerpc.cpp | 8 +- src/x86.cpp | 8 +- 7 files changed, 348 insertions(+), 228 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index ea7b458531..27ba7d4e10 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -175,20 +175,46 @@ const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; +const unsigned PoolOffsetMask = 0xFFF; + +const bool DebugPool = false; + +class Context; +class MyBlock; +class PoolOffset; +class PoolEvent; + +void +resolve(MyBlock*); + +unsigned +padding(MyBlock*, unsigned); + class MyBlock: public Assembler::Block { public: - MyBlock(unsigned offset): - next(0), offset(offset), start(~0), size(0) + MyBlock(Context* context, unsigned offset): + context(context), next(0), poolOffsetHead(0), poolOffsetTail(0), + lastPoolOffsetTail(0), poolEventHead(0), poolEventTail(0), + lastEventOffset(0), offset(offset), start(~0), size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); - return start + size; + ::resolve(this); + + return start + size + padding(this, size); } + Context* context; MyBlock* next; + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; + PoolOffset* lastPoolOffsetTail; + PoolEvent* poolEventHead; + PoolEvent* poolEventTail; + unsigned lastEventOffset; unsigned offset; unsigned start; unsigned size; @@ -201,8 +227,9 @@ class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), constantPool(0), constantPoolCount(0) + firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(this, 0)), + lastBlock(firstBlock), poolOffsetHead(0), poolOffsetTail(0), + constantPool(0), constantPoolCount(0) { } System* s; @@ -213,6 +240,8 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; ConstantPoolEntry* constantPool; unsigned constantPoolCount; }; @@ -302,7 +331,8 @@ class Offset: public Promise { virtual int64_t value() { assert(c, resolved()); - return block->start + (offset - block->offset); + unsigned o = offset - block->offset; + return block->start + padding(block, o) + o; } Context* c; @@ -324,7 +354,7 @@ bounded(int right, int left, int32_t v) } void* -updateOffset(System* s, uint8_t* instruction, bool conditional UNUSED, int64_t value) +updateOffset(System* s, uint8_t* instruction, int64_t value) { // ARM's PC is two words ahead, and branches drop the bottom 2 bits. int32_t v = (reinterpret_cast(value) - (instruction + 8)) >> 2; @@ -341,56 +371,48 @@ updateOffset(System* s, uint8_t* instruction, bool conditional UNUSED, int64_t v class OffsetListener: public Promise::Listener { public: - OffsetListener(System* s, uint8_t* instruction, bool conditional): + OffsetListener(System* s, uint8_t* instruction): s(s), - instruction(instruction), - conditional(conditional) + instruction(instruction) { } virtual bool resolve(int64_t value, void** location) { - void* p = updateOffset(s, instruction, conditional, value); + void* p = updateOffset(s, instruction, value); if (location) *location = p; return false; } System* s; uint8_t* instruction; - bool conditional; }; class OffsetTask: public Task { public: - OffsetTask(Task* next, Promise* promise, Promise* instructionOffset, - bool conditional): + OffsetTask(Task* next, Promise* promise, Promise* instructionOffset): Task(next), promise(promise), - instructionOffset(instructionOffset), - conditional(conditional) + instructionOffset(instructionOffset) { } virtual void run(Context* c) { if (promise->resolved()) { updateOffset - (c->s, c->result + instructionOffset->value(), conditional, - promise->value()); + (c->s, c->result + instructionOffset->value(), promise->value()); } else { new (promise->listen(sizeof(OffsetListener))) - OffsetListener(c->s, c->result + instructionOffset->value(), - conditional); + OffsetListener(c->s, c->result + instructionOffset->value()); } } Promise* promise; Promise* instructionOffset; - bool conditional; }; void -appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, - bool conditional) +appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset) { c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask - (c->tasks, promise, instructionOffset, conditional); + (c->tasks, promise, instructionOffset); } inline unsigned @@ -449,6 +471,12 @@ inline int newTemp(Context* con) { return con->client->acquireTemporary(); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } +inline void +write4(uint8_t* dst, uint32_t v) +{ + memcpy(dst, &v, 4); +} + void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { @@ -517,89 +545,11 @@ void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant emit(con, lsri(t->low, b->low, getValue(a))); } -void -updateImmediate(System* s, void* dst, int64_t src, unsigned size, bool) -{ - switch (size) { - case 4: { - int32_t* p = static_cast(dst); - int r = (p[0] >> 12) & 15; - - p[0] = movi(r, lo8(src)); - p[1] = orri(r, r, hi8(src), 12); - p[2] = orri(r, r, lo8(hi16(src)), 8); - p[3] = orri(r, r, hi8(hi16(src)), 4); - } break; - - default: abort(s); - } -} - -class ImmediateListener: public Promise::Listener { - public: - ImmediateListener(System* s, void* dst, unsigned size, unsigned offset, - bool address): - s(s), dst(dst), size(size), offset(offset), address(address) - { } - - virtual bool resolve(int64_t value, void** location) { - updateImmediate(s, dst, value, size, address); - if (location) *location = static_cast(dst) + offset; - return false; - } - - System* s; - void* dst; - unsigned size; - unsigned offset; - bool address; -}; - -class ImmediateTask: public Task { - public: - ImmediateTask(Task* next, Promise* promise, Promise* offset, unsigned size, - unsigned promiseOffset, bool address): - Task(next), - promise(promise), - offset(offset), - size(size), - promiseOffset(promiseOffset), - address(address) - { } - - virtual void run(Context* c) { - if (promise->resolved()) { - updateImmediate - (c->s, c->result + offset->value(), promise->value(), size, address); - } else { - new (promise->listen(sizeof(ImmediateListener))) ImmediateListener - (c->s, c->result + offset->value(), size, promiseOffset, address); - } - } - - Promise* promise; - Promise* offset; - unsigned size; - unsigned promiseOffset; - bool address; -}; - -void -appendImmediateTask(Context* c, Promise* promise, Promise* offset, - unsigned size, unsigned promiseOffset, bool address) -{ - c->tasks = new (c->zone->allocate(sizeof(ImmediateTask))) ImmediateTask - (c->tasks, promise, offset, size, promiseOffset, address); -} - class ConstantPoolEntry: public Promise { public: - ConstantPoolEntry(Context* c, Promise* constant): - c(c), constant(constant), next(c->constantPool), address(0) - { - c->constantPool = this; - ++ c->constantPoolCount; - } + ConstantPoolEntry(Context* c, Promise* constant, ConstantPoolEntry* next): + c(c), constant(constant), next(next), address(0) + { } virtual int64_t value() { assert(c, resolved()); @@ -618,11 +568,158 @@ class ConstantPoolEntry: public Promise { unsigned constantPoolCount; }; -ConstantPoolEntry* +class ConstantPoolListener: public Promise::Listener { + public: + ConstantPoolListener(System* s, uintptr_t* address): + s(s), + address(address) + { } + + virtual bool resolve(int64_t value, void** location) { + *address = value; + if (location) *location = address; + return true; + } + + System* s; + uintptr_t* address; +}; + +class PoolOffset { + public: + PoolOffset(MyBlock* block, ConstantPoolEntry* entry, unsigned offset): + block(block), entry(entry), next(0), offset(offset) + { } + + MyBlock* block; + ConstantPoolEntry* entry; + PoolOffset* next; + unsigned offset; +}; + +class PoolEvent { + public: + PoolEvent(PoolOffset* poolOffsetHead, PoolOffset* poolOffsetTail, + unsigned offset): + poolOffsetHead(poolOffsetHead), poolOffsetTail(poolOffsetTail), next(0), + offset(offset) + { } + + PoolOffset* poolOffsetHead; + PoolOffset* poolOffsetTail; + PoolEvent* next; + unsigned offset; +}; + +void appendConstantPoolEntry(Context* c, Promise* constant) { - return new (c->zone->allocate(sizeof(ConstantPoolEntry))) - ConstantPoolEntry(c, constant); + if (constant->resolved()) { + // make a copy, since the original might be allocated on the + // stack, and we need our copy to live until assembly is complete + constant = new (c->zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(constant->value()); + } + + c->constantPool = new (c->zone->allocate(sizeof(ConstantPoolEntry))) + ConstantPoolEntry(c, constant, c->constantPool); + + ++ c->constantPoolCount; + + PoolOffset* o = new (c->zone->allocate(sizeof(PoolOffset))) PoolOffset + (c->lastBlock, c->constantPool, c->code.length() - c->lastBlock->offset); + + if (DebugPool) { + fprintf(stderr, "add pool offset %p %d to block %p\n", + o, o->offset, c->lastBlock); + } + + if (c->lastBlock->poolOffsetTail) { + c->lastBlock->poolOffsetTail->next = o; + } else { + c->lastBlock->poolOffsetHead = o; + } + c->lastBlock->poolOffsetTail = o; +} + +void +appendPoolEvent(Context* c, MyBlock* b, unsigned offset, PoolOffset* head, + PoolOffset* tail) +{ + PoolEvent* e = new (c->zone->allocate(sizeof(PoolEvent))) PoolEvent + (head, tail, offset); + + if (b->poolEventTail) { + b->poolEventTail->next = e; + } else { + b->poolEventHead = e; + } + b->poolEventTail = e; +} + +unsigned +padding(MyBlock* b, unsigned offset) +{ + unsigned total = 0; + for (PoolEvent* e = b->poolEventHead; e; e = e->next) { + if (e->offset <= offset) { + total += BytesPerWord; + for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { + total += BytesPerWord; + } + } else { + break; + } + } + return total; +} + +void +resolve(MyBlock* b) +{ + Context* c = b->context; + + if (b->poolOffsetHead) { + if (c->poolOffsetTail) { + c->poolOffsetTail->next = b->poolOffsetHead; + } else { + c->poolOffsetHead = b->poolOffsetHead; + } + c->poolOffsetTail = b->poolOffsetTail; + } + + if (c->poolOffsetHead) { + bool append; + if (b->next == 0 or b->next->poolEventHead) { + append = true; + } else { + int32_t v = (b->offset + b->size + b->next->size + BytesPerWord - 8) + - (c->poolOffsetHead->offset + c->poolOffsetHead->block->offset); + + append = (v != (v & PoolOffsetMask)); + + if (DebugPool) { + fprintf(stderr, + "offset %p %d is of distance %d to next block; append? %d\n", + c->poolOffsetHead, c->poolOffsetHead->offset, v, append); + } + } + + if (append) { + appendPoolEvent(c, b, b->size, c->poolOffsetHead, c->poolOffsetTail); + + if (DebugPool) { + for (PoolOffset* o = c->poolOffsetHead; o; o = o->next) { + fprintf(stderr, + "include %p %d in pool event %p at offset %d in block %p\n", + o, o->offset, b->poolEventTail, b->size, b); + } + } + + c->poolOffsetHead = 0; + c->poolOffsetTail = 0; + } + } } void @@ -710,28 +807,14 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, void moveCR2(Context* c, unsigned, Assembler::Constant* src, - unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) + unsigned dstSize, Assembler::Register* dst) { if (dstSize <= 4) { - if (src->value->resolved()) { - int32_t i = getValue(src); - emit(c, movi(dst->low, lo8(i))); - if (!isOfWidth(i, 8)) { - emit(c, orri(dst->low, dst->low, hi8(i), 12)); - if (!isOfWidth(i, 16)) { - emit(c, orri(dst->low, dst->low, lo8(hi16(i)), 8)); - if (!isOfWidth(i, 24)) { - emit(c, orri(dst->low, dst->low, hi8(hi16(i)), 4)); - } - } - } + if (src->value->resolved() and isOfWidth(getValue(src), 8)) { + emit(c, movi(dst->low, lo8(getValue(src)))); } else { - appendImmediateTask - (c, src->value, offset(c), BytesPerWord, promiseOffset, false); - emit(c, movi(dst->low, 0)); - emit(c, orri(dst->low, dst->low, 0, 12)); - emit(c, orri(dst->low, dst->low, 0, 8)); - emit(c, orri(dst->low, dst->low, 0, 4)); + appendConstantPoolEntry(c, src->value); + emit(c, ldri(dst->low, ProgramCounter, 0)); } } else { abort(c); // todo @@ -742,7 +825,7 @@ void moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, unsigned dstSize, Assembler::Register* dst) { - moveCR2(c, srcSize, src, dstSize, dst, 0); + moveCR2(c, srcSize, src, dstSize, dst); } void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { @@ -1115,17 +1198,14 @@ xorR(Context* con, unsigned size, Assembler::Register* a, void moveAR2(Context* c, unsigned srcSize, Assembler::Address* src, - unsigned dstSize, Assembler::Register* dst, unsigned promiseOffset) + unsigned dstSize, Assembler::Register* dst) { assert(c, srcSize == 4 and dstSize == 4); Assembler::Constant constant(src->address); - Assembler::Memory memory(dst->low, 0, -1, 0); - - appendImmediateTask - (c, src->address, offset(c), BytesPerWord, promiseOffset, true); - moveCR(c, srcSize, &constant, dstSize, dst); + + Assembler::Memory memory(dst->low, 0, -1, 0); moveMR(c, dstSize, &memory, dstSize, dst); } @@ -1133,7 +1213,7 @@ void moveAR(Context* c, unsigned srcSize, Assembler::Address* src, unsigned dstSize, Assembler::Register* dst) { - moveAR2(c, srcSize, src, dstSize, dst, 0); + moveAR2(c, srcSize, src, dstSize, dst); } void @@ -1216,7 +1296,7 @@ branch(Context* c, TernaryOperation op) void conditional(Context* c, int32_t branch, Assembler::Constant* target) { - appendOffsetTask(c, target->value, offset(c), true); + appendOffsetTask(c, target->value, offset(c)); emit(c, branch); } @@ -1299,7 +1379,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, if (next) { updateOffset - (c->s, c->code.data + next, true, reinterpret_cast + (c->s, c->code.data + next, reinterpret_cast (c->code.data + c->code.length())); } } @@ -1426,7 +1506,7 @@ callC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - appendOffsetTask(c, target->value, offset(c), false); + appendOffsetTask(c, target->value, offset(c)); emit(c, bl(0)); } @@ -1436,50 +1516,26 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) assert(c, size == BytesPerWord); Assembler::Register tmp(4); - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp); callR(c, BytesPerWord, &tmp); } -void -alignedLongCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - Assembler::Register tmp(c->client->acquireTemporary()); - Assembler::Address address(appendConstantPoolEntry(c, target->value)); - moveAR2(c, BytesPerWord, &address, BytesPerWord, &tmp, 12); - callR(c, BytesPerWord, &tmp); - c->client->releaseTemporary(tmp.low); -} - void longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, 12); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp); jumpR(c, BytesPerWord, &tmp); } -void -alignedLongJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) -{ - assert(c, size == BytesPerWord); - - Assembler::Register tmp(c->client->acquireTemporary()); - Assembler::Address address(appendConstantPoolEntry(c, target->value)); - moveAR2(c, BytesPerWord, &address, BytesPerWord, &tmp, 12); - jumpR(c, BytesPerWord, &tmp); - c->client->releaseTemporary(tmp.low); -} - void jumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) { assert(c, size == BytesPerWord); - appendOffsetTask(c, target->value, offset(c), false); + appendOffsetTask(c, target->value, offset(c)); emit(c, b(0)); } @@ -1515,11 +1571,11 @@ populateTables(ArchitectureContext* c) uo[index(c, LongCall, C)] = CAST1(longCallC); - uo[index(c, AlignedLongCall, C)] = CAST1(alignedLongCallC); + uo[index(c, AlignedLongCall, C)] = CAST1(longCallC); uo[index(c, LongJump, C)] = CAST1(longJumpC); - uo[index(c, AlignedLongJump, C)] = CAST1(alignedLongJumpC); + uo[index(c, AlignedLongJump, C)] = CAST1(longJumpC); uo[index(c, Jump, R)] = CAST1(jumpR); uo[index(c, Jump, C)] = CAST1(jumpC); @@ -1674,19 +1730,14 @@ class MyArchitecture: public Assembler::Architecture { switch (op) { case Call: case Jump: + case LongCall: + case LongJump: case AlignedCall: case AlignedJump: { - updateOffset(c.s, static_cast(returnAddress) - 4, false, + updateOffset(c.s, static_cast(returnAddress) - 4, reinterpret_cast(newTarget)); } break; - case LongCall: - case LongJump: { - updateImmediate(c.s, static_cast(returnAddress) - 12, - reinterpret_cast(newTarget), BytesPerWord, - false); - } break; - case AlignedLongCall: case AlignedLongJump: { uint32_t* p = static_cast(returnAddress) - 4; @@ -1703,7 +1754,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual void setConstant(void* dst, uintptr_t constant) { - updateImmediate(c.s, dst, constant, BytesPerWord, false); + *static_cast(dst) = constant; } virtual unsigned alignFrameSize(unsigned sizeInWords) { @@ -2145,23 +2196,67 @@ class MyAssembler: public Assembler { virtual void writeTo(uint8_t* dst) { c.result = dst; + unsigned dstOffset = 0; for (MyBlock* b = c.firstBlock; b; b = b->next) { - memcpy(dst + b->start, c.code.data + b->offset, b->size); + if (DebugPool) { + fprintf(stderr, "write block %p\n", b); + } + + unsigned blockOffset = 0; + for (PoolEvent* e = b->poolEventHead; e; e = e->next) { + unsigned size = e->offset - blockOffset; + memcpy(dst + dstOffset, c.code.data + b->offset + blockOffset, size); + blockOffset = e->offset; + dstOffset += size; + + unsigned poolSize = 0; + for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { + if (DebugPool) { + fprintf(stderr, "visit pool offset %p %d in block %p\n", + o, o->offset, b); + } + + poolSize += BytesPerWord; + + unsigned entry = dstOffset + poolSize; + + o->entry->address = dst + entry; + + unsigned instruction = o->block->start + + padding(o->block, o->offset) + o->offset; + + int32_t v = (entry - 8) - instruction; + expect(&c, v == (v & PoolOffsetMask)); + + int32_t* p = reinterpret_cast(dst + instruction); + *p = (v & PoolOffsetMask) | ((~PoolOffsetMask) & *p); + } + + write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2)); + + dstOffset += poolSize + BytesPerWord; + } + + unsigned size = b->size - blockOffset; + + memcpy(dst + dstOffset, + c.code.data + b->offset + blockOffset, + size); + + dstOffset += size; } - - unsigned index = c.code.length(); - assert(&c, index % BytesPerWord == 0); - for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { - e->address = dst + index; - index += BytesPerWord; - } - + for (Task* t = c.tasks; t; t = t->next) { t->run(&c); } for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { - *static_cast(e->address) = e->constant->value(); + if (e->constant->resolved()) { + *static_cast(e->address) = e->constant->value(); + } else { + new (e->constant->listen(sizeof(ConstantPoolListener))) + ConstantPoolListener(c.s, static_cast(e->address)); + } // fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); } } @@ -2175,19 +2270,49 @@ class MyAssembler: public Assembler { b->size = c.code.length() - b->offset; if (startNew) { c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(c.code.length()); + MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } return b; } - virtual unsigned length() { - return c.code.length(); + virtual void endEvent() { + MyBlock* b = c.lastBlock; + unsigned thisEventOffset = c.code.length() - b->offset; + if (b->poolOffsetHead) { + int32_t v = (thisEventOffset + BytesPerWord - 8) + - b->poolOffsetHead->offset; + + if (v > 0 and v != (v & PoolOffsetMask)) { + appendPoolEvent + (&c, b, b->lastEventOffset, b->poolOffsetHead, + b->lastPoolOffsetTail); + + if (DebugPool) { + for (PoolOffset* o = b->poolOffsetHead; + o != b->lastPoolOffsetTail->next; o = o->next) + { + fprintf(stderr, + "in endEvent, include %p %d in pool event %p at offset %d " + "in block %p\n", + o, o->offset, b->poolEventTail, b->lastEventOffset, b); + } + } + + b->poolOffsetHead = b->lastPoolOffsetTail->next; + b->lastPoolOffsetTail->next = 0; + if (b->poolOffsetHead == 0) { + b->poolOffsetTail = 0; + } + } + } + b->lastEventOffset = thisEventOffset; + b->lastPoolOffsetTail = b->poolOffsetTail; } - virtual unsigned scratchSize() { - return c.constantPoolCount * BytesPerWord; + virtual unsigned length() { + return c.code.length(); } virtual void dispose() { diff --git a/src/assembler.h b/src/assembler.h index 918c548acb..70002768ca 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -418,9 +418,9 @@ class Assembler { virtual Block* endBlock(bool startNew) = 0; - virtual unsigned length() = 0; + virtual void endEvent() = 0; - virtual unsigned scratchSize() = 0; + virtual unsigned length() = 0; virtual void dispose() = 0; }; diff --git a/src/compile.cpp b/src/compile.cpp index 2b1688e63a..a3b93b1564 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5391,14 +5391,14 @@ codeSingletonSizeInBytes(MyThread*, unsigned codeSizeInBytes) } uint8_t* -finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name) +finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name, + unsigned length) { - uint8_t* start = static_cast - (allocator->allocate(pad(a->length()))); + uint8_t* start = static_cast(allocator->allocate(pad(length))); a->writeTo(start); - logCompile(t, start, a->length(), 0, name, 0); + logCompile(t, start, length, 0, name, 0); return start; } @@ -8289,9 +8289,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - a->endBlock(false)->resolve(0, 0); - - p->thunks.default_.length = a->length(); + p->thunks.default_.length = a->endBlock(false)->resolve(0, 0); } ThunkContext defaultVirtualContext(t, &zone); @@ -8335,9 +8333,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); - a->endBlock(false)->resolve(0, 0); - - p->thunks.defaultVirtual.length = a->length(); + p->thunks.defaultVirtual.length = a->endBlock(false)->resolve(0, 0); } ThunkContext nativeContext(t, &zone); @@ -8356,9 +8352,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->popFrameAndUpdateStackAndReturn(difference(&(t->stack), t)); - a->endBlock(false)->resolve(0, 0); - - p->thunks.native.length = a->length(); + p->thunks.native.length = a->endBlock(false)->resolve(0, 0); } ThunkContext aioobContext(t, &zone); @@ -8375,9 +8369,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(aioobContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->endBlock(false)->resolve(0, 0); - - p->thunks.aioob.length = a->length(); + p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0); } ThunkContext tableContext(t, &zone); @@ -8391,13 +8383,12 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(tableContext.promise)); a->apply(LongJump, BytesPerWord, ConstantOperand, &proc); - a->endBlock(false)->resolve(0, 0); - - p->thunks.table.length = a->length(); + p->thunks.table.length = a->endBlock(false)->resolve(0, 0); } p->thunks.default_.start = finish - (t, allocator, defaultContext.context.assembler, "default"); + (t, allocator, defaultContext.context.assembler, "default", + p->thunks.default_.length); BootImage* image = p->bootImage; uint8_t* imageBase = p->codeAllocator.base; @@ -8412,7 +8403,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.defaultVirtual.start = finish - (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual"); + (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual", + p->thunks.defaultVirtual.length); { void* call; defaultVirtualContext.promise.listener->resolve @@ -8425,7 +8417,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.native.start = finish - (t, allocator, nativeContext.context.assembler, "native"); + (t, allocator, nativeContext.context.assembler, "native", + p->thunks.native.length); { void* call; nativeContext.promise.listener->resolve @@ -8437,7 +8430,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } p->thunks.aioob.start = finish - (t, allocator, aioobContext.context.assembler, "aioob"); + (t, allocator, aioobContext.context.assembler, "aioob", + p->thunks.aioob.length); { void* call; aioobContext.promise.listener->resolve @@ -8573,9 +8567,7 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) Assembler::Constant thunk(&defaultVirtualThunkPromise); a->apply(Jump, BytesPerWord, ConstantOperand, &thunk); - a->endBlock(false)->resolve(0, 0); - - *size = a->length(); + *size = a->endBlock(false)->resolve(0, 0); uint8_t* start = static_cast(codeAllocator(t)->allocate(*size)); diff --git a/src/compiler.cpp b/src/compiler.cpp index dcfd325d42..2650fb7970 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5698,6 +5698,8 @@ compile(Context* c) p->offset = a->offset(); } + a->endEvent(); + LogicalInstruction* nextInstruction = next(c, e->logicalInstruction); if (e->next == 0 or (e->next->logicalInstruction != e->logicalInstruction @@ -5735,7 +5737,7 @@ compile(Context* c) block = next; } - return block->assemblerBlock->resolve(block->start, 0) + a->scratchSize(); + return block->assemblerBlock->resolve(block->start, 0); } unsigned diff --git a/src/posix.cpp b/src/posix.cpp index da0397c107..a8e92eb8e4 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -782,6 +782,7 @@ class MySystem: public System { } virtual void abort() { + *static_cast(0) = 0; ::abort(); } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index eb1d5ef33b..ce8a6bbb4b 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2393,12 +2393,12 @@ class MyAssembler: public Assembler { return b; } - virtual unsigned length() { - return c.code.length(); + virtual void endEvent() { + // ignore } - virtual unsigned scratchSize() { - return c.constantPoolCount * BytesPerWord; + virtual unsigned length() { + return c.code.length(); } virtual void dispose() { diff --git a/src/x86.cpp b/src/x86.cpp index 2d4d3e55f7..3ff4f716bb 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3532,12 +3532,12 @@ class MyAssembler: public Assembler { return b; } - virtual unsigned length() { - return c.code.length(); + virtual void endEvent() { + // ignore } - virtual unsigned scratchSize() { - return 0; + virtual unsigned length() { + return c.code.length(); } virtual void dispose() { From 8e23893af090632467a08c593cc9a35d85144496 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 14 Nov 2010 18:45:37 -0700 Subject: [PATCH 106/274] fix PowerPC builds on OS X 10.5+ The primary change is to ensure we output a Mach-O file of appropriate endianness when cross-compiling for an opposite-endian architecture. Earlier versions of XCode's linker accepted files of either endianness, reguardless of architecture, but later versions don't, hence the change. --- makefile | 22 +++-- src/binaryToObject/mach-o.cpp | 146 ++++++++++++++++++++-------------- src/powerpc.h | 2 +- 3 files changed, 104 insertions(+), 66 deletions(-) diff --git a/makefile b/makefile index f0dcab31a5..7c14992ac4 100644 --- a/makefile +++ b/makefile @@ -151,7 +151,8 @@ endif ifeq ($(platform),darwin) build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) - lflags = $(common-lflags) -ldl -framework CoreFoundation -framework CoreServices + lflags = $(common-lflags) -ldl -framework CoreFoundation \ + -framework CoreServices ifeq ($(bootimage),true) bootimage-lflags = -Wl,-segprot,__RWX,rwx,rwx endif @@ -161,18 +162,27 @@ ifeq ($(platform),darwin) shared = -dynamiclib ifeq ($(arch),powerpc) + ifneq (,$(filter i386 x86_64,$(build-arch))) + converter-cflags = -DOPPOSITE_ENDIAN + endif cflags += -arch ppc asmflags += -arch ppc lflags += -arch ppc endif ifeq ($(arch),i386) + ifeq ($(build-arch),powerpc) + converter-cflags = -DOPPOSITE_ENDIAN + endif cflags += -arch i386 asmflags += -arch i386 lflags += -arch i386 endif ifeq ($(arch),x86_64) + ifeq ($(build-arch),powerpc) + converter-cflags = -DOPPOSITE_ENDIAN + endif cflags += -arch x86_64 asmflags += -arch x86_64 lflags += -arch x86_64 @@ -640,19 +650,19 @@ $(native-build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build-cxx) -c $(^) -o $(@) $(native-build)/binaryToObject-elf64.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) $(native-build)/binaryToObject-elf32.o: $(src)/binaryToObject/elf.cpp - $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) $(native-build)/binaryToObject-mach-o64.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) -DBITS_PER_WORD=64 -c $(^) -o $(@) + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=64 -c $(^) -o $(@) $(native-build)/binaryToObject-mach-o32.o: $(src)/binaryToObject/mach-o.cpp - $(build-cxx) -DBITS_PER_WORD=32 -c $(^) -o $(@) + $(build-cxx) $(converter-cflags) -DBITS_PER_WORD=32 -c $(^) -o $(@) $(native-build)/binaryToObject-pe.o: $(src)/binaryToObject/pe.cpp - $(build-cxx) -c $(^) -o $(@) + $(build-cxx) $(converter-cflags) -c $(^) -o $(@) $(converter): $(converter-objects) $(build-cxx) $(^) -o $(@) diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index d153694b5c..527130a8db 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -12,6 +12,32 @@ #include "stdio.h" #include "string.h" +#define V1(v) v + +#ifdef OPPOSITE_ENDIAN +# define V2(v) \ + ((((v) >> 8) & 0xFF) | \ + (((v) << 8))) +# define V4(v) \ + ((((v) >> 24) & 0x000000FF) | \ + (((v) >> 8) & 0x0000FF00) | \ + (((v) << 8) & 0x00FF0000) | \ + (((v) << 24))) +# define V8(v) \ + (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ + ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ + ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ + ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ + ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ + ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ + ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ + ((static_cast(v) << 56))) +#else +# define V2(v) v +# define V4(v) v +# define V8(v) v +#endif + #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface @@ -37,6 +63,7 @@ #define CPU_SUBTYPE_POWERPC_ALL 0 #if (BITS_PER_WORD == 64) +# define VW(v) V8(v) # define Magic MH_MAGIC_64 # define Segment LC_SEGMENT_64 # define FileHeader mach_header_64 @@ -44,6 +71,7 @@ # define Section section_64 # define NList struct nlist_64 #elif (BITS_PER_WORD == 32) +# define VW(v) V4(v) # define Magic MH_MAGIC # define Segment LC_SEGMENT # define FileHeader mach_header @@ -191,32 +219,32 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, unsigned endNameLength = strlen(endName) + 1; FileHeader header = { - Magic, // magic - cpuType, - cpuSubType, - MH_OBJECT, // filetype, - 2, // ncmds - sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // sizeofcmds - 0 // flags + V4(Magic), // magic + V4(cpuType), + V4(cpuSubType), + V4(MH_OBJECT), // filetype, + V4(2), // ncmds + V4(sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // sizeofcmds + V4(0) // flags }; SegmentCommand segment = { - Segment, // cmd - sizeof(SegmentCommand) + sizeof(Section), // cmdsize + V4(Segment), // cmd + V4(sizeof(SegmentCommand) + sizeof(Section)), // cmdsize "", // segname - 0, // vmaddr - pad(size), // vmsize - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // fileoff - pad(size), // filesize - 7, // maxprot - 7, // initprot - 1, // nsects - 0 // flags + VW(0), // vmaddr + VW(pad(size)), // vmsize + VW(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // fileoff + VW(pad(size)), // filesize + V4(7), // maxprot + V4(7), // initprot + V4(1), // nsects + V4(0) // flags }; strncpy(segment.segname, segmentName, sizeof(segment.segname)); @@ -224,55 +252,55 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, Section sect = { "", // sectname "", // segname - 0, // addr - pad(size), // size - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command), // offset - log(alignment), // align - 0, // reloff - 0, // nreloc - S_REGULAR, // flags - 0, // reserved1 - 0, // reserved2 + VW(0), // addr + VW(pad(size)), // size + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command)), // offset + V4(log(alignment)), // align + V4(0), // reloff + V4(0), // nreloc + V4(S_REGULAR), // flags + V4(0), // reserved1 + V4(0), // reserved2 }; strncpy(sect.segname, segmentName, sizeof(sect.segname)); strncpy(sect.sectname, sectionName, sizeof(sect.sectname)); symtab_command symbolTable = { - LC_SYMTAB, // cmd - sizeof(symtab_command), // cmdsize - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size), // symoff - 2, // nsyms - sizeof(FileHeader) - + sizeof(SegmentCommand) - + sizeof(Section) - + sizeof(symtab_command) - + pad(size) - + (sizeof(NList) * 2), // stroff - 1 + startNameLength + endNameLength, // strsize + V4(LC_SYMTAB), // cmd + V4(sizeof(symtab_command)), // cmdsize + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command) + + pad(size)), // symoff + V4(2), // nsyms + V4(sizeof(FileHeader) + + sizeof(SegmentCommand) + + sizeof(Section) + + sizeof(symtab_command) + + pad(size) + + (sizeof(NList) * 2)), // stroff + V4(1 + startNameLength + endNameLength), // strsize }; NList symbolList[] = { { - 1, // n_un - N_SECT | N_EXT, // n_type - 1, // n_sect - 0, // n_desc - 0 // n_value + V4(1), // n_un + V1(N_SECT | N_EXT), // n_type + V1(1), // n_sect + V2(0), // n_desc + VW(0) // n_value }, { - 1 + startNameLength, // n_un - N_SECT | N_EXT, // n_type - 1, // n_sect - 0, // n_desc - size // n_value + V4(1 + startNameLength), // n_un + V1(N_SECT | N_EXT), // n_type + V1(1), // n_sect + V2(0), // n_desc + VW(size) // n_value } }; diff --git a/src/powerpc.h b/src/powerpc.h index 9a55c13266..d252039b89 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -15,7 +15,7 @@ #include "common.h" #ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) # define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r13) From 02bdec6f8c6d2a615cd2dc577f9723819c705533 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 15 Nov 2010 16:27:00 -0700 Subject: [PATCH 107/274] fix Cygwin/MSYS openjdk-src builds --- makefile | 24 ++++++++++++++++-------- readme.txt | 5 +++++ src/openjdk/{ => caseSensitive}/Wincon.h | 0 3 files changed, 21 insertions(+), 8 deletions(-) rename src/openjdk/{ => caseSensitive}/Wincon.h (100%) diff --git a/makefile b/makefile index 0fe5c503da..96361d6136 100644 --- a/makefile +++ b/makefile @@ -169,6 +169,8 @@ so-suffix = .so shared = -shared +openjdk-extra-cflags = -fvisibility=hidden + ifeq ($(arch),i386) pointer-size = 4 endif @@ -230,6 +232,7 @@ ifeq ($(platform),windows) cflags = -I$(inc) $(common-cflags) ifeq (,$(filter mingw32 cygwin,$(build-platform))) + openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive cxx = x86_64-w64-mingw32-g++ -m32 cc = x86_64-w64-mingw32-gcc -m32 dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 @@ -246,10 +249,12 @@ ifeq ($(platform),windows) build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" build-cflags = $(common-cflags) -I$(src) -I$(inc) -mthreads + openjdk-extra-cflags = build-lflags = -L$(lib) $(common-lflags) ifeq ($(build-platform),cygwin) build-lflags += -mno-cygwin build-cflags += -mno-cygwin + openjdk-extra-cflags += -mno-cygwin lflags += -mno-cygwin cflags += -mno-cygwin endif @@ -661,10 +666,10 @@ $(classpath-object): $(build)/classpath.jar $(converter) $(converter) $(<) $(@) _binary_classpath_jar_start \ _binary_classpath_jar_end $(platform) $(arch) -$(build)/javahome.jar: $(foreach x,$(javahome-files),$(build-javahome)/$(x)) +$(build)/javahome.jar: @echo "creating $(@)" (wd=$$(pwd) && \ - cd $(build-javahome) && \ + cd "$(build-javahome)" && \ $(jar) c0f "$$($(native-path) "$${wd}/$(@)")" $(javahome-files)) $(javahome-object): $(build)/javahome.jar $(converter) @@ -777,20 +782,23 @@ $(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) - $(cc) -fPIC -fvisibility=hidden $(openjdk-cflags) $(optimization-cflags) \ - -w -c $(<) $(call output,$(@)) + $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ + $(optimization-cflags) -w -c $(<) $(call output,$(@)) -$(openjdk-headers-dep): $(openjdk)/jre/lib/rt.jar +$(openjdk-headers-dep): @echo "generating openjdk headers" @mkdir -p $(dir $(@)) $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ $(openjdk-headers-classes) @touch $(@) -$(openjdk-jar-dep): $(openjdk)/jre/lib/rt.jar $(openjdk)/jre/lib/jsse.jar \ - $(openjdk)/jre/lib/jce.jar $(openjdk)/jre/lib/resources.jar +$(openjdk-jar-dep): @echo "extracting openjdk classes" @mkdir -p $(dir $(@)) @mkdir -p $(classpath-build) - (cd $(classpath-build) && for x in $(^); do jar xf $${x}; done) + (cd $(classpath-build) && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/rt.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jsse.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/jce.jar")" && \ + $(jar) xf "$$($(native-path) "$(openjdk)/jre/lib/resources.jar")") @touch $(@) diff --git a/readme.txt b/readme.txt index 57b978c1fc..18cdf325dd 100644 --- a/readme.txt +++ b/readme.txt @@ -219,6 +219,11 @@ specifying the location of the OpenJDK source code, e.g.: $ make openjdk=$(pwd)/../jdk6/build/linux-amd64/j2sdk-image \ openjdk-src=$(pwd)/../jdk6/jdk/src +You must ensure that the path specified for openjdk-src does not have +any spaces in it; make gets confused when dependency paths include +spaces, and we haven't found away around that except to avoid paths +with spaces entirely. + The result of such a build is a self-contained binary which does not depend on external libraries, jars, or other files. In this case, the specified paths are used only at build time; anything needed at diff --git a/src/openjdk/Wincon.h b/src/openjdk/caseSensitive/Wincon.h similarity index 100% rename from src/openjdk/Wincon.h rename to src/openjdk/caseSensitive/Wincon.h From 3fb834d00886c6aed10cc8ecf7c1cf565aae497a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 15 Nov 2010 23:56:34 +0000 Subject: [PATCH 108/274] fix pre-GCC-4.4 ARM build --- src/arm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arm.cpp b/src/arm.cpp index 27ba7d4e10..ccb0ece4d6 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -175,7 +175,7 @@ const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; -const unsigned PoolOffsetMask = 0xFFF; +const int32_t PoolOffsetMask = 0xFFF; const bool DebugPool = false; From bc326fb5e97f11005ff604193abff1d9e522b192 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 16 Nov 2010 02:38:36 +0000 Subject: [PATCH 109/274] fix ARM bootimage=true build --- src/arm.cpp | 44 +++++++++++++++++++++++--------------- src/binaryToObject/elf.cpp | 2 +- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index ccb0ece4d6..46e87a3b23 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -547,8 +547,10 @@ void unsignedShiftRightC(Context* con, unsigned size UNUSED, Assembler::Constant class ConstantPoolEntry: public Promise { public: - ConstantPoolEntry(Context* c, Promise* constant, ConstantPoolEntry* next): - c(c), constant(constant), next(next), address(0) + ConstantPoolEntry(Context* c, Promise* constant, ConstantPoolEntry* next, + Promise* callOffset): + c(c), constant(constant), next(next), callOffset(callOffset), + address(0) { } virtual int64_t value() { @@ -564,25 +566,30 @@ class ConstantPoolEntry: public Promise { Context* c; Promise* constant; ConstantPoolEntry* next; + Promise* callOffset; void* address; unsigned constantPoolCount; }; class ConstantPoolListener: public Promise::Listener { public: - ConstantPoolListener(System* s, uintptr_t* address): + ConstantPoolListener(System* s, uintptr_t* address, uint8_t* returnAddress): s(s), - address(address) + address(address), + returnAddress(returnAddress) { } virtual bool resolve(int64_t value, void** location) { *address = value; - if (location) *location = address; + if (location) { + *location = returnAddress ? static_cast(returnAddress) : address; + } return true; } System* s; uintptr_t* address; + uint8_t* returnAddress; }; class PoolOffset { @@ -612,7 +619,7 @@ class PoolEvent { }; void -appendConstantPoolEntry(Context* c, Promise* constant) +appendConstantPoolEntry(Context* c, Promise* constant, Promise* callOffset) { if (constant->resolved()) { // make a copy, since the original might be allocated on the @@ -622,7 +629,7 @@ appendConstantPoolEntry(Context* c, Promise* constant) } c->constantPool = new (c->zone->allocate(sizeof(ConstantPoolEntry))) - ConstantPoolEntry(c, constant, c->constantPool); + ConstantPoolEntry(c, constant, c->constantPool, callOffset); ++ c->constantPoolCount; @@ -807,13 +814,13 @@ moveZRR(Context* c, unsigned srcSize, Assembler::Register* src, void moveCR2(Context* c, unsigned, Assembler::Constant* src, - unsigned dstSize, Assembler::Register* dst) + unsigned dstSize, Assembler::Register* dst, Promise* callOffset) { if (dstSize <= 4) { if (src->value->resolved() and isOfWidth(getValue(src), 8)) { emit(c, movi(dst->low, lo8(getValue(src)))); } else { - appendConstantPoolEntry(c, src->value); + appendConstantPoolEntry(c, src->value, callOffset); emit(c, ldri(dst->low, ProgramCounter, 0)); } } else { @@ -825,7 +832,7 @@ void moveCR(Context* c, unsigned srcSize, Assembler::Constant* src, unsigned dstSize, Assembler::Register* dst) { - moveCR2(c, srcSize, src, dstSize, dst); + moveCR2(c, srcSize, src, dstSize, dst, 0); } void addR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { @@ -1516,7 +1523,7 @@ longCallC(Context* c, unsigned size UNUSED, Assembler::Constant* target) assert(c, size == BytesPerWord); Assembler::Register tmp(4); - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, offset(c)); callR(c, BytesPerWord, &tmp); } @@ -1526,7 +1533,7 @@ longJumpC(Context* c, unsigned size UNUSED, Assembler::Constant* target) assert(c, size == BytesPerWord); Assembler::Register tmp(4); // a non-arg reg that we don't mind clobbering - moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp); + moveCR2(c, BytesPerWord, target, BytesPerWord, &tmp, offset(c)); jumpR(c, BytesPerWord, &tmp); } @@ -1730,18 +1737,18 @@ class MyArchitecture: public Assembler::Architecture { switch (op) { case Call: case Jump: - case LongCall: - case LongJump: case AlignedCall: case AlignedJump: { updateOffset(c.s, static_cast(returnAddress) - 4, reinterpret_cast(newTarget)); } break; + case LongCall: + case LongJump: case AlignedLongCall: case AlignedLongJump: { - uint32_t* p = static_cast(returnAddress) - 4; - *reinterpret_cast(unha16(p[0] & 0xFFFF, p[1] & 0xFFFF)) + uint32_t* p = static_cast(returnAddress) - 2; + *reinterpret_cast(p + (((*p & PoolOffsetMask) + 8) / 4)) = newTarget; } break; @@ -2255,7 +2262,10 @@ class MyAssembler: public Assembler { *static_cast(e->address) = e->constant->value(); } else { new (e->constant->listen(sizeof(ConstantPoolListener))) - ConstantPoolListener(c.s, static_cast(e->address)); + ConstantPoolListener(c.s, static_cast(e->address), + e->callOffset + ? dst + e->callOffset->value() + 8 + : 0); } // fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); } diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 8a6c2417d1..2e58f08e27 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -232,7 +232,7 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, fileHeader.e_entry = 0; fileHeader.e_phoff = 0; fileHeader.e_shoff = sizeof(FileHeader); - fileHeader.e_flags = 0; + fileHeader.e_flags = (machine == EM_ARM ? 0x04000000 : 0); fileHeader.e_ehsize = sizeof(FileHeader); fileHeader.e_phentsize = 0; fileHeader.e_phnum = 0; From 86188cfc04147b7b9b6daff6288f2565e48e1c12 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 15 Nov 2010 20:28:53 -0700 Subject: [PATCH 110/274] fix OS X openjdk and openjdk-src builds --- makefile | 28 ++++++++++++++++++++-------- openjdk-src.mk | 6 ++++++ src/classpath-openjdk.cpp | 10 ++-------- src/common.h | 2 +- src/posix.cpp | 2 +- src/windows.cpp | 2 +- test/test.sh | 5 ++--- 7 files changed, 33 insertions(+), 22 deletions(-) diff --git a/makefile b/makefile index 96361d6136..ba76e7afd4 100644 --- a/makefile +++ b/makefile @@ -66,7 +66,18 @@ ifneq (,$(filter mingw32 cygwin,$(build-platform))) path-separator = ; endif +library-path-variable = LD_LIBRARY_PATH + +ifeq ($(build-platform),darwin) + library-path-variable = DYLD_LIBRARY_PATH +endif + ifdef openjdk + openjdk-arch = $(arch) + ifeq ($(arch),x86_64) + openjdk-arch = amd64 + endif + ifdef openjdk-src include openjdk-src.mk options := $(options)-openjdk-src @@ -83,7 +94,8 @@ ifdef openjdk else options := $(options)-openjdk test-executable = $(executable-dynamic) - library-path = LD_LIBRARY_PATH=$(build) + library-path = \ + $(library-path-variable)=$(build):$(openjdk)/jre/lib/$(openjdk-arch) javahome = "$$($(native-path) "$(openjdk)/jre")" endif @@ -155,8 +167,6 @@ lflags = $(common-lflags) -lpthread -ldl version-script-flag = -Wl,--version-script=openjdk.ld -jvm-flags = -L$(build) -ljvm - build-system = posix system = posix @@ -185,7 +195,6 @@ endif ifeq ($(platform),darwin) version-script-flag = - jvm-flags = $(build)/libjvm.jnilib build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) build-lflags += -framework CoreFoundation lflags = $(common-lflags) -ldl -framework CoreFoundation -framework CoreServices @@ -194,22 +203,25 @@ ifeq ($(platform),darwin) endif rdynamic = strip-all = -S -x - so-suffix = .jnilib + so-suffix = .dylib shared = -dynamiclib ifeq ($(arch),powerpc) + openjdk-extra-cflags += -arch ppc cflags += -arch ppc asmflags += -arch ppc lflags += -arch ppc endif ifeq ($(arch),i386) + openjdk-extra-cflags += -arch i386 cflags += -arch i386 asmflags += -arch i386 lflags += -arch i386 endif ifeq ($(arch),x86_64) + openjdk-extra-cflags += -arch x86_64 cflags += -arch x86_64 asmflags += -arch x86_64 lflags += -arch x86_64 @@ -532,8 +544,8 @@ vg: build .PHONY: test test: build - /bin/sh $(test)/test.sh 2>/dev/null \ - $(build) $(test-executable) $(mode) "$(test-flags)" \ + $(library-path) /bin/sh $(test)/test.sh 2>/dev/null \ + $(test-executable) $(mode) "$(test-flags)" \ $(call class-names,$(test-build),$(test-classes)) .PHONY: tarball @@ -770,7 +782,7 @@ ifdef msvc -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(<) $(jvm-flags) $(lflags) -o $(@) + $(ld) $(<) -L$(build) -ljvm $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk index 1c2e62d0cd..84b6c91786 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -127,6 +127,12 @@ openjdk-cflags = \ -DJDK_BUILD_NUMBER=\"0\" \ -D_GNU_SOURCE +ifeq ($(platform),darwin) + openjdk-cflags += \ + -D_LFS_LARGEFILE=1 \ + -D_ALLBSD_SOURCE +endif + ifeq ($(platform),windows) openjdk-sources += \ $(openjdk-src)/windows/native/java/io/canonicalize_md.c \ diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 13cab76928..8d6c5994a5 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -52,9 +52,6 @@ # define EXPORT(x) _##x # endif -# define LIBRARY_PREFIX "" -# define LIBRARY_SUFFIX ".dll" - typedef int socklen_t; #else // not PLATFORM_WINDOWS @@ -78,9 +75,6 @@ typedef int socklen_t; # define EXPORT(x) x -# define LIBRARY_PREFIX "lib" -# define LIBRARY_SUFFIX ".so" - #endif // not PLATFORM_WINDOWS using namespace vm; @@ -245,9 +239,9 @@ class MyClasspath : public Classpath { this->zipLibrary = sb.pointer; sb.append(this->libraryPath); sb.append("/"); - sb.append(LIBRARY_PREFIX); + sb.append(SO_PREFIX); sb.append("zip"); - sb.append(LIBRARY_SUFFIX); + sb.append(SO_SUFFIX); sb.append('\0'); this->tzMappings = sb.pointer; diff --git a/src/common.h b/src/common.h index 6ab13f23ec..7cf95a85e3 100644 --- a/src/common.h +++ b/src/common.h @@ -132,7 +132,7 @@ typedef uint64_t uintptr_t; #endif #ifdef __APPLE__ -# define SO_SUFFIX ".jnilib" +# define SO_SUFFIX ".dylib" #elif defined PLATFORM_WINDOWS # define SO_SUFFIX ".dll" #else diff --git a/src/posix.cpp b/src/posix.cpp index cf7d600bb5..e72587eea6 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -719,7 +719,7 @@ class MySystem: public System { } virtual const char* libraryPrefix() { - return "lib"; + return SO_PREFIX; } virtual const char* librarySuffix() { diff --git a/src/windows.cpp b/src/windows.cpp index 405d626d82..8b93f96e5c 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -716,7 +716,7 @@ class MySystem: public System { } virtual const char* libraryPrefix() { - return ""; + return SO_PREFIX; } virtual const char* librarySuffix() { diff --git a/test/test.sh b/test/test.sh index 786c9e24c0..72d7734832 100644 --- a/test/test.sh +++ b/test/test.sh @@ -4,7 +4,6 @@ log=build/log.txt vg="nice valgrind --leak-check=full --num-callers=32 \ --freelist-vol=100000000 --error-exitcode=1" -library_path=${1}; shift vm=${1}; shift mode=${1}; shift flags=${1}; shift @@ -19,10 +18,10 @@ for test in ${tests}; do case ${mode} in debug|debug-fast|fast|small ) - LD_LIBRARY_PATH=${library_path} ${vm} ${flags} ${test} >>${log} 2>&1;; + ${vm} ${flags} ${test} >>${log} 2>&1;; stress* ) - LD_LIBRARY_PATH=${library_path} ${vg} ${vm} ${flags} ${test} \ + ${vg} ${vm} ${flags} ${test} \ >>${log} 2>&1;; * ) From 64601e6f3e77c2cb8bdaeb9d6da535001eaef32f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 16 Nov 2010 09:31:49 -0700 Subject: [PATCH 111/274] name VM-internal classes for heapdump=true builds This makes heap dumps more useful since these classes are now refered to by name instead of number. This commit also adds a couple of utilities for parsing heap dumps: PrintDump and DumpStats. --- makefile | 3 +- src/machine.cpp | 11 +++ src/type-generator.cpp | 28 +++++++- test/extra/DumpStats.java | 147 ++++++++++++++++++++++++++++++++++++++ test/extra/PrintDump.java | 101 ++++++++++++++++++++++++++ 5 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 test/extra/DumpStats.java create mode 100644 test/extra/PrintDump.java diff --git a/makefile b/makefile index 7c14992ac4..69beda3adb 100644 --- a/makefile +++ b/makefile @@ -315,7 +315,8 @@ generated-code = \ $(native-build)/type-declarations.cpp \ $(native-build)/type-constructors.cpp \ $(native-build)/type-initializations.cpp \ - $(native-build)/type-java-initializations.cpp + $(native-build)/type-java-initializations.cpp \ + $(native-build)/type-name-initializations.cpp vm-depends = \ $(generated-code) \ diff --git a/src/machine.cpp b/src/machine.cpp index fedbf9c35f..d0b82f87fb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1888,6 +1888,13 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash); } +void +nameClass(Thread* t, Machine::Type type, const char* name) +{ + object n = makeByteArray(t, name); + set(t, arrayBody(t, t->m->types, type), ClassName, n); +} + void boot(Thread* t) { @@ -1990,6 +1997,10 @@ boot(Thread* t) PROTECT(t, bootMethod); #include "type-java-initializations.cpp" + +#ifdef AVIAN_HEAPDUMP +# include "type-name-initializations.cpp" +#endif } } diff --git a/src/type-generator.cpp b/src/type-generator.cpp index fc0fb72061..82f1748358 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -2184,6 +2184,27 @@ writeJavaInitializations(Output* out, Object* declarations) } } +void +writeNameInitialization(Output* out, Object* type) +{ + out->write("nameClass(t, Machine::"); + out->write(capitalize(typeName(type))); + out->write("Type, \"vm::"); + out->write(typeName(type)); + out->write("\");\n"); +} + +void +writeNameInitializations(Output* out, Object* declarations) +{ + for (Object* p = declarations; p; p = cdr(p)) { + Object* o = car(p); + if (o->type == Object::Type and typeJavaName(o) == 0) { + writeNameInitialization(out, o); + } + } +} + void usageAndExit(const char* command) { @@ -2206,7 +2227,8 @@ main(int ac, char** av) and not equal(av[2], "declarations") and not equal(av[2], "constructors") and not equal(av[2], "initializations") - and not equal(av[2], "java-initializations"))) + and not equal(av[2], "java-initializations") + and not equal(av[2], "name-initializations"))) { usageAndExit(av[0]); } @@ -2246,5 +2268,9 @@ main(int ac, char** av) writeJavaInitializations(&out, declarations); } + if (ac == 2 or equal(av[2], "name-initializations")) { + writeNameInitializations(&out, declarations); + } + return 0; } diff --git a/test/extra/DumpStats.java b/test/extra/DumpStats.java new file mode 100644 index 0000000000..c9e7774484 --- /dev/null +++ b/test/extra/DumpStats.java @@ -0,0 +1,147 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; +import java.util.Arrays; + +/** + * This is a simple utility to generate and print statistics from a + * heap dump generated by Avian's heapdump.cpp. The output is a list + * of classes (identified by number in the case of anonymous, + * VM-internal classes), each followed by (1) the total memory + * footprint of all instances of the class, and (2) the number of + * instances. The output is ordered by instance memory footprint. + */ +public class DumpStats { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static int readInt(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) throw new EOFException(); + return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static Record record(Map map, int key) { + Record r = map.get(key); + if (r == null) { + map.put(key, r = new Record(key)); + } + return r; + } + + private static Map read(InputStream in) + throws IOException + { + boolean done = false; + boolean popped = false; + int size = 0; + int last = 0; + Map map = new HashMap(); + + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + last = readInt(in); + popped = false; + } break; + + case ClassName: { + record(map, last).name = readString(in); + } break; + + case Push: { + last = readInt(in); + if (! popped) { + Record r = record(map, last); + r.footprint += size; + ++ r.count; + } + popped = false; + } break; + + case Pop: { + popped = true; + } break; + + case Size: { + size = readInt(in); + } break; + + case -1: + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + + return map; + } + + public static void main(String[] args) throws Exception { + Map map = read + (new BufferedInputStream(new FileInputStream(args[0]))); + + Record[] array = map.values().toArray(new Record[map.size()]); + Arrays.sort(array, new Comparator() { + public int compare(Record a, Record b) { + return b.footprint - a.footprint; + } + }); + + int footprint = 0; + int count = 0; + for (Record r: array) { + if (r.name == null) { + r.name = String.valueOf(r.key); + } + System.out.println(r.name + ": " + r.footprint + " " + r.count); + footprint += r.footprint; + count += r.count; + } + + System.out.println(); + System.out.println("total: " + footprint + " " + count); + } + + private static class Record { + public final int key; + public String name; + public int footprint; + public int count; + + public Record(int key) { + this.key = key; + } + } +} diff --git a/test/extra/PrintDump.java b/test/extra/PrintDump.java new file mode 100644 index 0000000000..8f43f419c9 --- /dev/null +++ b/test/extra/PrintDump.java @@ -0,0 +1,101 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; + +/** + * This is a simple utility to print the contents of a heap dump + * generated by Avian's heapdump.cpp in a human-readable format. + */ +public class PrintDump { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static void indent(PrintStream out, int level) { + for (; level > 0; --level) out.print(" "); + } + + private static int readInt(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) throw new EOFException(); + return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static void pipe(InputStream in, PrintStream out) + throws IOException + { + boolean done = false; + boolean popped = false; + int level = 0; + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + out.print("\nroot " + readInt(in)); + popped = false; + } break; + + case ClassName: { + out.print(" class " + readString(in)); + } break; + + case Push: { + ++ level; + out.println(); + indent(out, level); + if (! popped) { + out.print("first "); + } + out.print("child " + readInt(in)); + popped = false; + } break; + + case Pop: { + -- level; + popped = true; + } break; + + case Size: { + out.print(" size " + readInt(in)); + } break; + + case -1: + out.println(); + out.flush(); + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + } + + public static void main(String[] args) throws Exception { + pipe(new BufferedInputStream(new FileInputStream(args[0])), System.out); + } +} From 3ff1f9c59f572e21b8480bc3274d5804c4c2136c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 16 Nov 2010 10:49:56 -0700 Subject: [PATCH 112/274] remove temporary debugging code from posix.cpp --- src/posix.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index 66582fb5b4..e72587eea6 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -784,7 +784,6 @@ class MySystem: public System { } virtual void abort() { - *static_cast(0) = 0; ::abort(); } From aea02e545f5dea8fdfacf3a61110291229a75ead Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 16 Nov 2010 10:50:19 -0700 Subject: [PATCH 113/274] fix race condition in interrupting/joining threads as they are exiting My recent commit to ensure that OS resources are released immediately upon thread exit introduced a race condition where interrupting or joining a thread as it exited could lead to attempts to use already-released resources. This commit adds locking to avoid the race. --- src/machine.cpp | 15 +++++++++++---- src/machine.h | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index a3d9402941..0191e1d285 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -45,10 +45,9 @@ void join(Thread* t, Thread* o) { if (t != o) { - if (o->state != Thread::ZombieState - and o->state != Thread::JoinedState) - { + if (acquireSystem(t, o)) { o->systemThread->join(); + releaseSystem(t, o); } o->state = Thread::JoinedState; } @@ -2407,7 +2406,15 @@ Thread::exit() turnOffTheLights(this); } else { threadPeer(this, javaThread) = 0; - enter(this, Thread::ZombieState); + + { ACQUIRE_RAW(this, m->stateLock); + + while (flags & SystemFlag) { + m->stateLock->wait(systemThread, 0); + } + + enter(this, Thread::ZombieState); + } lock->dispose(); lock = 0; diff --git a/src/machine.h b/src/machine.h index 21849fc04d..77c821e522 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1298,6 +1298,7 @@ class Thread { static const unsigned DaemonFlag = 1 << 3; static const unsigned StressFlag = 1 << 4; static const unsigned ActiveFlag = 1 << 5; + static const unsigned SystemFlag = 1 << 6; class Protector { public: @@ -2758,13 +2759,42 @@ notifyAll(Thread* t, object o) } } -inline void -interrupt(Thread*, Thread* target) +inline bool +zombified(Thread* t) { - if (target->state != Thread::ZombieState - and target->state != Thread::JoinedState) - { + return t->state == Thread::ZombieState + or t->state == Thread::JoinedState; +} + +inline bool +acquireSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + if (not zombified(target)) { + atomicOr(&(target->flags), Thread::SystemFlag); + return true; + } else { + return false; + } +} + +inline void +releaseSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, not zombified(target)); + + atomicAnd(&(target->flags), ~Thread::SystemFlag); +} + +inline void +interrupt(Thread* t, Thread* target) +{ + if (acquireSystem(t, target)) { target->systemThread->interrupt(); + releaseSystem(t, target); } } From aac85ff2786190163b3809866f15843824b9e39f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 7 Nov 2010 12:57:42 -0700 Subject: [PATCH 114/274] remove @Overload annotation since Java 1.5.0_19 chokes on it --- classpath/java/util/Collections.java | 1 - 1 file changed, 1 deletion(-) diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index e790c4ed70..eb7c5d462c 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -393,7 +393,6 @@ public class Collections { this.cmp = cmp; } - @Override public int compare(T o1, T o2) { return - cmp.compare(o1, o2); } From 86ed206f5a3a83f297ceecd07eab08c6251b71d0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Nov 2010 10:19:48 -0700 Subject: [PATCH 115/274] remove temporary debug code from posix.cpp --- src/posix.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index a8e92eb8e4..da0397c107 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -782,7 +782,6 @@ class MySystem: public System { } virtual void abort() { - *static_cast(0) = 0; ::abort(); } From 7b85afedecdd0801d6a4414c6ef6a24467b2668c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Nov 2010 10:24:58 -0700 Subject: [PATCH 116/274] ensure that sa_sigaction is non-null before attempting to call it --- src/posix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/posix.cpp b/src/posix.cpp index da0397c107..e5ec88b0a1 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -874,7 +874,9 @@ handleSignal(int signal, siginfo_t* info, void* context) default: abort(); } - if (system->oldHandlers[index].sa_flags & SA_SIGINFO) { + if (system->oldHandlers[index].sa_flags & SA_SIGINFO + and system->oldHandlers[index].sa_sigaction) + { system->oldHandlers[index].sa_sigaction(signal, info, context); } else if (system->oldHandlers[index].sa_handler) { system->oldHandlers[index].sa_handler(signal); From 19dbc61e9f8324fe159acd1621bc5c84eea8e39d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 18 Nov 2010 10:55:00 -0700 Subject: [PATCH 117/274] for heapdump=true builds, optionally generate dump on OOM If the VM runs out of heap space and the "avian.heap.dump" system property was specified at startup, the VM will write a heap dump to the filename indicated by that property. This dump may be analyzed using e.g. DumpStats.java. --- src/heap.cpp | 24 +++++++++++++++++++----- src/heap.h | 1 + src/machine.cpp | 15 +++++++++++++++ test/extra/DumpStats.java | 5 +++-- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index 718d2885a0..02211204b2 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -69,6 +69,7 @@ void assert(Context*, bool); System* system(Context*); void* tryAllocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); +void outOfMemory(Context*); #ifdef USE_ATOMIC_OPERATIONS inline void @@ -359,7 +360,7 @@ class Segment { break; } } else { - abort(context); + outOfMemory(context); } } } @@ -1708,7 +1709,8 @@ collect(Context* c) } } -void* tryAllocate(Context* c, unsigned size) +void* +tryAllocate(Context* c, unsigned size) { ACQUIRE(c->lock); @@ -1733,7 +1735,9 @@ void* tryAllocate(Context* c, unsigned size) return 0; } -void free(Context* c, const void* p, unsigned size) { +void +free(Context* c, const void* p, unsigned size) +{ ACQUIRE(c->lock); if (DebugAllocation) { @@ -1755,10 +1759,18 @@ void free(Context* c, const void* p, unsigned size) { c->count -= size; } -void free_(Context* c, const void* p, unsigned size) { +void +free_(Context* c, const void* p, unsigned size) +{ free(c, p, size); } +void +outOfMemory(Context* c) +{ + c->client->outOfMemory(); +} + class MyHeap: public Heap { public: MyHeap(System* system, unsigned limit): @@ -1781,7 +1793,9 @@ class MyHeap: public Heap { virtual void* allocate(unsigned size) { void* p = local::tryAllocate(&c, size); - expect(c.system, p); + if (p == 0) { + c.client->outOfMemory(); + } return p; } diff --git a/src/heap.h b/src/heap.h index 769bc1ec4b..6b392a1de6 100644 --- a/src/heap.h +++ b/src/heap.h @@ -49,6 +49,7 @@ class Heap: public Allocator { virtual unsigned copiedSizeInWords(void*) = 0; virtual void copy(void*, void*) = 0; virtual void walk(void*, Walker*) = 0; + virtual void outOfMemory() = 0; }; virtual void setClient(Client* client) = 0; diff --git a/src/machine.cpp b/src/machine.cpp index d0b82f87fb..4684fca888 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2081,6 +2081,21 @@ class HeapClient: public Heap::Client { ::walk(m->rootThread, w, o, 0); } + virtual void outOfMemory() { +#ifdef AVIAN_HEAPDUMP + const char* path = findProperty(m->rootThread, "avian.heap.dump"); + if (path) { + FILE* out = vm::fopen(path, "wb"); + if (out) { + dumpHeap(m->rootThread, out); + fclose(out); + } + } +#endif//AVIAN_HEAPDUMP + + abort(m->system); + } + void dispose() { m->heap->free(this, sizeof(*this)); } diff --git a/test/extra/DumpStats.java b/test/extra/DumpStats.java index c9e7774484..470d22656a 100644 --- a/test/extra/DumpStats.java +++ b/test/extra/DumpStats.java @@ -16,8 +16,9 @@ import java.util.Arrays; * heap dump generated by Avian's heapdump.cpp. The output is a list * of classes (identified by number in the case of anonymous, * VM-internal classes), each followed by (1) the total memory - * footprint of all instances of the class, and (2) the number of - * instances. The output is ordered by instance memory footprint. + * footprint of all instances of the class in machine words, and (2) + * the number of instances. The output is ordered by instance memory + * footprint. */ public class DumpStats { private static final int Root = 0; From f9197cb07692b067030999d670b37fd4188b071c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 21 Nov 2010 17:26:17 -0700 Subject: [PATCH 118/274] fix a few HashMap bugs 1. HashMap.containsValue only checked one hash bucket, which was pretty much useless :) 2. HashMap.MyIterator.remove was broken in that it failed to decrement the size field and it did not update the previousCell field properly, which sometimes led to more than one cell being removed. --- classpath/java/util/HashMap.java | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index 0f00f920b2..e767b166d8 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -149,16 +149,17 @@ public class HashMap implements Map { } public boolean containsValue(Object value) { - if (array != null) { - int index = array.length - 1; - for (Cell c = array[index]; c != null; c = c.next()) { - if (helper.equal(value, c.getValue())) { - return true; + if (array != null) { + for (int i = 0; i < array.length; ++i) { + for (Cell c = array[i]; c != null; c = c.next()) { + if (helper.equal(value, c.getValue())) { + return true; + } } } } - return false; + return false; } public V get(Object key) { @@ -450,10 +451,12 @@ public class HashMap implements Map { public Entry next() { if (hasNext()) { - if (currentCell != null && currentCell.next() != null) { - previousCell = currentCell; - } else { - previousCell = null; + if (currentCell != null) { + if (currentCell.next() != null) { + previousCell = currentCell; + } else { + previousCell = null; + } } currentCell = nextCell; @@ -490,6 +493,7 @@ public class HashMap implements Map { } } currentCell = null; + -- size; } else { throw new IllegalStateException(); } From 878e98954b360efaea231da88ce4f07aa30ca0dd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 22 Nov 2010 10:04:28 -0700 Subject: [PATCH 119/274] add QueryDump heap dump analysis tool --- test/extra/DumpStats.java | 15 +- test/extra/QueryDump.java | 358 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 test/extra/QueryDump.java diff --git a/test/extra/DumpStats.java b/test/extra/DumpStats.java index 470d22656a..73b9170bed 100644 --- a/test/extra/DumpStats.java +++ b/test/extra/DumpStats.java @@ -108,8 +108,16 @@ public class DumpStats { return map; } + + private static void usageAndExit() { + System.err.println("usage: java DumpStats "); + } public static void main(String[] args) throws Exception { + if (args.length != 2) { + usageAndExit(); + } + Map map = read (new BufferedInputStream(new FileInputStream(args[0]))); @@ -120,19 +128,22 @@ public class DumpStats { } }); + int wordSize = Integer.parseInt(args[1]); + int footprint = 0; int count = 0; for (Record r: array) { if (r.name == null) { r.name = String.valueOf(r.key); } - System.out.println(r.name + ": " + r.footprint + " " + r.count); + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); footprint += r.footprint; count += r.count; } System.out.println(); - System.out.println("total: " + footprint + " " + count); + System.out.println("total: " + (footprint * wordSize) + " " + count); } private static class Record { diff --git a/test/extra/QueryDump.java b/test/extra/QueryDump.java new file mode 100644 index 0000000000..156cd64d36 --- /dev/null +++ b/test/extra/QueryDump.java @@ -0,0 +1,358 @@ +package extra; + +import java.io.PrintStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.EOFException; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Comparator; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +public class QueryDump { + private static final int Root = 0; + private static final int Size = 1; + private static final int ClassName = 2; + private static final int Push = 3; + private static final int Pop = 4; + + private static int readInt(InputStream in) throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + if (b4 == -1) throw new EOFException(); + return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4)); + } + + private static String readString(InputStream in) throws IOException { + int count = readInt(in); + byte[] b = new byte[count]; + int offset = 0; + int c; + while ((c = in.read(b, offset, b.length - offset)) != -1 + && offset < b.length) + { + offset += c; + } + if (offset != b.length) throw new EOFException(); + return new String(b); + } + + private static Record record(Map map, int key) { + Record r = map.get(key); + if (r == null) { + map.put(key, r = new Record(key)); + } + return r; + } + + private static void push(List stack, T value) { + stack.add(value); + } + + private static T pop(List stack) { + return stack.remove(stack.size() - 1); + } + + private static T peek(List stack, int offset) { + return stack.get(stack.size() - 1 - offset); + } + + private static T peek(List stack) { + return peek(stack, 0); + } + + private static Set nodes(Record record) { + if (record.nodes == null) { + record.nodes = new HashSet(2); + } + return record.nodes; + } + + private static void query(Map nodes, Record[] query, + List stack, int index) + { + Node node = nodes.get(peek(stack, index).key); + if (node != null) { + int base = node.index(); + for (int i = base + 1; i < query.length; ++i) { + int peek = index + i - base; + if (peek < stack.size()) { + Instance instance = peek(stack, peek); + if (query[i] == instance.record) { + TreeNode next = (TreeNode) nodes.get(instance); + if (next == null) { + nodes.put(instance.key, next = new TreeNode(instance, i)); + } + next.children.add(node); + node = next; + } else { + return; + } + } else { + return; + } + } + + if (index + query.length - base < stack.size()) { + nodes(peek(stack, index + query.length - base).record).add(node); + } + } + } + + private static void query(Map nodes, Record[] query, + List stack) + { + if (stack.size() > 1) { + Instance instance = peek(stack, 1); + if (instance != null && instance.record == query[0]) { + Node node = nodes.get(instance.key); + if (node == null) { + nodes.put(instance.key, new LeafNode(instance)); + query(nodes, query, stack, 1); + } + return; + } + } + + query(nodes, query, stack, 0); + } + + private static Map read(InputStream in, + String[] queryClasses) + throws IOException + { + boolean done = false; + boolean popped = false; + Map records = new HashMap(); + Map nodes = new HashMap(); + List stack = new ArrayList(); + Record[] query = new Record[queryClasses.length]; + + Record roots = new Record(-1, ""); + records.put(roots.key, roots); + + while (! done) { + int flag = in.read(); + switch (flag) { + case Root: { + stack.clear(); + push(stack, new Instance(readInt(in))); + + query(nodes, query, stack); + + popped = false; + // System.out.println("root " + last); + } break; + + case ClassName: { + String name = readString(in); + Record r = record(records, peek(stack).key); + r.name = name; + + for (int i = 0; i < queryClasses.length; ++i) { + if (queryClasses[i].equals(name)) { + query[i] = r; + } + } + + query(nodes, query, stack); + } break; + + case Push: { + int key = readInt(in); + + if (! popped) { + peek(stack).record = record(records, key); + } + + push(stack, new Instance(key)); + + query(nodes, query, stack); + + popped = false; + } break; + + case Pop: { + pop(stack); + + popped = true; + } break; + + case Size: { + peek(stack).size = readInt(in); + } break; + + case -1: + done = true; + break; + + default: + throw new RuntimeException("bad flag: " + flag); + } + } + + return records; + } + + private static String[] copy(String[] array, int offset, int length) { + String[] copy = new String[length]; + if (length > 0) { + System.arraycopy(array, offset, copy, 0, length); + } + + return copy; + } + + private static void visitLeaves(Set nodes, LeafVisitor visitor) { + for (Node n: nodes) { + n.visitLeaves(visitor); + } + } + + private static void usageAndExit() { + System.err.println("usage: java QueryDump " + + " ..."); + } + + public static void main(String[] args) throws Exception { + if (args.length < 3) { + usageAndExit(); + } + + Map map = read + (new BufferedInputStream(new FileInputStream(args[0])), + copy(args, 2, args.length - 2)); + + for (Iterator it = map.values().iterator(); it.hasNext();) { + final Record r = it.next(); + if (r.nodes == null) { + it.remove(); + } else { + visitLeaves(r.nodes, new LeafVisitor() { + private Set set = new HashSet(); + + public void visit(LeafNode node) { + if (! set.contains(node.instance)) { + r.footprint += node.instance.size; + ++ r.count; + } + set.add(node.instance); + } + }); + } + } + + Record[] array = map.values().toArray(new Record[map.size()]); + Arrays.sort(array, new Comparator() { + public int compare(Record a, Record b) { + return b.footprint - a.footprint; + } + }); + + int wordSize = Integer.parseInt(args[1]); + + int footprint = 0; + int count = 0; + for (Record r: array) { + if (r.name == null) { + r.name = String.valueOf(r.key); + } + System.out.println + (r.name + ": " + (r.footprint * wordSize) + " " + r.count); + footprint += r.footprint; + count += r.count; + } + + System.out.println(); + System.out.println("total: " + (footprint * wordSize) + " " + count); + } + + private static class Record { + public final int key; + public String name; + public int footprint; + public int count; + public Set nodes; + + public Record(int key) { + this(key, null); + } + + public Record(int key, String name) { + this.key = key; + this.name = name; + } + + public String toString() { + return name; + } + } + + private static class Instance { + public final int key; + public int size; + public Record record; + + public Instance(int key) { + this.key = key; + } + + public String toString() { + return "[" + key + " " + record + "]"; + } + } + + public interface Node { + public void visitLeaves(LeafVisitor visitor); + public int index(); + } + + public static class LeafNode implements Node { + public final Instance instance; + + public LeafNode(Instance instance) { + this.instance = instance; + } + + public void visitLeaves(LeafVisitor visitor) { + visitor.visit(this); + } + + public int index() { + return 0; + } + } + + public static class TreeNode implements Node { + public final Instance instance; + public final int index; + + public final Set children = new HashSet(2); + + public TreeNode(Instance instance, int index) { + this.instance = instance; + this.index = index; + } + + public void visitLeaves(LeafVisitor visitor) { + QueryDump.visitLeaves(children, visitor); + } + + public int index() { + return index; + } + } + + public interface LeafVisitor { + public void visit(LeafNode node); + } +} From b8063285f32237430e8bb18c0fb5f0364d88d615 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 22 Nov 2010 16:46:10 -0700 Subject: [PATCH 120/274] fix deadlock MySystem::visit in posix.cpp We must call notifyAll on visitLock after setting threadVisitor to null in case another thread is waiting to do a visit of its own. Otherwise, the latter thread will wait forever, eventually deadlocking the whole VM at the next GC since it's in an active state. --- src/posix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posix.cpp b/src/posix.cpp index e5ec88b0a1..84f3a1fc60 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -655,6 +655,8 @@ class MySystem: public System { threadVisitor = 0; + system->visitLock->notifyAll(t); + return 0; } else { return -1; From 44fcc5c04e9b7ae2186dea7e16a18f0b0d557a7a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 22 Nov 2010 16:57:02 -0700 Subject: [PATCH 121/274] clean up properly if pthread_kill fails in MySystem::visit --- src/posix.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 84f3a1fc60..1ccf604f68 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -650,17 +650,22 @@ class MySystem: public System { int rv = pthread_kill(target->thread, VisitSignal); + int result; if (rv == 0) { while (visitTarget) visitLock->wait(t, 0); - threadVisitor = 0; - - system->visitLock->notifyAll(t); - - return 0; + result = 0; } else { - return -1; + visitTarget = 0; + + result = -1; } + + threadVisitor = 0; + + system->visitLock->notifyAll(t); + + return result; } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, From 9a676b4f1f824f3c8f92cdd48a8a074fbc20d201 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 23 Nov 2010 15:54:35 -0700 Subject: [PATCH 122/274] fix OS X 10.4 PowerPC cross-build --- makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index 20cb58e8ae..f4ac4b0849 100644 --- a/makefile +++ b/makefile @@ -117,6 +117,8 @@ common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread +converter-cflags = -D__STDC_CONSTANT_MACROS + cflags = $(build-cflags) common-lflags = -lm -lz $(gnu-lflags) @@ -172,7 +174,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),powerpc) ifneq (,$(filter i386 x86_64,$(build-arch))) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif cflags += -arch ppc asmflags += -arch ppc @@ -181,7 +183,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),i386) ifeq ($(build-arch),powerpc) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif cflags += -arch i386 asmflags += -arch i386 @@ -190,7 +192,7 @@ ifeq ($(platform),darwin) ifeq ($(arch),x86_64) ifeq ($(build-arch),powerpc) - converter-cflags = -DOPPOSITE_ENDIAN + converter-cflags += -DOPPOSITE_ENDIAN endif cflags += -arch x86_64 asmflags += -arch x86_64 From 4f23601b56bfc31f713e8b28f0d834453b926e3b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 26 Nov 2010 12:36:43 -0700 Subject: [PATCH 123/274] fix corner cases which led to crashes in JIT compiler Compiling the entire OpenJDK class library into a bootimage revealed some corner cases which broke the compiler, including synchronization in a finally block and gotos targeting the first instruction of an unsynchronized method. --- src/compiler.cpp | 112 +++++++++++++++++++++++++++++-------------- test/Misc.java | 21 ++++++++ test/Subroutine.java | 16 +++++++ 3 files changed, 112 insertions(+), 37 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index f6a2458aaa..f82c7a48a2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -982,9 +982,30 @@ valid(Read* r) return r and r->valid(); } -Read* -live(Value* v) +bool +hasBuddy(Context* c, Value* a, Value* b) { + if (a == b) { + return true; + } + + int i = 0; + for (Value* p = a->buddy; p != a; p = p->buddy) { + if (p == b) { + return true; + } + if (++i > 1000) { + abort(c); + } + } + return false; +} + +Read* +live(Context* c UNUSED, Value* v) +{ + assert(c, hasBuddy(c, v->buddy, v)); + Value* p = v; do { if (valid(p->reads)) { @@ -999,6 +1020,8 @@ live(Value* v) Read* liveNext(Context* c, Value* v) { + assert(c, hasBuddy(c, v->buddy, v)); + Read* r = v->reads->next(c); if (valid(r)) return r; @@ -1082,7 +1105,7 @@ popRead(Context* c, Event* e UNUSED, Value* v) } } - Read* r = live(v); + Read* r = live(c, v); if (r) { deadBuddy(c, v, r); } else { @@ -1493,7 +1516,7 @@ pickTarget(Context* c, Read* read, bool intersectRead, Value* successor = read->successor(); if (successor) { - Read* r = live(successor); + Read* r = live(c, successor); if (r) { SiteMask intersection = mask; if (r->intersect(&intersection)) { @@ -2534,7 +2557,7 @@ steal(Context* c, Resource* r, Value* thief) { r->site->freeze(c, r->value); - maybeMove(c, live(r->value), false, true, StealRegisterReserveCount); + maybeMove(c, live(c, r->value), false, true, StealRegisterReserveCount); r->site->thaw(c, r->value); } @@ -3360,9 +3383,9 @@ class CallEvent: public Event { clean(c, this, stackBefore, localsBefore, reads, popIndex); - if (resultSize and live(result)) { + if (resultSize and live(c, result)) { addSite(c, result, registerSite(c, c->arch->returnLow())); - if (resultSize > BytesPerWord and live(result->nextWord)) { + if (resultSize > BytesPerWord and live(c, result->nextWord)) { addSite(c, result->nextWord, registerSite(c, c->arch->returnHigh())); } } @@ -3446,7 +3469,7 @@ maybeMove(Context* c, BinaryOperation type, unsigned srcSize, unsigned srcSelectSize, Value* src, unsigned dstSize, Value* dst, const SiteMask& dstMask) { - Read* read = live(dst); + Read* read = live(c, dst); bool isStore = read == 0; Site* target; @@ -3607,8 +3630,8 @@ Site* pickSiteOrMove(Context* c, Value* src, Value* dst, Site* nextWord, unsigned index) { - if (live(dst)) { - Read* read = live(src); + if (live(c, dst)) { + Read* read = live(c, src); Site* s; if (nextWord) { s = pickMatchOrMove(c, read, nextWord, index, false); @@ -3727,7 +3750,7 @@ class MoveEvent: public Event { apply(c, Move, srcSelectSize, src->source, src->source, dstSize, dst->target, dst->target); - if (live(dst) == 0) { + if (live(c, dst) == 0) { removeSite(c, dst, dst->target); if (dstSize > BytesPerWord) { removeSite(c, dst->nextWord, dst->nextWord->target); @@ -3754,7 +3777,7 @@ class MoveEvent: public Event { assert(c, srcSize == BytesPerWord); assert(c, srcSelectSize == BytesPerWord); - if (dst->nextWord->target or live(dst->nextWord)) { + if (dst->nextWord->target or live(c, dst->nextWord)) { assert(c, dstLowMask.typeMask & (1 << RegisterOperand)); Site* low = freeRegisterSite(c, dstLowMask.registerMask); @@ -3945,12 +3968,12 @@ class CombineEvent: public Event { virtual void compile(Context* c) { assert(c, first->source->type(c) == first->nextWord->source->type(c)); - if (second->source->type(c) != second->nextWord->source->type(c)) { - fprintf(stderr, "%p %p %d : %p %p %d\n", - second, second->source, second->source->type(c), - second->nextWord, second->nextWord->source, - second->nextWord->source->type(c)); - } + // if (second->source->type(c) != second->nextWord->source->type(c)) { + // fprintf(stderr, "%p %p %d : %p %p %d\n", + // second, second->source, second->source->type(c), + // second->nextWord, second->nextWord->source, + // second->nextWord->source->type(c)); + // } assert(c, second->source->type(c) == second->nextWord->source->type(c)); @@ -4004,9 +4027,9 @@ class CombineEvent: public Event { high->thaw(c, second->nextWord); } - if (live(result)) { + if (live(c, result)) { addSite(c, result, low); - if (resultSize > lowSize and live(result->nextWord)) { + if (resultSize > lowSize and live(c, result->nextWord)) { addSite(c, result->nextWord, high); } } @@ -4043,11 +4066,11 @@ removeBuddy(Context* c, Value* v) assert(c, p->buddy); - if (not live(next)) { + if (not live(c, next)) { clearSites(c, next); } - if (not live(v)) { + if (not live(c, v)) { clearSites(c, v); } } @@ -4420,9 +4443,9 @@ class TranslateEvent: public Event { high->thaw(c, value->nextWord); } - if (live(result)) { + if (live(c, result)) { addSite(c, result, low); - if (resultSize > lowSize and live(result->nextWord)) { + if (resultSize > lowSize and live(c, result->nextWord)) { addSite(c, result->nextWord, high); } } @@ -4937,7 +4960,7 @@ class FrameSiteEvent: public Event { } virtual void compile(Context* c) { - if (live(value)) { + if (live(c, value)) { addSite(c, value, frameSite(c, index)); } } @@ -4975,7 +4998,7 @@ visit(Context* c, Link* link) Value* v = p->value; v->reads = p->read->nextTarget(); // fprintf(stderr, "next read %p for %p from %p\n", v->reads, v, p->read); - if (not live(v)) { + if (not live(c, v)) { clearSites(c, v); } } @@ -5238,7 +5261,7 @@ resolveOriginalSites(Context* c, Event* e, SiteRecordList* frozen, { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = v ? live(v) : 0; + Read* r = v ? live(c, v) : 0; Site* s = sites[el.localIndex]; if (r) { @@ -5282,7 +5305,7 @@ resolveSourceSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = live(v); + Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand), @@ -5316,7 +5339,7 @@ resolveTargetSites(Context* c, Event* e, SiteRecordList* frozen, Site** sites) for (FrameIterator it(c, e->stackAfter, e->localsAfter); it.hasMore();) { FrameIterator::Element el = it.next(c); Value* v = el.value; - Read* r = live(v); + Read* r = live(c, v); if (r and sites[el.localIndex] == 0) { SiteMask mask((1 << RegisterOperand) | (1 << MemoryOperand), @@ -5415,7 +5438,7 @@ populateSiteTables(Context* c, Event* e, SiteRecordList* frozen) void setSites(Context* c, Value* v, Site* s) { - assert(c, live(v)); + assert(c, live(c, v)); for (; s; s = s->next) { addSite(c, v, s->copy(c)); @@ -5444,7 +5467,7 @@ setSites(Context* c, Event* e, Site** sites) for (FrameIterator it(c, e->stackBefore, e->localsBefore); it.hasMore();) { FrameIterator::Element el = it.next(c); if (sites[el.localIndex]) { - if (live(el.value)) { + if (live(c, el.value)) { setSites(c, el.value, sites[el.localIndex]); } else if (DebugControl) { char buffer[256]; sitesToString(c, sites[el.localIndex], buffer, 256); @@ -5471,10 +5494,17 @@ void restore(Context* c, Event* e, Snapshot* snapshots) { for (Snapshot* s = snapshots; s; s = s->next) { - // char buffer[256]; sitesToString(c, s->sites, buffer, 256); - // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", - // s->value, s->value->buddy, buffer, live(s->value)); + Value* v = s->value; + Value* next = v->buddy; + if (v != next) { + v->buddy = v; + Value* p = next; + while (p->buddy != v) p = p->buddy; + p->buddy = next; + } + } + for (Snapshot* s = snapshots; s; s = s->next) { assert(c, s->buddy); s->value->buddy = s->buddy; @@ -5483,11 +5513,15 @@ restore(Context* c, Event* e, Snapshot* snapshots) resetFrame(c, e); for (Snapshot* s = snapshots; s; s = s->next) { - if (live(s->value)) { - if (live(s->value) and s->sites and s->value->sites == 0) { + if (live(c, s->value)) { + if (live(c, s->value) and s->sites and s->value->sites == 0) { setSites(c, s->value, s->sites); } } + + // char buffer[256]; sitesToString(c, s->sites, buffer, 256); + // fprintf(stderr, "restore %p buddy %p sites %s live %p\n", + // s->value, s->value->buddy, buffer, live(c, s->value)); } } @@ -5554,7 +5588,7 @@ updateJunctionReads(Context* c, JunctionState* state) FrameIterator::Element e = it.next(c); StubReadPair* p = state->reads + e.localIndex; if (p->value and p->read->read == 0) { - Read* r = live(e.value); + Read* r = live(c, e.value); if (r) { if (DebugReads) { fprintf(stderr, "stub read %p for %p valid: %p\n", @@ -5784,6 +5818,10 @@ addForkElement(Context* c, Value* v, ForkState* state, unsigned index) ForkState* saveState(Context* c) { + if (c->logicalCode[c->logicalIp]->lastEvent == 0) { + appendDummy(c); + } + unsigned elementCount = frameFootprint(c, c->stack) + count(c->saved); ForkState* state = new diff --git a/test/Misc.java b/test/Misc.java index 57bb0180e6..8a501392c7 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -104,7 +104,28 @@ public class Misc { return (o == null ? default_ : o); } + private static class Zam { + public void bim() { } + } + + private static class Zim { + public Object zum() { + return null; + } + } + + private static Zim zim = new Zim(); + + private static void zam() { + Zam z; + while ((z = (Zam) zim.zum()) != null) { + z.bim(); + } + } + public static void main(String[] args) { + zam(); + Bim bim = new Baz(); expect(bim.baz() == 42); diff --git a/test/Subroutine.java b/test/Subroutine.java index 2516d34398..d46bafe543 100644 --- a/test/Subroutine.java +++ b/test/Subroutine.java @@ -138,6 +138,19 @@ public class Subroutine { } } + public boolean test5(boolean predicate) { + try { + if (predicate) { + return false; + } + } finally { + synchronized (this) { + notifyAll(); + } + } + return true; + } + public static void main(String[] args) { test(false, false); test(false, true); @@ -188,6 +201,9 @@ public class Subroutine { String.valueOf(test4(3)); expect(test4(1) == 0xFABFABFABFL); + + new Subroutine().test5(true); + new Subroutine().test5(false); } private static class DummyException extends RuntimeException { } From 459f4d5194b9396fce2170d813da3d4fd0c937ef Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 26 Nov 2010 12:41:31 -0700 Subject: [PATCH 124/274] fix openjdk-src bootimage build The main change here is to use a lazily-populated vector to associate runtime data with classes instead of referencing them directly from the class which requires updating immutable references in the heap image. The other changes employ other strategies to avoid trying to update immutable references. --- classpath/avian/ClassAddendum.java | 6 +- classpath/avian/VMClass.java | 3 +- classpath/avian/VMMethod.java | 1 + classpath/java/lang/Class.java | 4 - makefile | 16 ++- src/bootimage.cpp | 214 +++++++++++++++++++++++------ src/classpath-avian.cpp | 2 +- src/classpath-openjdk.cpp | 86 +++++++++--- src/compile.cpp | 76 +++++++--- src/interpret.cpp | 6 +- src/jnienv.cpp | 26 +++- src/machine.cpp | 45 ++---- src/machine.h | 72 ++++++++-- src/process.cpp | 14 +- src/thunks.cpp | 1 + src/types.def | 8 ++ 16 files changed, 426 insertions(+), 154 deletions(-) diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index ce13dbe35a..adc45bbeb3 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -10,8 +10,4 @@ package avian; -public class ClassAddendum extends Addendum { - public volatile Class class_; - public Object[] signers; - public volatile Class arrayClass; -} +public class ClassAddendum extends Addendum { } diff --git a/classpath/avian/VMClass.java b/classpath/avian/VMClass.java index da9a64f832..b32ff7f689 100644 --- a/classpath/avian/VMClass.java +++ b/classpath/avian/VMClass.java @@ -16,6 +16,7 @@ public class VMClass { public short fixedSize; public byte arrayElementSize; public byte arrayDimensions; + public int runtimeDataIndex; public int[] objectMask; public byte[] name; public byte[] sourceFile; @@ -24,7 +25,7 @@ public class VMClass { public VMMethod[] virtualTable; public VMField[] fieldTable; public VMMethod[] methodTable; - public volatile avian.ClassAddendum addendum; + public avian.ClassAddendum addendum; public Object staticTable; public ClassLoader loader; } diff --git a/classpath/avian/VMMethod.java b/classpath/avian/VMMethod.java index 5a6754c034..e68d725242 100644 --- a/classpath/avian/VMMethod.java +++ b/classpath/avian/VMMethod.java @@ -18,6 +18,7 @@ public class VMMethod { public short flags; public short offset; public int nativeID; + public int runtimeDataIndex; public byte[] name; public byte[] spec; public MethodAddendum addendum; diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 15e4053175..1a6ea4a382 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -572,10 +572,6 @@ public final class Class implements Type, AnnotatedElement { return (T) o; } - public Object[] getSigners() { - return vmClass.addendum.signers; - } - public Package getPackage() { if ((vmClass.vmFlags & PrimitiveFlag) != 0 || isArray()) { return null; diff --git a/makefile b/makefile index 9d1c1c63cc..c7394d2140 100644 --- a/makefile +++ b/makefile @@ -72,13 +72,13 @@ ifeq ($(build-platform),darwin) library-path-variable = DYLD_LIBRARY_PATH endif -ifdef openjdk +ifneq ($(openjdk),) openjdk-arch = $(arch) ifeq ($(arch),x86_64) openjdk-arch = amd64 endif - ifdef openjdk-src + ifneq ($(openjdk-src),) include openjdk-src.mk options := $(options)-openjdk-src classpath-objects = $(openjdk-objects) @@ -436,8 +436,7 @@ endif bootimage-generator-sources = $(src)/bootimage.cpp bootimage-generator-objects = \ $(call cpp-objects,$(bootimage-generator-sources),$(src),$(build)) -bootimage-generator = \ - $(build)/$(bootimage-platform)-$(build-arch)$(options)/bootimage-generator +bootimage-generator = $(build)/bootimage-generator bootimage-bin = $(build)/bootimage.bin bootimage-object = $(build)/bootimage-bin.o @@ -454,10 +453,11 @@ $(error "bootimage cross-builds not yet supported") endif vm-classpath-object = $(bootimage-object) - cflags += -DBOOT_IMAGE=\"bootimageBin\" + cflags += -DBOOT_IMAGE=\"bootimageBin\" -DAVIAN_CLASSPATH=\"\" else vm-classpath-object = $(classpath-object) - cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" + cflags += -DBOOT_CLASSPATH=\"[classpathJar]\" \ + -DAVIAN_CLASSPATH=\"[classpathJar]\" endif driver-source = $(src)/main.cpp @@ -509,7 +509,7 @@ ifneq ($(classpath),avian) $(classpath-src)/avian/VMMethod.java \ $(classpath-src)/avian/resource/Handler.java - ifdef openjdk + ifneq ($(openjdk),) classpath-sources := $(classpath-sources) \ $(classpath-src)/avian/OpenJDK.java endif @@ -759,6 +759,8 @@ $(bootimage-generator): $(MAKE) mode=$(mode) \ arch=$(build-arch) \ platform=$(bootimage-platform) \ + openjdk=$(openjdk) \ + openjdk-src=$(openjdk-src) \ bootimage-generator= \ build-bootimage-generator=$(bootimage-generator) \ $(bootimage-generator) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index bc9b847cd8..cda4abd2a0 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -23,6 +23,38 @@ using namespace vm; namespace { +const unsigned HeapCapacity = 768 * 1024 * 1024; + +// Notes on immutable references in the heap image: +// +// One of the advantages of a bootimage-based build is that reduces +// the overhead of major GCs at runtime since we can avoid scanning +// the pre-built heap image entirely. However, this only works if we +// can ensure that no part of the heap image (with an exception noted +// below) ever points to runtime-allocated objects. Therefore (most) +// references in the heap image are considered immutable, and any +// attempt to update them at runtime will cause the process to abort. +// +// However, some references in the heap image really must be updated +// at runtime: e.g. the static field table for each class. Therefore, +// we allocate these as "fixed" objects, subject to mark-and-sweep +// collection, instead of as "copyable" objects subject to copying +// collection. This strategy avoids the necessity of maintaining +// "dirty reference" bitsets at runtime for the entire heap image; +// each fixed object has its own bitset specific to that object. +// +// In addition to the "fixed" object solution, there are other +// strategies available to avoid attempts to update immutable +// references at runtime: +// +// * Table-based: use a lazily-updated array or vector to associate +// runtime data with heap image objects (see +// e.g. getClassRuntimeData in machine.cpp). +// +// * Update references at build time: for example, we set the names +// of primitive classes before generating the heap image so that we +// need not populate them lazily at runtime. + bool endsWith(const char* suffix, const char* s, unsigned length) { @@ -44,7 +76,11 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, DelayedPromise* addresses = 0; - for (Finder::Iterator it(t->m->finder); it.hasMore();) { + for (Finder::Iterator it + (static_cast + (systemClassLoaderFinder(t, root(t, Machine::BootLoader)))); + it.hasMore();) + { unsigned nameSize = 0; const char* name = it.next(&nameSize); @@ -53,7 +89,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, { // fprintf(stderr, "%.*s\n", nameSize - 6, name); object c = resolveSystemClass - (t, makeByteArray(t, "%.*s", nameSize - 6, name)); + (t, root(t, Machine::BootLoader), + makeByteArray(t, "%.*s", nameSize - 6, name), true); if (t->exception) return 0; @@ -62,21 +99,53 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if ((methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) - and ((methodName == 0 + if (((methodName == 0 + or ::strcmp + (reinterpret_cast + (&byteArrayBody + (t, vm::methodName(t, method), 0)), methodName) == 0) + and (methodSpec == 0 or ::strcmp (reinterpret_cast (&byteArrayBody - (t, vm::methodName(t, method), 0)), methodName) == 0) - and (methodSpec == 0 - or ::strcmp - (reinterpret_cast - (&byteArrayBody - (t, vm::methodSpec(t, method), 0)), methodSpec) - == 0))) + (t, vm::methodSpec(t, method), 0)), methodSpec) + == 0))) { - t->m->processor->compileMethod - (t, zone, &constants, &calls, &addresses, method); + if (methodCode(t, method) + or (methodFlags(t, method) & ACC_NATIVE)) + { + PROTECT(t, method); + + t->m->processor->compileMethod + (t, zone, &constants, &calls, &addresses, method); + } + + object addendum = methodAddendum(t, method); + if (addendum and methodAddendumExceptionTable(t, addendum)) { + PROTECT(t, addendum); + + // resolve exception types now to avoid trying to update + // immutable references at runtime + for (unsigned i = 0; i < shortArrayLength + (t, methodAddendumExceptionTable(t, addendum)); ++i) + { + uint16_t index = shortArrayBody + (t, methodAddendumExceptionTable(t, addendum), i) - 1; + + object o = singletonObject + (t, addendumPool(t, addendum), index); + + if (objectClass(t, o) == type(t, Machine::ReferenceType)) { + o = resolveClass + (t, root(t, Machine::BootLoader), referenceName(t, o)); + + if (t->exception) return 0; + + set(t, addendumPool(t, addendum), + SingletonBody + (index * BytesPerWord), o); + } + } + } } } } @@ -89,7 +158,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (methodFlags(t, method) & ACC_NATIVE) { address = reinterpret_cast(code + image->thunks.native.start); } else { - address = methodCompiled(t, method); + address = codeCompiled(t, methodCode(t, method)); } static_cast(pointerValue(t, tripleSecond(t, calls))) @@ -131,14 +200,17 @@ visitRoots(Thread* t, BootImage* image, HeapWalker* w, object constants) { Machine* m = t->m; - for (HashMapIterator it(t, m->classMap); it.hasMore();) { + for (HashMapIterator it(t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { w->visitRoot(tripleSecond(t, it.next())); } - image->loader = w->visitRoot(m->loader); + image->bootLoader = w->visitRoot(root(t, Machine::BootLoader)); + image->appLoader = w->visitRoot(root(t, Machine::AppLoader)); image->types = w->visitRoot(m->types); - m->processor->visitRoots(w); + m->processor->visitRoots(t, w); for (; constants; constants = tripleThird(t, constants)) { w->visitRoot(tripleFirst(t, constants)); @@ -177,9 +249,17 @@ makeHeapImage(Thread* t, BootImage* image, uintptr_t* heap, uintptr_t* map, unsigned size = objectSize(t, p); unsigned number; - if (currentObject - and (currentOffset * BytesPerWord) == ClassStaticTable) + if ((currentObject + and (currentOffset * BytesPerWord) == ClassStaticTable) + or instanceOf(t, type(t, Machine::SystemClassLoaderType), p)) { + // Static tables and system classloaders must be allocated + // as fixed objects in the heap image so that they can be + // marked as dirty and visited during GC. Otherwise, + // attempts to update references in these objects to point + // to runtime-allocated memory would fail because we don't + // scan non-fixed objects in the heap image during GC. + FixedAllocator allocator (t->m->system, reinterpret_cast(heap + position), (capacity - position) * BytesPerWord); @@ -296,40 +376,90 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, PROTECT(t, constants); - const unsigned HeapCapacity = 32 * 1024 * 1024; + // this map will not be used when the bootimage is loaded, so + // there's no need to preserve it: + setRoot(t, Machine::ByteArrayMap, makeWeakHashMap(t, 0, 0)); + + // name all primitive classes so we don't try to update immutable + // references at runtime: + { object name = makeByteArray(t, "void"); + set(t, type(t, Machine::JvoidType), ClassName, name); + + name = makeByteArray(t, "boolean"); + set(t, type(t, Machine::JbooleanType), ClassName, name); + + name = makeByteArray(t, "byte"); + set(t, type(t, Machine::JbyteType), ClassName, name); + + name = makeByteArray(t, "short"); + set(t, type(t, Machine::JshortType), ClassName, name); + + name = makeByteArray(t, "char"); + set(t, type(t, Machine::JcharType), ClassName, name); + + name = makeByteArray(t, "int"); + set(t, type(t, Machine::JintType), ClassName, name); + + name = makeByteArray(t, "float"); + set(t, type(t, Machine::JfloatType), ClassName, name); + + name = makeByteArray(t, "long"); + set(t, type(t, Machine::JlongType), ClassName, name); + + name = makeByteArray(t, "double"); + set(t, type(t, Machine::JdoubleType), ClassName, name); + } + + collect(t, Heap::MajorCollection); + uintptr_t* heap = static_cast (t->m->heap->allocate(HeapCapacity)); uintptr_t* heapMap = static_cast (t->m->heap->allocate(heapMapSize(HeapCapacity))); memset(heapMap, 0, heapMapSize(HeapCapacity)); - // this map will not be used when the bootimage is loaded, so - // there's no need to preserve it: - t->m->byteArrayMap = makeWeakHashMap(t, 0, 0); - - collect(t, Heap::MajorCollection); - HeapWalker* heapWalker = makeHeapImage (t, image, heap, heapMap, HeapCapacity, constants); updateConstants(t, constants, code, codeMap, heapWalker->map()); - image->classCount = hashMapSize(t, t->m->classMap); - unsigned* classTable = static_cast - (t->m->heap->allocate(image->classCount * sizeof(unsigned))); + image->bootClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + + unsigned* bootClassTable = static_cast + (t->m->heap->allocate(image->bootClassCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->classMap); it.hasMore();) { - classTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::BootLoader))); + it.hasMore();) + { + bootClassTable[i++] = heapWalker->map()->find + (tripleSecond(t, it.next())); } } - image->stringCount = hashMapSize(t, t->m->stringMap); + image->appClassCount = hashMapSize + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + + unsigned* appClassTable = static_cast + (t->m->heap->allocate(image->appClassCount * sizeof(unsigned))); + + { unsigned i = 0; + for (HashMapIterator it + (t, classLoaderMap(t, root(t, Machine::AppLoader))); + it.hasMore();) + { + appClassTable[i++] = heapWalker->map()->find(tripleSecond(t, it.next())); + } + } + + image->stringCount = hashMapSize(t, root(t, Machine::StringMap)); unsigned* stringTable = static_cast (t->m->heap->allocate(image->stringCount * sizeof(unsigned))); { unsigned i = 0; - for (HashMapIterator it(t, t->m->stringMap); it.hasMore();) { + for (HashMapIterator it(t, root(t, Machine::StringMap)); it.hasMore();) { stringTable[i++] = heapWalker->map()->find (jreferenceTarget(t, tripleFirst(t, it.next()))); } @@ -344,17 +474,19 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, fprintf(stderr, "class count %d string count %d call count %d\n" "heap size %d code size %d\n", - image->classCount, image->stringCount, image->callCount, + image->bootClassCount, image->stringCount, image->callCount, image->heapSize, image->codeSize); if (true) { fwrite(image, sizeof(BootImage), 1, out); - fwrite(classTable, image->classCount * sizeof(unsigned), 1, out); + fwrite(bootClassTable, image->bootClassCount * sizeof(unsigned), 1, out); + fwrite(appClassTable, image->appClassCount * sizeof(unsigned), 1, out); fwrite(stringTable, image->stringCount * sizeof(unsigned), 1, out); fwrite(callTable, image->callCount * sizeof(unsigned) * 2, 1, out); - unsigned offset = (image->classCount * sizeof(unsigned)) + unsigned offset = (image->bootClassCount * sizeof(unsigned)) + + (image->appClassCount * sizeof(unsigned)) + (image->stringCount * sizeof(unsigned)) + (image->callCount * sizeof(unsigned) * 2); @@ -384,16 +516,18 @@ main(int ac, const char** av) } System* s = makeSystem(0); - Heap* h = makeHeap(s, 128 * 1024 * 1024); - Finder* f = makeFinder(s, av[1], 0); + Heap* h = makeHeap(s, HeapCapacity * 2); + Classpath* c = makeClasspath(s, h, AVIAN_JAVA_HOME, AVIAN_EMBED_PREFIX); + Finder* f = makeFinder(s, h, av[1], 0); Processor* p = makeProcessor(s, h, false); BootImage image; - const unsigned CodeCapacity = 16 * 1024 * 1024; + const unsigned CodeCapacity = 128 * 1024 * 1024; uint8_t* code = static_cast(h->allocate(CodeCapacity)); p->initialize(&image, code, CodeCapacity); - Machine* m = new (h->allocate(sizeof(Machine))) Machine(s, h, f, p, 0, 0); + Machine* m = new (h->allocate(sizeof(Machine))) Machine + (s, h, f, 0, p, c, 0, 0); Thread* t = p->makeThread(m, 0, 0); enter(t, Thread::ActiveState); diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index aacfb7e9d5..e86fae4079 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -95,7 +95,7 @@ class MyClasspath : public Classpath { virtual const char* bootClasspath() { - return BOOT_CLASSPATH; + return AVIAN_CLASSPATH; } virtual void diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 8d6c5994a5..4f18675a04 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -209,7 +209,7 @@ class MyClasspath : public Classpath { sb.append('\0'); this->classpath = sb.pointer; - sb.append(BOOT_CLASSPATH); + sb.append(AVIAN_CLASSPATH); sb.append(s->pathSeparator()); sb.append(javaHome); sb.append("/lib/rt.jar"); @@ -590,7 +590,8 @@ getFileAttributes } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file); return (r ? intValue(t, r) : 0); @@ -631,7 +632,8 @@ getLength return 0; } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), reinterpret_cast(arguments[0]), file); return (r ? longValue(t, r) : 0); @@ -703,7 +705,9 @@ openFile(Thread* t, object method, uintptr_t* arguments) = index + VirtualFileBase; } else { t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, path); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, path); } } @@ -740,7 +744,9 @@ readByteFromFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); return r ? intValue(t, r) : 0; } @@ -793,8 +799,9 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, dst, - offset, length); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, dst, offset, length); return r ? intValue(t, r) : 0; } @@ -837,7 +844,9 @@ skipBytesInFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_, count); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, count); return r ? longValue(t, r) : 0; } @@ -870,7 +879,9 @@ availableBytesInFile(Thread* t, object method, uintptr_t* arguments) } } else { object r = t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); return r ? intValue(t, r) : 0; } @@ -901,7 +912,9 @@ closeFile(Thread* t, object method, uintptr_t* arguments) 0); } else { t->m->processor->invoke - (t, nativeInterceptOriginal(t, methodCode(t, method)), this_); + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_); } } @@ -926,7 +939,11 @@ intercept(Thread* t, object c, const char* name, const char* spec, object native = makeNativeIntercept(t, function, true, clone); - set(t, m, MethodCode, native); + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, m); + + set(t, runtimeData, MethodRuntimeDataNative, native); } } @@ -1196,7 +1213,7 @@ resolveParameterJTypes(Thread* t, object loader, object spec, object resolveExceptionJTypes(Thread* t, object loader, object addendum) { - if (addendum == 0) { + if (addendum == 0 or methodAddendumExceptionTable(t, addendum) == 0) { return makeObjectArray(t, type(t, Machine::JclassType), 0); } @@ -2470,8 +2487,9 @@ EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - return makeLocalReference - (t, addendumAnnotationTable(t, classAddendum(t, jclassVmClass(t, *c)))); + object addendum = classAddendum(t, jclassVmClass(t, *c)); + return addendum + ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; } extern "C" JNIEXPORT jobjectArray JNICALL @@ -2537,7 +2555,12 @@ EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } @@ -2607,8 +2630,13 @@ EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) ? 0 : addendumAnnotationTable(t, fieldAddendum(t, vmField)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, - addendumPool(t, fieldAddendum(t, vmField))); + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, + addendumPool(t, methodAddendum(t, vmField))); } object field = makeJfield @@ -2680,7 +2708,12 @@ EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, ? 0 : addendumAnnotationTable(t, methodAddendum(t, vmMethod)); if (annotationTable) { - set(t, classAddendum(t, jclassVmClass(t, *c)), AddendumPool, + PROTECT(t, signature); + PROTECT(t, annotationTable); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataPool, addendumPool(t, methodAddendum(t, vmMethod))); } @@ -2766,9 +2799,20 @@ EXPORT(JVM_GetClassConstantPool)(Thread* t, jclass c) { ENTER(t, Thread::ActiveState); - return makeLocalReference - (t, makeConstantPool - (t, addendumPool(t, classAddendum(t, jclassVmClass(t, *c))))); + object vmClass = jclassVmClass(t, *c); + object addendum = classAddendum(t, vmClass); + object pool; + if (addendum) { + pool = addendumPool(t, addendum); + } else { + pool = 0; + } + + if (pool == 0) { + pool = classRuntimeDataPool(t, getClassRuntimeData(t, vmClass)); + } + + return makeLocalReference(t, makeConstantPool(t, pool)); } extern "C" JNIEXPORT jint JNICALL diff --git a/src/compile.cpp b/src/compile.cpp index 6a46b5b39a..fdd909d127 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2900,6 +2900,8 @@ handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function) if (methodFlags(t, method) & ACC_SYNCHRONIZED) { Compiler::Operand* lock; if (methodFlags(t, method) & ACC_STATIC) { + PROTECT(t, method); + lock = frame->append(methodClass(t, method)); } else { lock = loadLocal(frame->context, 1, savedTargetIndex(t, method)); @@ -3716,6 +3718,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), Compiler::AddressType), @@ -3729,6 +3733,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (instruction == getstatic) { assert(t, fieldFlags(t, field) & ACC_STATIC); + PROTECT(t, field); + if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { @@ -4127,7 +4133,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, unsigned instance = parameterFootprint - 1; - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + int returnCode = methodReturnCode(t, target); + + unsigned rSize = resultSize(t, returnCode); Compiler::Operand* result = c->stackCall (c->call @@ -4143,13 +4151,13 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, 0, frame->trace(0, 0), rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), + operandTypeForFieldCode(t, returnCode), parameterFootprint); frame->pop(parameterFootprint); if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + pushReturnValue(t, frame, returnCode, result); } } break; @@ -4385,12 +4393,20 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (singletonIsObject(t, pool, index - 1)) { object v = singletonObject(t, pool, index - 1); if (objectClass(t, v) == type(t, Machine::ReferenceType)) { - object class_ = resolveClassInPool(t, context->method, index - 1); + v = resolveClassInPool(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; + } - frame->pushObject(frame->append(getJClass(t, class_))); - } else if (objectClass(t, v) == type(t, Machine::ClassType)) { - frame->pushObject(frame->append(getJClass(t, v))); + if (objectClass(t, v) == type(t, Machine::ClassType)) { + frame->pushObject + (c->call + (c->constant + (getThunk(t, getJClassThunk), Compiler::AddressType), + 0, + frame->trace(0, 0), + BytesPerWord, + Compiler::ObjectType, + 2, c->register_(t->arch->thread()), frame->append(v))); } else { frame->pushObject(frame->append(v)); } @@ -4703,6 +4719,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (fieldClass(t, field) != methodClass(t, context->method) and classNeedsInit(t, fieldClass(t, field))) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, tryInitClassThunk), Compiler::AddressType), @@ -4729,6 +4747,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, and (fieldCode(t, field) == DoubleField or fieldCode(t, field) == LongField)) { + PROTECT(t, field); + c->call (c->constant (getThunk(t, acquireMonitorForObjectThunk), @@ -4766,6 +4786,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* table; if (instruction == putstatic) { + PROTECT(t, field); + table = frame->append(staticTable); } else { table = frame->popObject(); @@ -6308,7 +6330,7 @@ invokeNativeSlow(MyThread* t, object method, void* function) uint64_t invokeNative2(MyThread* t, object method) { - object native = methodCode(t, method); + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { return invokeNativeFast(t, method, nativeFunction(t, native)); } else { @@ -7276,7 +7298,7 @@ class MyProcessor: public Processor { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -7301,8 +7323,9 @@ class MyProcessor: public Processor { { return vm::makeClass (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, - objectMask, name, sourceFile, super, interfaceTable, virtualTable, - fieldTable, methodTable, staticTable, addendum, loader, vtableLength); + 0, objectMask, name, sourceFile, super, interfaceTable, + virtualTable, fieldTable, methodTable, staticTable, addendum, loader, + vtableLength); } virtual void @@ -7664,11 +7687,11 @@ class MyProcessor: public Processor { codeAllocator.capacity = ExecutableAreaSizeInBytes; } - roots = makeArray(t, RootCount); - if (image) { local::boot(static_cast(t), image); } else { + roots = makeArray(t, RootCount); + setRoot(t, CallTable, makeArray(t, 128)); setRoot(t, MethodTreeSentinal, makeTreeNode(t, 0, 0, 0)); @@ -8069,7 +8092,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) if (classMethodTable(t, c)) { for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); - if (methodCode(t, method) or (methodFlags(t, method) & ACC_NATIVE)) { + if (methodCode(t, method)) { assert(t, (methodCompiled(t, method) - image->codeBase) <= image->codeSize); @@ -8077,7 +8100,7 @@ fixupMethods(Thread* t, object map, BootImage* image, uint8_t* code) = (methodCompiled(t, method) - image->codeBase) + reinterpret_cast(code); - if (DebugCompile and (methodFlags(t, method) & ACC_NATIVE) == 0) { + if (DebugCompile) { logCompile (static_cast(t), reinterpret_cast(methodCompiled(t, method)), @@ -8180,11 +8203,16 @@ boot(MyThread* t, BootImage* image) t->m->heap->setImmortalHeap(heap, image->heapSize / BytesPerWord); - setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); - setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); t->m->types = bootObject(heap, image->types); + t->m->roots = makeArray(t, Machine::RootCount); + + setRoot(t, Machine::BootLoader, bootObject(heap, image->bootLoader)); + setRoot(t, Machine::AppLoader, bootObject(heap, image->appLoader)); + MyProcessor* p = static_cast(t->m->processor); + + p->roots = makeArray(t, RootCount); setRoot(t, MethodTree, bootObject(heap, image->methodTree)); setRoot(t, MethodTreeSentinal, bootObject(heap, image->methodTreeSentinal)); @@ -8195,11 +8223,17 @@ boot(MyThread* t, BootImage* image) syncInstructionCache(code, image->codeSize); - set(t, root(t, Machine::BootLoader), ClassLoaderMap, makeClassMap - (t, bootClassTable, image->bootClassCount, heap)); + { object map = makeClassMap(t, bootClassTable, image->bootClassCount, heap); + set(t, root(t, Machine::BootLoader), ClassLoaderMap, map); + } - set(t, root(t, Machine::AppLoader), ClassLoaderMap, makeClassMap - (t, appClassTable, image->appClassCount, heap)); + systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = t->m->bootFinder; + + { object map = makeClassMap(t, appClassTable, image->appClassCount, heap); + set(t, root(t, Machine::AppLoader), ClassLoaderMap, map); + } + + systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = t->m->appFinder; setRoot(t, Machine::StringMap, makeStringMap (t, stringTable, image->stringCount, heap)); diff --git a/src/interpret.cpp b/src/interpret.cpp index f14b7084d0..530af13b44 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -656,7 +656,7 @@ invokeNative(Thread* t, object method) return VoidField; } - object native = methodCode(t, method); + object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { pushFrame(t, method); @@ -3045,7 +3045,7 @@ class MyProcessor: public Processor { { return vm::makeMethod (t, vmFlags, returnCode, parameterCount, parameterFootprint, flags, - offset, 0, name, spec, addendum, class_, code); + offset, 0, 0, name, spec, addendum, class_, code); } virtual object @@ -3069,7 +3069,7 @@ class MyProcessor: public Processor { unsigned vtableLength UNUSED) { return vm::makeClass - (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, + (t, flags, vmFlags, fixedSize, arrayElementSize, arrayDimensions, 0, objectMask, name, sourceFile, super, interfaceTable, virtualTable, fieldTable, methodTable, addendum, staticTable, loader, 0); } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 44cbb0cb91..b315dac3ae 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -430,7 +430,8 @@ methodID(Thread* t, object method) if (methodNativeID(t, method) == 0) { setRoot(t, Machine::JNIMethodTable, vectorAppend (t, root(t, Machine::JNIMethodTable), method)); - methodNativeID(t, method) = vectorSize(t, root(t, Machine::JNIMethodTable)); + methodNativeID(t, method) = vectorSize + (t, root(t, Machine::JNIMethodTable)); } } @@ -2036,6 +2037,27 @@ append(char** p, const char* value, unsigned length, char tail) } } +void +boot(Thread* t) +{ + enter(t, Thread::ActiveState); + + if (t->exception == 0) { + setRoot(t, Machine::NullPointerException, t->m->classpath->makeThrowable + (t, Machine::NullPointerExceptionType)); + + if (t->exception == 0) { + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + t->m->classpath->makeThrowable + (t, Machine::ArrayIndexOutOfBoundsExceptionType)); + } + } + + t->m->classpath->boot(t); + + enter(t, Thread::IdleState); +} + } // namespace local } // namespace @@ -2349,5 +2371,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) *t = p->makeThread(*m, 0, 0); + local::boot(*t); + return 0; } diff --git a/src/machine.cpp b/src/machine.cpp index 0191e1d285..f2d6178318 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1314,6 +1314,7 @@ addInterfaceMethods(Thread* t, object class_, object virtualMap, methodFlags(t, method), (*virtualCount)++, 0, + 0, methodName(t, method), methodSpec(t, method), 0, @@ -1650,7 +1651,7 @@ parseAttributeTable(Thread* t, Stream& s, object class_, object pool) object body = makeByteArray(t, length); s.read(reinterpret_cast(&byteArrayBody(t, body, 0)), length); - object addendum = makeClassAddendum(t, pool, body, 0, 0, 0); + object addendum = makeClassAddendum(t, pool, body); set(t, class_, ClassAddendum, addendum); } else { @@ -1839,21 +1840,11 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) object resolveObjectArrayClass(Thread* t, object loader, object elementClass) { - object addendum = classAddendum(t, elementClass); - if (addendum) { - object arrayClass = classAddendumArrayClass(t, addendum); + { object arrayClass = classRuntimeDataArrayClass + (t, getClassRuntimeData(t, elementClass)); if (arrayClass) { return arrayClass; } - } else { - PROTECT(t, loader); - PROTECT(t, elementClass); - - ACQUIRE(t, t->m->classLock); - - object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); - - set(t, elementClass, ClassAddendum, addendum); } PROTECT(t, loader); @@ -1882,7 +1873,7 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass) object arrayClass = resolveClass(t, loader, spec); - set(t, classAddendum(t, elementClass), ClassAddendumArrayClass, + set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, arrayClass); return arrayClass; @@ -2104,7 +2095,7 @@ boot(Thread* t) { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod - (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); + (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); PROTECT(t, bootMethod); #include "type-java-initializations.cpp" @@ -2349,6 +2340,8 @@ Thread::init() m->unsafe = false; + enter(this, ActiveState); + if (image) { m->processor->boot(this, image); } else { @@ -2358,6 +2351,8 @@ Thread::init() setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0)); setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0)); + setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0)); + setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0)); setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); m->localThread->set(this); @@ -2373,25 +2368,6 @@ Thread::init() } threadPeer(this, javaThread) = reinterpret_cast(this); - - if (parent == 0) { - enter(this, Thread::ActiveState); - - if (exception == 0) { - setRoot(this, Machine::NullPointerException, m->classpath->makeThrowable - (this, Machine::NullPointerExceptionType)); - - if (exception == 0) { - setRoot(this, Machine::ArrayIndexOutOfBoundsException, - m->classpath->makeThrowable - (this, Machine::ArrayIndexOutOfBoundsExceptionType)); - } - } - - m->classpath->boot(this); - - enter(this, Thread::IdleState); - } } void @@ -3151,6 +3127,7 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) 0, // fixed size 0, // array size 0, // array dimensions + 0, // runtime data index 0, // object mask referenceName (t, singletonObject(t, pool, name - 1)), diff --git a/src/machine.h b/src/machine.h index 77c821e522..17bd0b41c3 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1194,6 +1194,8 @@ class Machine { MonitorMap, StringMap, ByteArrayMap, + ClassRuntimeDataTable, + MethodRuntimeDataTable, JNIMethodTable, ShutdownHooks, ObjectsToFinalize, @@ -3056,28 +3058,70 @@ resolveMethod(Thread* t, object method, unsigned index) (t, classLoader(t, methodClass(t, method)), method, index); } +object +vectorAppend(Thread*, object, object); + inline object -getJClass(Thread* t, object c) +getClassRuntimeData(Thread* t, object c) { - if (classAddendum(t, c) == 0) { + if (classRuntimeDataIndex(t, c) == 0) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); - object addendum = makeClassAddendum(t, 0, 0, 0, 0, 0); - - set(t, c, ClassAddendum, addendum); + if (classRuntimeDataIndex(t, c) == 0) { + object runtimeData = makeClassRuntimeData(t, 0, 0, 0); + + setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend + (t, root(t, Machine::ClassRuntimeDataTable), runtimeData)); + + classRuntimeDataIndex(t, c) = vectorSize + (t, root(t, Machine::ClassRuntimeDataTable)); + } } - object jclass = classAddendumClass(t, classAddendum(t, c)); + return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), + classRuntimeDataIndex(t, c) - 1); +} + +inline object +getMethodRuntimeData(Thread* t, object method) +{ + if (methodRuntimeDataIndex(t, method) == 0) { + PROTECT(t, method); + + ACQUIRE(t, t->m->classLock); + + if (methodRuntimeDataIndex(t, method) == 0) { + object runtimeData = makeMethodRuntimeData(t, 0); + + setRoot(t, Machine::MethodRuntimeDataTable, vectorAppend + (t, root(t, Machine::MethodRuntimeDataTable), runtimeData)); + + methodRuntimeDataIndex(t, method) = vectorSize + (t, root(t, Machine::MethodRuntimeDataTable)); + } + } + + return vectorBody(t, root(t, Machine::MethodRuntimeDataTable), + methodRuntimeDataIndex(t, method) - 1); +} + +inline object +getJClass(Thread* t, object c) +{ + object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); if (jclass == 0) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); - jclass = t->m->classpath->makeJclass(t, c); + jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); + if (jclass == 0) { + jclass = t->m->classpath->makeJclass(t, c); - set(t, classAddendum(t, c), ClassAddendumClass, jclass); + set(t, getClassRuntimeData(t, c), ClassRuntimeDataJclass, jclass); + } } return jclass; @@ -3111,12 +3155,15 @@ registerNative(Thread* t, object method, void* function) expect(t, methodFlags(t, method) & ACC_NATIVE); object native = makeNative(t, function, false); + PROTECT(t, native); - // ensure other threads only see the methodCode field populated - // once the object it points to has been populated: + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: storeStoreMemoryBarrier(); - set(t, method, MethodCode, native); + set(t, runtimeData, MethodRuntimeDataNative, native); } inline void @@ -3126,7 +3173,7 @@ unregisterNatives(Thread* t, object c) for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) { object method = arrayBody(t, classMethodTable(t, c), i); if (methodFlags(t, method) & ACC_NATIVE) { - set(t, method, MethodCode, 0); + set(t, getMethodRuntimeData(t, method), MethodRuntimeDataNative, 0); } } } @@ -3152,6 +3199,7 @@ methodClone(Thread* t, object method) methodFlags(t, method), methodOffset(t, method), methodNativeID(t, method), + methodRuntimeDataIndex(t, method), methodName(t, method), methodSpec(t, method), methodAddendum(t, method), diff --git a/src/process.cpp b/src/process.cpp index c9ed7a4505..e4835592a7 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -232,7 +232,9 @@ resolveNative(Thread* t, object method) initClass(t, methodClass(t, method)); - if (LIKELY(t->exception == 0) and methodCode(t, method) == 0) { + if (LIKELY(t->exception == 0) + and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) + { object native = resolveNativeMethod(t, method); if (UNLIKELY(native == 0)) { object message = makeString @@ -246,11 +248,15 @@ resolveNative(Thread* t, object method) return; } - // ensure other threads only see the methodCode field populated - // once the object it points do has been populated: + PROTECT(t, native); + + object runtimeData = getMethodRuntimeData(t, method); + + // ensure other threads only see the methodRuntimeDataNative field + // populated once the object it points to has been populated: storeStoreMemoryBarrier(); - set(t, method, MethodCode, native); + set(t, runtimeData, MethodRuntimeDataNative, native); } } diff --git a/src/thunks.cpp b/src/thunks.cpp index f55c0018a9..9de7aaf263 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -48,4 +48,5 @@ THUNK(instanceOf64) THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(set) +THUNK(getJClass) THUNK(gcIfNecessary) diff --git a/src/types.def b/src/types.def index 68db65d187..ae746d76b4 100644 --- a/src/types.def +++ b/src/types.def @@ -37,6 +37,14 @@ (type fieldAddendum avian/FieldAddendum) +(type classRuntimeData + (object arrayClass) + (object jclass) + (object pool)) + +(type methodRuntimeData + (object native)) + (type pointer (void* value)) From e68dfe1e89c8b1c5bd6d5655ceec48fc1c67b292 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 11:25:02 -0700 Subject: [PATCH 125/274] various fixes to get Eclipse 3.6 working * add libnet.so and libnio.so to built-in libraries for openjdk-src build * implement sun.misc.Unsafe.park/unpark * implement JVM_SetClassSigners/JVM_GetClassSigners * etc. --- makefile | 11 ++++- openjdk-src.mk | 77 +++++++++++++++++++++++++++++- src/classpath-openjdk.cpp | 99 +++++++++++++++++++++++++++++++++++++-- src/compile.cpp | 4 +- src/finder.cpp | 2 +- src/machine.cpp | 5 -- src/machine.h | 13 ++++- src/types.def | 4 +- 8 files changed, 198 insertions(+), 17 deletions(-) diff --git a/makefile b/makefile index c7394d2140..0ac94ab419 100644 --- a/makefile +++ b/makefile @@ -81,12 +81,12 @@ ifneq ($(openjdk),) ifneq ($(openjdk-src),) include openjdk-src.mk options := $(options)-openjdk-src - classpath-objects = $(openjdk-objects) + classpath-objects = $(openjdk-objects) $(openjdk-local-objects) classpath-cflags = -DAVIAN_OPENJDK_SRC -DBOOT_JAVAHOME openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar - javahome-files = lib/zi + javahome-files = lib/zi lib/currency.data ifeq ($(platform),windows) javahome-files += lib/tzmappings endif @@ -819,6 +819,13 @@ $(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ $(optimization-cflags) -w -c $(<) $(call output,$(@)) +$(openjdk-local-objects): $(build)/openjdk/%.o: $(src)/openjdk/%.c \ + $(openjdk-headers-dep) + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ + $(optimization-cflags) -w -c $(<) $(call output,$(@)) + $(openjdk-headers-dep): @echo "generating openjdk headers" @mkdir -p $(dir $(@)) diff --git a/openjdk-src.mk b/openjdk-src.mk index 84b6c91786..c3985492ce 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -32,6 +32,10 @@ openjdk-sources = \ $(openjdk-src)/share/native/java/lang/Thread.c \ $(openjdk-src)/share/native/java/lang/Throwable.c \ $(wildcard $(openjdk-src)/share/native/java/lang/fdlibm/src/*.c) \ + $(openjdk-src)/share/native/java/net/DatagramPacket.c \ + $(openjdk-src)/share/native/java/net/InetAddress.c \ + $(openjdk-src)/share/native/java/net/Inet4Address.c \ + $(openjdk-src)/share/native/java/net/Inet6Address.c \ $(openjdk-src)/share/native/java/nio/Bits.c \ $(openjdk-src)/share/native/java/security/AccessController.c \ $(openjdk-src)/share/native/java/sql/DriverManager.c \ @@ -70,6 +74,7 @@ openjdk-headers-classes = \ java.lang.Compiler \ java.lang.Double \ java.lang.Float \ + java.lang.Integer \ java.lang.Object \ java.lang.Package \ java.lang.Runtime \ @@ -83,6 +88,20 @@ openjdk-headers-classes = \ java.lang.ref.Finalizer \ java.lang.reflect.Array \ java.lang.reflect.Proxy \ + java.net.InetAddress \ + java.net.Inet4Address \ + java.net.Inet6Address \ + java.net.DatagramPacket \ + java.net.SocketOptions \ + java.net.InetAddressImplFactory \ + java.net.Inet4AddressImpl \ + java.net.Inet6AddressImpl \ + java.net.NetworkInterface \ + java.net.PlainSocketImpl \ + java.net.PlainDatagramSocketImpl \ + java.net.SocketInputStream \ + java.net.SocketOutputStream \ + java.nio.MappedByteBuffer \ java.security.AccessController \ java.util.ResourceBundle \ java.util.TimeZone \ @@ -101,6 +120,21 @@ openjdk-headers-classes = \ sun.misc.VM \ sun.misc.VMSupport \ sun.misc.Version \ + sun.net.spi.DefaultProxySelector \ + sun.nio.ch.FileKey \ + sun.nio.ch.FileChannelImpl \ + sun.nio.ch.FileDispatcher \ + sun.nio.ch.DatagramChannelImpl \ + sun.nio.ch.DatagramDispatcher \ + sun.nio.ch.IOStatus \ + sun.nio.ch.IOUtil \ + sun.nio.ch.Net \ + sun.nio.ch.ServerSocketChannelImpl \ + sun.nio.ch.SocketChannelImpl \ + sun.nio.ch.EPollArrayWrapper \ + sun.nio.ch.PollArrayWrapper \ + sun.nio.ch.InheritedChannel \ + sun.nio.ch.NativeThread \ sun.reflect.ConstantPool \ sun.reflect.NativeConstructorAccessorImpl \ sun.reflect.NativeMethodAccessorImpl \ @@ -116,7 +150,9 @@ openjdk-cflags = \ "-I$(openjdk-src)/share/native/java/io" \ "-I$(openjdk-src)/share/native/java/lang" \ "-I$(openjdk-src)/share/native/java/lang/fdlibm/include" \ + "-I$(openjdk-src)/share/native/java/net" \ "-I$(openjdk-src)/share/native/java/util/zip" \ + "-I$(openjdk-src)/share/native/sun/nio/ch" \ "-I$(openjdk-src)/share/javavm/include" \ -D_LITTLE_ENDIAN \ -DARCHPROPNAME=\"x86\" \ @@ -147,6 +183,10 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ $(openjdk-src)/windows/native/java/lang/java_props_md.c \ $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/windows/native/java/net/InetAddressImplFactory.c \ + $(openjdk-src)/windows/native/java/net/Inet4AddressImpl.c \ + $(openjdk-src)/windows/native/java/net/Inet6AddressImpl.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface.c \ $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ $(openjdk-src)/windows/native/java/util/logging.c \ $(openjdk-src)/windows/native/java/util/TimeZone_md.c \ @@ -158,6 +198,7 @@ ifeq ($(platform),windows) openjdk-cflags += "-I$(openjdk-src)/windows/javavm/export" \ "-I$(openjdk-src)/windows/native/common" \ "-I$(openjdk-src)/windows/native/java/io" \ + "-I$(openjdk-src)/windows/native/java/net" \ "-I$(openjdk-src)/windows/native/java/util" \ "-I$(openjdk-src)/windows/javavm/include" \ "-I$(root)/win32/include" \ @@ -178,9 +219,36 @@ else $(openjdk-src)/solaris/native/java/lang/java_props_md.c \ $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ + $(openjdk-src)/solaris/native/java/net/net_util_md.c \ + $(openjdk-src)/solaris/native/java/net/linux_close.c \ + $(openjdk-src)/solaris/native/java/net/InetAddressImplFactory.c \ + $(openjdk-src)/solaris/native/java/net/Inet4AddressImpl.c \ + $(openjdk-src)/solaris/native/java/net/Inet6AddressImpl.c \ + $(openjdk-src)/solaris/native/java/net/NetworkInterface.c \ + $(openjdk-src)/solaris/native/java/net/PlainSocketImpl.c \ + $(openjdk-src)/solaris/native/java/net/PlainDatagramSocketImpl.c \ + $(openjdk-src)/solaris/native/java/net/SocketInputStream.c \ + $(openjdk-src)/solaris/native/java/net/SocketOutputStream.c \ + $(openjdk-src)/solaris/native/java/nio/MappedByteBuffer.c \ $(openjdk-src)/solaris/native/java/util/FileSystemPreferences.c \ $(openjdk-src)/solaris/native/java/util/logging.c \ - $(openjdk-src)/solaris/native/java/util/TimeZone_md.c + $(openjdk-src)/solaris/native/java/util/TimeZone_md.c \ + $(openjdk-src)/solaris/native/sun/net/dns/ResolverConfigurationImpl.c \ + $(openjdk-src)/solaris/native/sun/net/spi/DefaultProxySelector.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/DatagramChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/DatagramDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/FileKey.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/IOUtil.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/Net.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/SocketChannelImpl.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/SocketDispatcher.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/EPollArrayWrapper.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/PollArrayWrapper.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/InheritedChannel.c \ + $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ openjdk-headers-classes += \ java.io.UnixFileSystem @@ -188,13 +256,20 @@ else openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ "-I$(openjdk-src)/solaris/native/common" \ "-I$(openjdk-src)/solaris/native/java/io" \ + "-I$(openjdk-src)/solaris/native/java/net" \ "-I$(openjdk-src)/solaris/native/java/util" \ "-I$(openjdk-src)/solaris/javavm/include" endif +openjdk-local-sources = \ + $(src)/openjdk/my_net_util.c + c-objects = $(foreach x,$(1),$(patsubst $(2)/%.c,$(3)/%.o,$(x))) openjdk-objects = \ $(call c-objects,$(openjdk-sources),$(openjdk-src),$(build)/openjdk) +openjdk-local-objects = \ + $(call c-objects,$(openjdk-local-sources),$(src)/openjdk,$(build)/openjdk) + openjdk-headers-dep = $(build)/openjdk/headers.dep diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 4f18675a04..5b226e9970 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -64,6 +64,7 @@ typedef int socklen_t; # include # include # include +# include # define OPEN open # define CLOSE close @@ -244,6 +245,22 @@ class MyClasspath : public Classpath { sb.append(SO_SUFFIX); sb.append('\0'); + this->netLibrary = sb.pointer; + sb.append(this->libraryPath); + sb.append("/"); + sb.append(SO_PREFIX); + sb.append("net"); + sb.append(SO_SUFFIX); + sb.append('\0'); + + this->nioLibrary = sb.pointer; + sb.append(this->libraryPath); + sb.append("/"); + sb.append(SO_PREFIX); + sb.append("nio"); + sb.append(SO_SUFFIX); + sb.append('\0'); + this->tzMappings = sb.pointer; sb.append(javaHome); sb.append("/lib/tzmappings"); @@ -414,6 +431,8 @@ class MyClasspath : public Classpath { const char* classpath; const char* libraryPath; const char* zipLibrary; + const char* netLibrary; + const char* nioLibrary; const char* tzMappings; const char* embedPrefix; unsigned tzMappingsLength; @@ -561,7 +580,10 @@ getFileAttributes stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); - if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p))) { + if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) + or pathEqual(cp->netLibrary, RUNTIME_ARRAY_BODY(p)) + or pathEqual(cp->nioLibrary, RUNTIME_ARRAY_BODY(p))) + { return Exists | Regular; } else { EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); @@ -1665,6 +1687,41 @@ Avian_sun_misc_Unsafe_ensureClassInitialized initClass(t, jclassVmClass(t, reinterpret_cast(arguments[1]))); } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_unpark +(Thread* t, object, uintptr_t* arguments) +{ + object thread = reinterpret_cast(arguments[1]); + + monitorAcquire(t, local::interruptLock(t, thread)); + threadUnparked(t, thread) = true; + monitorNotify(t, local::interruptLock(t, thread)); + monitorRelease(t, local::interruptLock(t, thread)); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_park +(Thread* t, object, uintptr_t* arguments) +{ + bool absolute = arguments[1]; + int64_t time; memcpy(&time, arguments + 2, 8); + + if (absolute) { + time -= t->m->system->now(); + } + + if (time <= 0) { + return; + } + + monitorAcquire(t, local::interruptLock(t, t->javaThread)); + while (not (threadUnparked(t, t->javaThread) + or monitorWait(t, local::interruptLock(t, t->javaThread), time))) + { } + threadUnparked(t, t->javaThread) = false; + monitorRelease(t, local::interruptLock(t, t->javaThread)); +} + extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetInterfaceVersion)() { @@ -1879,7 +1936,13 @@ EXPORT(JVM_MaxMemory)() } extern "C" JNIEXPORT jint JNICALL -EXPORT(JVM_ActiveProcessorCount)(void) { abort(); } +EXPORT(JVM_ActiveProcessorCount)() +{ + return 1; +} + +extern "C" JNIEXPORT jint JNICALL +net_JNI_OnLoad(JavaVM*, void*); extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_LoadLibrary)(const char* path) @@ -1892,9 +1955,18 @@ EXPORT(JVM_LoadLibrary)(const char* path) #ifdef AVIAN_OPENJDK_SRC if (local::pathEqual (static_cast(t->m->classpath)->zipLibrary, + RUNTIME_ARRAY_BODY(p)) + or local::pathEqual + (static_cast(t->m->classpath)->nioLibrary, RUNTIME_ARRAY_BODY(p))) { return t->m->libraries; + } else if (local::pathEqual + (static_cast(t->m->classpath)->netLibrary, + RUNTIME_ARRAY_BODY(p))) + { + net_JNI_OnLoad(t->m, 0); + return t->m->libraries; } #endif // AVIAN_OPENJDK_SRC @@ -1915,6 +1987,10 @@ EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) ENTER(t, Thread::ActiveState); + if (library == 0) { + library = t->m->libraries; + } + return static_cast(library)->resolve(name); } @@ -2411,10 +2487,25 @@ EXPORT(JVM_IsInterface)(Thread* t, jclass c) } extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassSigners)(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassSigners)(Thread* t, jclass c) +{ + ENTER(t, Thread::ActiveState); + + object runtimeData = getClassRuntimeDataIfExists(t, jclassVmClass(t, *c)); + + return runtimeData ? makeLocalReference + (t, classRuntimeDataSigners(t, runtimeData)) : 0; +} extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_SetClassSigners)(Thread*, jclass, jobjectArray) { abort(); } +EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) +{ + ENTER(t, Thread::ActiveState); + + object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); + + set(t, runtimeData, ClassRuntimeDataSigners, *signers); +} extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) diff --git a/src/compile.cpp b/src/compile.cpp index fdd909d127..53e31367f1 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2625,7 +2625,7 @@ throw_(MyThread* t, object o) (t, Machine::NullPointerExceptionType); } -// printTrace(t, t->exception); + // printTrace(t, t->exception); unwind(t); } @@ -7178,7 +7178,7 @@ class SegFaultHandler: public System::SignalHandler { t->exception = root(t, Machine::NullPointerException); } - printTrace(t, t->exception); + // printTrace(t, t->exception); object continuation; findUnwindTarget(t, ip, base, stack, &continuation); diff --git a/src/finder.cpp b/src/finder.cpp index 17e9078243..74f070102e 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -222,7 +222,7 @@ class DataRegion: public System::Region { } virtual void dispose() { - allocator->free(this, sizeof(*this)); + allocator->free(this, sizeof(*this) + length_); } System* s; diff --git a/src/machine.cpp b/src/machine.cpp index f2d6178318..415ecee29a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1882,9 +1882,6 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass) void removeMonitor(Thread* t, object o) { - expect(t, t->state == Thread::ExclusiveState - or t->state == Thread::ExitState); - unsigned hash; if (DebugMonitors) { hash = objectHash(t, o); @@ -1893,8 +1890,6 @@ removeMonitor(Thread* t, object o) object m = hashMapRemove (t, root(t, Machine::MonitorMap), o, objectHash, objectEqual); - expect(t, m); - if (DebugMonitors) { fprintf(stderr, "dispose monitor %p for object %x\n", m, hash); } diff --git a/src/machine.h b/src/machine.h index 17bd0b41c3..11c76b1c31 100644 --- a/src/machine.h +++ b/src/machine.h @@ -3061,6 +3061,17 @@ resolveMethod(Thread* t, object method, unsigned index) object vectorAppend(Thread*, object, object); +inline object +getClassRuntimeDataIfExists(Thread* t, object c) +{ + if (classRuntimeDataIndex(t, c)) { + return vectorBody(t, root(t, Machine::ClassRuntimeDataTable), + classRuntimeDataIndex(t, c) - 1); + } else { + return 0; + } +} + inline object getClassRuntimeData(Thread* t, object c) { @@ -3070,7 +3081,7 @@ getClassRuntimeData(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (classRuntimeDataIndex(t, c) == 0) { - object runtimeData = makeClassRuntimeData(t, 0, 0, 0); + object runtimeData = makeClassRuntimeData(t, 0, 0, 0, 0); setRoot(t, Machine::ClassRuntimeDataTable, vectorAppend (t, root(t, Machine::ClassRuntimeDataTable), runtimeData)); diff --git a/src/types.def b/src/types.def index ae746d76b4..b16cd79bf9 100644 --- a/src/types.def +++ b/src/types.def @@ -40,7 +40,8 @@ (type classRuntimeData (object arrayClass) (object jclass) - (object pool)) + (object pool) + (object signers)) (type methodRuntimeData (object native)) @@ -187,6 +188,7 @@ (require object sleepLock) (require object interruptLock) (require uint8_t interrupted) + (require uint8_t unparked) (alias peer uint64_t eetop)) (type threadGroup java/lang/ThreadGroup) From d4708907ea9fa1d4544218fb93f843d7484d1928 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 11:31:34 -0700 Subject: [PATCH 126/274] fix non-openjdk build --- classpath/java/lang/Thread.java | 1 + src/classpath-avian.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 3633921866..6e8ea0cae4 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -16,6 +16,7 @@ import java.util.WeakHashMap; public class Thread implements Runnable { private long peer; private volatile boolean interrupted; + private volatile boolean unparked; private boolean daemon; private byte state; private byte priority; diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index e86fae4079..509e13ece4 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -49,7 +49,7 @@ class MyClasspath : public Classpath { const unsigned NormalPriority = 5; return vm::makeThread - (t, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, + (t, 0, 0, 0, 0, NewState, NormalPriority, 0, 0, 0, root(t, Machine::BootLoader), 0, 0, group, 0); } From adc5c95214537dc97d922b82e004e64d034f32dc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 14:44:49 -0700 Subject: [PATCH 127/274] fix GC safety bug in resolveClass --- src/machine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 415ecee29a..77f5656ec0 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3294,15 +3294,15 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) } else { expect(t, throw_); + PROTECT(t, loader); + PROTECT(t, spec); + { object c = findLoadedClass(t, loader, spec); if (c) { return c; } } - PROTECT(t, loader); - PROTECT(t, spec); - if (byteArrayBody(t, spec, 0) == '[') { return resolveArrayClass(t, loader, spec, throw_); } else { From 1f6ccbf5b757a7d61bc573df5decb78f028b220d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 14:45:38 -0700 Subject: [PATCH 128/274] meant to add my_net_util.c in previous commit --- src/openjdk/my_net_util.c | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/openjdk/my_net_util.c diff --git a/src/openjdk/my_net_util.c b/src/openjdk/my_net_util.c new file mode 100644 index 0000000000..13eea537ae --- /dev/null +++ b/src/openjdk/my_net_util.c @@ -0,0 +1,2 @@ +#define JNI_OnLoad net_JNI_OnLoad +#include "net_util.c" From 0f04865e939024210a61c9ad26bd7eb28b2f682b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 14:46:07 -0700 Subject: [PATCH 129/274] implement -jar option in main.cpp --- makefile | 14 ++++--- src/main.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 7 deletions(-) diff --git a/makefile b/makefile index 0ac94ab419..cde9ffff5b 100644 --- a/makefile +++ b/makefile @@ -462,7 +462,10 @@ endif driver-source = $(src)/main.cpp driver-object = $(build)/main.o -driver-dynamic-object = $(build)/main-dynamic.o +driver-dynamic-objects = \ + $(build)/main-dynamic.o \ + $(build)/$(build-system).o \ + $(build)/finder.o boot-source = $(src)/boot.cpp boot-object = $(build)/boot.o @@ -657,7 +660,7 @@ $(heapwalk-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(driver-object): $(driver-source) $(compile-object) -$(driver-dynamic-object): $(driver-source) +$(build)/main-dynamic.o: $(driver-source) @echo "compiling $(@)" @mkdir -p $(dir $(@)) $(cxx) $(cflags) -DBOOT_LIBRARY=\"$(so-prefix)jvm$(so-suffix)\" \ @@ -797,14 +800,15 @@ else endif $(strip) $(strip-all) $(@) -$(executable-dynamic): $(driver-dynamic-object) $(dynamic-library) +$(executable-dynamic): $(driver-dynamic-objects) $(dynamic-library) @echo "linking $(@)" ifdef msvc $(ld) $(lflags) -LIBPATH:$(build) -DEFAULTLIB:$(name) \ - -PDB:$(@).pdb -IMPLIB:$(@).lib $(<) -out:$(@) -MANIFESTFILE:$(@).manifest + -PDB:$(@).pdb -IMPLIB:$(@).lib $(driver-dynamic-objects) -out:$(@) \ + -MANIFESTFILE:$(@).manifest $(mt) -manifest $(@).manifest -outputresource:"$(@);1" else - $(ld) $(<) -L$(build) -ljvm $(lflags) -o $(@) + $(ld) $(driver-dynamic-objects) -L$(build) -ljvm $(lflags) -o $(@) endif $(strip) $(strip-all) $(@) diff --git a/src/main.cpp b/src/main.cpp index 38cc765a3a..7bc5e85aa9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,9 @@ #include "string.h" #include "jni.h" +#include "system.h" +#include "finder.h" + #if (defined __MINGW32__) || (defined _MSC_VER) # define PATH_SEPARATOR ';' #else @@ -50,8 +53,92 @@ class RuntimeArray { #endif // not _MSC_VER +#ifdef BOOT_LIBRARY + +// since we aren't linking against libstdc++, we must implement this +// ourselves: +extern "C" void __cxa_pure_virtual(void) { abort(); } + +#endif // BOOT_LIBRARY + namespace { +bool +readLine(const uint8_t* base, unsigned total, unsigned* start, + unsigned* length) +{ + const uint8_t* p = base + *start; + const uint8_t* end = base + total; + while (p != end and (*p == '\n' or *p == '\r')) ++ p; + + *start = p - base; + while (p != end and not (*p == '\n' or *p == '\r')) ++ p; + + *length = (p - base) - *start; + + return *length != 0; +} + +const char* +mainClass(const char* jar) +{ + using namespace vm; + + System* system = makeSystem(0); + + class MyAllocator: public Allocator { + public: + MyAllocator(System* s): s(s) { } + + virtual void* tryAllocate(unsigned size) { + return s->tryAllocate(size); + } + + virtual void* allocate(unsigned size) { + void* p = tryAllocate(size); + if (p == 0) { + abort(s); + } + return p; + } + + virtual void free(const void* p, unsigned) { + s->free(p); + } + + System* s; + } allocator(system); + + Finder* finder = makeFinder(system, &allocator, jar, 0); + + const char* result = 0; + + System::Region* region = finder->find("META-INF/MANIFEST.MF"); + if (region) { + unsigned start = 0; + unsigned length; + while (readLine(region->start(), region->length(), &start, &length)) { + if (strncmp("Main-Class: ", reinterpret_cast + (region->start() + start), 12) == 0) + { + result = strndup + (reinterpret_cast(region->start() + start + 12), + length - 12); + break; + } + start += length; + } + + region->dispose(); + } + + finder->dispose(); + + system->dispose(); + + return result; +} + void usageAndExit(const char* name) { @@ -63,7 +150,7 @@ usageAndExit(const char* name) "\t[-Xbootclasspath:]\n" "\t[-Xbootclasspath/a:]\n" "\t[-D= ...]\n" - "\t [ ...]\n", name); + "\t{|-jar } [ ...]\n", name); exit(-1); } @@ -78,6 +165,7 @@ main(int ac, const char** av) vmArgs.ignoreUnrecognized = JNI_TRUE; const char* class_ = 0; + const char* jar = 0; int argc = 0; const char** argv = 0; const char* classpath = "."; @@ -87,12 +175,17 @@ main(int ac, const char** av) or strcmp(av[i], "-classpath") == 0) { classpath = av[++i]; + } else if (strcmp(av[i], "-jar") == 0) + { + jar = av[++i]; } else if (strncmp(av[i], "-X", 2) == 0 or strncmp(av[i], "-D", 2) == 0) { ++ vmArgs.nOptions; } else { - class_ = av[i++]; + if (jar == 0) { + class_ = av[i++]; + } if (i < ac) { argc = ac - i; argv = av + i; @@ -101,6 +194,17 @@ main(int ac, const char** av) } } + if (jar) { + classpath = jar; + + class_ = mainClass(jar); + + if (class_ == 0) { + fprintf(stderr, "Main-Class manifest header not found in %s\n", jar); + exit(-1); + } + } + #ifdef BOOT_LIBRARY ++ vmArgs.nOptions; #endif @@ -169,6 +273,11 @@ main(int ac, const char** av) JNIEnv* e = static_cast(env); jclass c = e->FindClass(class_); + + if (jar) { + free(const_cast(class_)); + } + if (not e->ExceptionCheck()) { jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V"); if (not e->ExceptionCheck()) { From 3cba6edf1fb8d04ab59ad959abb80d1dd9bc04d9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 16:27:22 -0700 Subject: [PATCH 130/274] print path elements if DebugFind == true in parsePath --- src/finder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/finder.cpp b/src/finder.cpp index 74f070102e..519f1efa6d 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -673,6 +673,10 @@ parsePath(System* s, Allocator* allocator, const char* path, } } + if (DebugFind) { + fprintf(stderr, "add element %.*s %p\n", token.length, token.s, e); + } + if (e) { if (prev) { prev->next = e; From 70a36c05b99aad4f7cbc18154101bbd23ffed8fa Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 27 Nov 2010 16:27:30 -0700 Subject: [PATCH 131/274] fix time==0 case in Unsafe.park and implement JVM_DumpThreads Also, set name field on system threads for OpenJDK build to avoid NPEs in Thread.getName. --- src/classpath-openjdk.cpp | 59 ++++++++++++++++++++++++--- src/machine.cpp | 84 +++++++++++++++++++-------------------- src/machine.h | 3 ++ 3 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 5b226e9970..2e08333c2a 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -313,6 +313,8 @@ class MyClasspath : public Classpath { setObjectClass(t, group, type(t, Machine::ThreadGroupType)); threadGroupMaxPriority(t, group) = MaxPriority; } + + PROTECT(t, group); object thread = allocate(t, FixedSizeOfThread, true); setObjectClass(t, thread, type(t, Machine::ThreadType)); @@ -320,6 +322,17 @@ class MyClasspath : public Classpath { threadGroup(t, thread) = group; threadContextClassLoader(t, thread) = root(t, Machine::BootLoader); + PROTECT(t, thread); + + const unsigned BufferSize = 256; + char buffer[BufferSize]; + unsigned length = vm::snprintf(buffer, BufferSize, "Thread-%p", thread); + object name = makeCharArray(t, length); + for (unsigned i = 0; i < length; ++i) { + charArrayBody(t, name, i) = buffer[i]; + } + set(t, thread, ThreadName, name); + return thread; } @@ -1708,10 +1721,9 @@ Avian_sun_misc_Unsafe_park if (absolute) { time -= t->m->system->now(); - } - - if (time <= 0) { - return; + if (time <= 0) { + return; + } } monitorAcquire(t, local::interruptLock(t, t->javaThread)); @@ -2162,7 +2174,44 @@ extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_DumpThreads)(Thread*, jclass, jobjectArray) { abort(); } +EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) +{ + ENTER(t, Thread::ActiveState); + + unsigned threadsLength = objectArrayLength(t, *threads); + object arrayClass = resolveObjectArrayClass + (t, classLoader(t, type(t, Machine::StackTraceElementType)), + type(t, Machine::StackTraceElementType)); + object result = makeObjectArray(t, arrayClass, threadsLength); + PROTECT(t, result); + + for (unsigned threadsIndex = 0; threadsIndex < threadsLength; + ++ threadsIndex) + { + Thread* peer = reinterpret_cast + (threadPeer(t, objectArrayBody(t, *threads, threadsIndex))); + + if (peer) { + object trace = t->m->processor->getStackTrace(t, peer); + PROTECT(t, trace); + + unsigned traceLength = objectArrayLength(t, trace); + object array = makeObjectArray + (t, type(t, Machine::StackTraceElementType), traceLength); + PROTECT(t, array); + + for (unsigned traceIndex = 0; traceIndex < traceLength; ++ traceIndex) { + object ste = makeStackTraceElement + (t, objectArrayBody(t, trace, traceIndex)); + set(t, array, ArrayBody + (traceIndex * BytesPerWord), ste); + } + + set(t, result, ArrayBody + (threadsIndex * BytesPerWord), array); + } + } + + return makeLocalReference(t, result); +} extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } diff --git a/src/machine.cpp b/src/machine.cpp index 77f5656ec0..ad112c6070 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1837,48 +1837,6 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) } } -object -resolveObjectArrayClass(Thread* t, object loader, object elementClass) -{ - { object arrayClass = classRuntimeDataArrayClass - (t, getClassRuntimeData(t, elementClass)); - if (arrayClass) { - return arrayClass; - } - } - - PROTECT(t, loader); - PROTECT(t, elementClass); - - object elementSpec = className(t, elementClass); - PROTECT(t, elementSpec); - - object spec; - if (byteArrayBody(t, elementSpec, 0) == '[') { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); - byteArrayBody(t, spec, 0) = '['; - memcpy(&byteArrayBody(t, spec, 1), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec)); - } else { - spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); - byteArrayBody(t, spec, 0) = '['; - byteArrayBody(t, spec, 1) = 'L'; - memcpy(&byteArrayBody(t, spec, 2), - &byteArrayBody(t, elementSpec, 0), - byteArrayLength(t, elementSpec) - 1); - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; - byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; - } - - object arrayClass = resolveClass(t, loader, spec); - - set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, - arrayClass); - - return arrayClass; -} - void removeMonitor(Thread* t, object o) { @@ -3519,6 +3477,48 @@ initClass(Thread* t, object c) } } +object +resolveObjectArrayClass(Thread* t, object loader, object elementClass) +{ + { object arrayClass = classRuntimeDataArrayClass + (t, getClassRuntimeData(t, elementClass)); + if (arrayClass) { + return arrayClass; + } + } + + PROTECT(t, loader); + PROTECT(t, elementClass); + + object elementSpec = className(t, elementClass); + PROTECT(t, elementSpec); + + object spec; + if (byteArrayBody(t, elementSpec, 0) == '[') { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1); + byteArrayBody(t, spec, 0) = '['; + memcpy(&byteArrayBody(t, spec, 1), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec)); + } else { + spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3); + byteArrayBody(t, spec, 0) = '['; + byteArrayBody(t, spec, 1) = 'L'; + memcpy(&byteArrayBody(t, spec, 2), + &byteArrayBody(t, elementSpec, 0), + byteArrayLength(t, elementSpec) - 1); + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';'; + byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0; + } + + object arrayClass = resolveClass(t, loader, spec); + + set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, + arrayClass); + + return arrayClass; +} + object makeObjectArray(Thread* t, object elementClass, unsigned count) { diff --git a/src/machine.h b/src/machine.h index 11c76b1c31..cb425953a9 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2196,6 +2196,9 @@ postInitClass(Thread* t, object c); void initClass(Thread* t, object c); +object +resolveObjectArrayClass(Thread* t, object loader, object elementClass); + object makeObjectArray(Thread* t, object elementClass, unsigned count); From 8de53aeacc2fe9c8560fc8fb6f9407f21acdddd7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 29 Nov 2010 17:39:41 -0700 Subject: [PATCH 132/274] fix Windows openjdk-src build --- makefile | 9 ++++++++- openjdk-src.mk | 36 ++++++++++++++++++++++++++++++------ src/main.cpp | 17 ++++++++++++----- src/openjdk/my_net_util.c | 18 ++++++++++++++++++ 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/makefile b/makefile index cde9ffff5b..10cc18eb47 100644 --- a/makefile +++ b/makefile @@ -86,9 +86,11 @@ ifneq ($(openjdk),) openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar - javahome-files = lib/zi lib/currency.data + javahome-files = lib/zi ifeq ($(platform),windows) javahome-files += lib/tzmappings + else + javahome-files += lib/currency.data endif javahome-object = $(build)/javahome-jar.o else @@ -835,6 +837,11 @@ $(openjdk-headers-dep): @mkdir -p $(dir $(@)) $(javah) -d $(build)/openjdk -bootclasspath $(boot-classpath) \ $(openjdk-headers-classes) +ifeq ($(platform),windows) + sed 's/^#ifdef _WIN64/#if 1/' \ + < "$(openjdk-src)/windows/native/java/net/net_util_md.h" \ + > $(build)/openjdk/net_util_md.h +endif @touch $(@) $(openjdk-jar-dep): diff --git a/openjdk-src.mk b/openjdk-src.mk index c3985492ce..b11819bd70 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -131,14 +131,14 @@ openjdk-headers-classes = \ sun.nio.ch.Net \ sun.nio.ch.ServerSocketChannelImpl \ sun.nio.ch.SocketChannelImpl \ - sun.nio.ch.EPollArrayWrapper \ + sun.nio.ch.SocketDispatcher \ sun.nio.ch.PollArrayWrapper \ - sun.nio.ch.InheritedChannel \ sun.nio.ch.NativeThread \ sun.reflect.ConstantPool \ sun.reflect.NativeConstructorAccessorImpl \ sun.reflect.NativeMethodAccessorImpl \ sun.reflect.Reflection \ + sun.security.provider.NativeSeedGenerator # todo: set properties according to architecture targeted and OpenJDK # version used: @@ -183,19 +183,38 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ $(openjdk-src)/windows/native/java/lang/java_props_md.c \ $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/windows/native/java/net/net_util_md.c \ $(openjdk-src)/windows/native/java/net/InetAddressImplFactory.c \ $(openjdk-src)/windows/native/java/net/Inet4AddressImpl.c \ $(openjdk-src)/windows/native/java/net/Inet6AddressImpl.c \ $(openjdk-src)/windows/native/java/net/NetworkInterface.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface_winXP.c \ + $(openjdk-src)/windows/native/java/net/NetworkInterface_win9x.c \ + $(openjdk-src)/windows/native/java/net/SocketInputStream.c \ + $(openjdk-src)/windows/native/java/net/SocketOutputStream.c \ $(openjdk-src)/windows/native/java/util/WindowsPreferences.c \ $(openjdk-src)/windows/native/java/util/logging.c \ $(openjdk-src)/windows/native/java/util/TimeZone_md.c \ $(openjdk-src)/windows/native/sun/io/Win32ErrorMode.c \ + $(openjdk-src)/windows/native/sun/nio/ch/DatagramChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/DatagramDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/FileKey.c \ + $(openjdk-src)/windows/native/sun/nio/ch/IOUtil.c \ + $(openjdk-src)/windows/native/sun/nio/ch/Net.c \ + $(openjdk-src)/windows/native/sun/nio/ch/ServerSocketChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/SocketChannelImpl.c \ + $(openjdk-src)/windows/native/sun/nio/ch/SocketDispatcher.c \ + $(openjdk-src)/windows/native/sun/nio/ch/WindowsSelectorImpl.c \ + $(openjdk-src)/windows/native/sun/security/provider/WinCAPISeedGenerator.c openjdk-headers-classes += \ - sun.io.Win32ErrorMode + sun.io.Win32ErrorMode \ + sun.nio.ch.WindowsSelectorImpl \ - openjdk-cflags += "-I$(openjdk-src)/windows/javavm/export" \ + openjdk-cflags += \ + "-I$(openjdk-src)/windows/javavm/export" \ "-I$(openjdk-src)/windows/native/common" \ "-I$(openjdk-src)/windows/native/java/io" \ "-I$(openjdk-src)/windows/native/java/net" \ @@ -203,7 +222,10 @@ ifeq ($(platform),windows) "-I$(openjdk-src)/windows/javavm/include" \ "-I$(root)/win32/include" \ -D_JNI_IMPLEMENTATION_ \ - -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ + -D_JAVASOFT_WIN32_TYPEDEF_MD_H_ \ + -D_WINSOCK2API_ \ + -Ds6_words=_s6_words \ + -Ds6_bytes=_s6_bytes else openjdk-sources += \ $(openjdk-src)/solaris/native/common/jdk_util_md.c \ @@ -251,7 +273,9 @@ else $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ openjdk-headers-classes += \ - java.io.UnixFileSystem + java.io.UnixFileSystem \ + sun.nio.ch.InheritedChannel \ + sun.nio.ch.EPollArrayWrapper \ openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ "-I$(openjdk-src)/solaris/native/common" \ diff --git a/src/main.cpp b/src/main.cpp index 7bc5e85aa9..bafca2a515 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,6 +59,11 @@ class RuntimeArray { // ourselves: extern "C" void __cxa_pure_virtual(void) { abort(); } +// we link against a System implmentation, which requires this at link +// time, but it should not be used at runtime: +extern "C" uint64_t +vmNativeCall(void*, void*, unsigned, unsigned) { abort(); } + #endif // BOOT_LIBRARY namespace { @@ -111,19 +116,21 @@ mainClass(const char* jar) Finder* finder = makeFinder(system, &allocator, jar, 0); - const char* result = 0; + char* result = 0; System::Region* region = finder->find("META-INF/MANIFEST.MF"); if (region) { unsigned start = 0; unsigned length; while (readLine(region->start(), region->length(), &start, &length)) { + const unsigned PrefixLength = 12; if (strncmp("Main-Class: ", reinterpret_cast - (region->start() + start), 12) == 0) + (region->start() + start), PrefixLength) == 0) { - result = strndup - (reinterpret_cast(region->start() + start + 12), - length - 12); + result = static_cast(malloc(length + 1 - PrefixLength)); + memcpy(result, region->start() + start + PrefixLength, + length - PrefixLength); + result[length - PrefixLength] = 0; break; } start += length; diff --git a/src/openjdk/my_net_util.c b/src/openjdk/my_net_util.c index 13eea537ae..11728df231 100644 --- a/src/openjdk/my_net_util.c +++ b/src/openjdk/my_net_util.c @@ -1,2 +1,20 @@ #define JNI_OnLoad net_JNI_OnLoad #include "net_util.c" + +#ifdef _WIN32 + +#undef IN6_SET_ADDR_UNSPECIFIED +#define IN6_SET_ADDR_UNSPECIFIED(a) \ + memset((a)->s6_bytes,0,sizeof(struct in6_addr)) + +void +IN6ADDR_SETANY(struct sockaddr_in6 *a) +{ + a->sin6_family = AF_INET6; + a->sin6_port = 0; + a->sin6_flowinfo = 0; + IN6_SET_ADDR_UNSPECIFIED(&a->sin6_addr); + a->sin6_scope_id = 0; +} + +#endif From 19dca18cd0356fd1f49efac99814b37aa6451adb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 30 Nov 2010 11:36:18 -0700 Subject: [PATCH 133/274] disable Math.abs(long) intrinsic on 32-bit x86 It never worked and caused the compiler to crash instead due to an impossible-to-fulfill constraint. --- src/x86.cpp | 8 ++++++-- test/Longs.java | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 3ff4f716bb..4e67576f1f 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2914,8 +2914,12 @@ class MyArchitecture: public Assembler::Architecture { break; case Absolute: - *aTypeMask = (1 << RegisterOperand); - *aRegisterMask = (static_cast(1) << rax); + if (aSize <= BytesPerWord) { + *aTypeMask = (1 << RegisterOperand); + *aRegisterMask = (static_cast(1) << rax); + } else { + *thunk = true; + } break; case FloatAbsolute: diff --git a/test/Longs.java b/test/Longs.java index e868dca385..7565b42121 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -60,6 +60,8 @@ public class Longs { } public static void main(String[] args) throws Exception { + expect(Math.abs(-123L) == 123L); + expect(readLongFrom(new java.io.InputStream() { int step; From 1d9489a76ea8085640fb1835aae709a912eb964c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 30 Nov 2010 16:58:51 -0700 Subject: [PATCH 134/274] fix a couple of 64-bit-op-on-32-bit-system bugs We weren't properly handling the case where a 64-bit value is multipled with itself in multiplyRR, leading to wrong code. Also, addCarryCR didn't know how to handle constants more than 8-bits wide. --- src/x86.cpp | 28 ++++++++++++++++++++++------ test/Longs.java | 17 +++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 4e67576f1f..65ac67ce30 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1403,17 +1403,18 @@ addRR(Context* c, unsigned aSize, Assembler::Register* a, } void -addCarryCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, +addCarryCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b) { int64_t v = a->value->value(); + maybeRex(c, size, b); if (isInt8(v)) { - maybeRex(c, size, b); opcode(c, 0x83, 0xd0 + regCode(b)); c->code.append(v); } else { - abort(c); + opcode(c, 0x81, 0xd0 + regCode(b)); + c->code.append4(v); } } @@ -1740,16 +1741,31 @@ multiplyRR(Context* c, unsigned aSize, Assembler::Register* a, Assembler::Register ah(a->high); Assembler::Register bh(b->high); + Assembler::Register tmp(-1); + Assembler::Register* scratch; + if (a->low == b->low) { + tmp.low = c->client->acquireTemporary + (GeneralRegisterMask & ~(1 << rax)); + scratch = &tmp; + moveRR(c, 4, b, 4, scratch); + } else { + scratch = b; + } + moveRR(c, 4, b, 4, &axdx); - multiplyRR(c, 4, &ah, 4, b); + multiplyRR(c, 4, &ah, 4, scratch); multiplyRR(c, 4, a, 4, &bh); - addRR(c, 4, &bh, 4, b); + addRR(c, 4, &bh, 4, scratch); // mul a->low,%eax%edx opcode(c, 0xf7, 0xe0 + a->low); - addRR(c, 4, b, 4, &bh); + addRR(c, 4, scratch, 4, &bh); moveRR(c, 4, &axdx, 4, b); + + if (tmp.low != -1) { + c->client->releaseTemporary(tmp.low); + } } else { maybeRex(c, aSize, b, a); opcode(c, 0x0f, 0xaf); diff --git a/test/Longs.java b/test/Longs.java index 7565b42121..8c34fddce9 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -243,6 +243,23 @@ public class Longs { expect(buffer.getLong() == 231); expect(unsignedShiftRight32(231) == 0); + + { int[] x = new int[] { 1701899151 }; + int[] z = new int[x.length * 2]; + final long LONG_MASK = 0xffffffffL; + + int lastProductLowWord = 0; + for (int j=0, i=0; j>> 33); + z[i++] = (int) (product >>> 1); + lastProductLowWord = (int) product; + } + + expect(z[0] == 337192406); + expect(z[1] == -437261072); + } } } From 21a54cdf55476e7c704b83cfe4a4745a7ae4f38f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 30 Nov 2010 20:25:48 -0700 Subject: [PATCH 135/274] set java.protocol.handler.pkgs on Windows as well as Posix Also, fix cut-and-paste error where we should have called fieldAddendum instead of methodAddendum. --- src/classpath-openjdk.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 2e08333c2a..8469568927 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1853,10 +1853,11 @@ EXPORT(JVM_InitProperties)(Thread* t, jobject properties) local::setProperty(t, method, *properties, "java.io.tmpdir", "/tmp"); local::setProperty(t, method, *properties, "user.home", getenv("HOME")); local::setProperty(t, method, *properties, "user.dir", getenv("PWD")); +#endif + local::setProperty(t, method, *properties, "java.protocol.handler.pkgs", "avian"); -#endif local::setProperty (t, method, *properties, "java.home", static_cast(t->m->classpath)->javaHome); @@ -2776,7 +2777,7 @@ EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) object runtimeData = getClassRuntimeData(t, jclassVmClass(t, *c)); set(t, runtimeData, ClassRuntimeDataPool, - addendumPool(t, methodAddendum(t, vmField))); + addendumPool(t, fieldAddendum(t, vmField))); } object field = makeJfield From cca9a5ee0bb57c046b85d3cd82827c8541941681 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 30 Nov 2010 20:27:07 -0700 Subject: [PATCH 136/274] build ProcessImpl_md.c as part of Windows openjdk-src build --- openjdk-src.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openjdk-src.mk b/openjdk-src.mk index b11819bd70..8f5a9630d1 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -183,6 +183,7 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/java/io/WinNTFileSystem_md.c \ $(openjdk-src)/windows/native/java/lang/java_props_md.c \ $(openjdk-src)/windows/native/java/lang/ProcessEnvironment_md.c \ + $(openjdk-src)/windows/native/java/lang/ProcessImpl_md.c \ $(openjdk-src)/windows/native/java/net/net_util_md.c \ $(openjdk-src)/windows/native/java/net/InetAddressImplFactory.c \ $(openjdk-src)/windows/native/java/net/Inet4AddressImpl.c \ @@ -210,6 +211,7 @@ ifeq ($(platform),windows) $(openjdk-src)/windows/native/sun/security/provider/WinCAPISeedGenerator.c openjdk-headers-classes += \ + java.lang.ProcessImpl \ sun.io.Win32ErrorMode \ sun.nio.ch.WindowsSelectorImpl \ From 4b1b3e032b70c1894eb7948372c36c12018b38dd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 30 Nov 2010 20:27:36 -0700 Subject: [PATCH 137/274] add new array classes to classloader map upon creation We were already doing this for non-array classes; we need to do it for all classes or else risk creating duplicates. --- src/machine.cpp | 52 ++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index ad112c6070..89512b0b59 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3255,14 +3255,13 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) PROTECT(t, loader); PROTECT(t, spec); - { object c = findLoadedClass(t, loader, spec); - if (c) { - return c; - } + object c = findLoadedClass(t, loader, spec); + if (c) { + return c; } if (byteArrayBody(t, spec, 0) == '[') { - return resolveArrayClass(t, loader, spec, throw_); + c = resolveArrayClass(t, loader, spec, throw_); } else { if (root(t, Machine::LoadClassMethod) == 0) { object m = resolveMethod @@ -3295,34 +3294,35 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - object c = t->m->processor->invoke(t, method, loader, specString); - - if (LIKELY(c and t->exception == 0)) { - PROTECT(t, c); - - ACQUIRE(t, t->m->classLock); - - if (classLoaderMap(t, loader) == 0) { - object map = makeHashMap(t, 0, 0); - set(t, loader, ClassLoaderMap, map); - } - - c = jclassVmClass(t, c); - - hashMapInsert - (t, classLoaderMap(t, loader), spec, c, byteArrayHash); - - return c; + object jc = t->m->processor->invoke(t, method, loader, specString); + if (LIKELY(jc and t->exception == 0)) { + c = jclassVmClass(t, jc); } } } + } + if (LIKELY(c and t->exception == 0)) { + PROTECT(t, c); + + ACQUIRE(t, t->m->classLock); + + if (classLoaderMap(t, loader) == 0) { + object map = makeHashMap(t, 0, 0); + set(t, loader, ClassLoaderMap, map); + } + + hashMapInsert + (t, classLoaderMap(t, loader), spec, c, byteArrayHash); + + return c; + } else { if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); t->exception = t->m->classpath->makeThrowable (t, Machine::ClassNotFoundExceptionType, message); } - + return 0; } } @@ -3883,6 +3883,8 @@ printTrace(Thread* t, object exception) break; } } + + fflush(stderr); } object @@ -4087,6 +4089,8 @@ vmPrintTrace(Thread* t) fprintf(stderr, "debug trace for thread %p\n", t); t->m->processor->walkStack(t, &v); + + fflush(stderr); } // also for debugging From 6a7f651f79f51757a3e2aad93adad8280c0d4e19 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 08:33:00 -0700 Subject: [PATCH 138/274] fix OS X openjdk-src build --- openjdk-src.mk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openjdk-src.mk b/openjdk-src.mk index 8f5a9630d1..df23e4772c 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -244,7 +244,6 @@ else $(openjdk-src)/solaris/native/java/lang/ProcessEnvironment_md.c \ $(openjdk-src)/solaris/native/java/lang/UNIXProcess_md.c \ $(openjdk-src)/solaris/native/java/net/net_util_md.c \ - $(openjdk-src)/solaris/native/java/net/linux_close.c \ $(openjdk-src)/solaris/native/java/net/InetAddressImplFactory.c \ $(openjdk-src)/solaris/native/java/net/Inet4AddressImpl.c \ $(openjdk-src)/solaris/native/java/net/Inet6AddressImpl.c \ @@ -274,6 +273,11 @@ else $(openjdk-src)/solaris/native/sun/nio/ch/InheritedChannel.c \ $(openjdk-src)/solaris/native/sun/nio/ch/NativeThread.c \ + ifeq ($(platform),linux) + openjdk-sources += \ + $(openjdk-src)/solaris/native/java/net/linux_close.c + endif + openjdk-headers-classes += \ java.io.UnixFileSystem \ sun.nio.ch.InheritedChannel \ @@ -284,7 +288,8 @@ else "-I$(openjdk-src)/solaris/native/java/io" \ "-I$(openjdk-src)/solaris/native/java/net" \ "-I$(openjdk-src)/solaris/native/java/util" \ - "-I$(openjdk-src)/solaris/javavm/include" + "-I$(openjdk-src)/solaris/javavm/include" \ + "-I$(openjdk-src)/solaris/hpi/include" endif openjdk-local-sources = \ From 8f06ac402ada10c69fd25c2b4c1de16999c3e722 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 09:54:29 -0700 Subject: [PATCH 139/274] compare library to RTLD_DEFAULT, not zero in JVM_FindLibraryEntry Although RTLD_DEFAULT is zero on Linux, it's not on OS X. --- src/classpath-openjdk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 8469568927..33c1dc3784 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2000,7 +2000,7 @@ EXPORT(JVM_FindLibraryEntry)(void* library, const char* name) ENTER(t, Thread::ActiveState); - if (library == 0) { + if (library == RTLD_DEFAULT) { library = t->m->libraries; } From 6d1ad1e5baaae8b84b0f89deab193cc8dbd8fae9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 13:40:43 -0700 Subject: [PATCH 140/274] intercept UnixFileSystem.checkAccess calls to handle embedded java home case --- src/classpath-openjdk.cpp | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 33c1dc3784..9c115aaa2f 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -634,6 +634,63 @@ getFileAttributes } } +int64_t JNICALL +checkFileAccess +(Thread* t, object method, uintptr_t* arguments) +{ + const unsigned Read = 4; + + MyClasspath* cp = static_cast(t->m->classpath); + + object file = reinterpret_cast(arguments[1]); + unsigned mask = arguments[2]; + object path = cast(file, cp->filePathField); + + RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + stringChars(t, path, RUNTIME_ARRAY_BODY(p)); + replace('\\', '/', RUNTIME_ARRAY_BODY(p)); + + if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) + or pathEqual(cp->netLibrary, RUNTIME_ARRAY_BODY(p)) + or pathEqual(cp->nioLibrary, RUNTIME_ARRAY_BODY(p))) + { + return mask == Read; + } else { + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return mask == Read; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { + return mask == Read; + } + + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeDoesNotExist: return false; + case System::TypeUnknown: + case System::TypeFile: + case System::TypeDirectory: return mask == Read; + default: abort(t); + } + } else { + return 0; + } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file, mask); + + return (r ? booleanValue(t, r) : false); + } + } +} + int64_t JNICALL getLength (Thread* t, object method, uintptr_t* arguments) @@ -1057,6 +1114,9 @@ interceptFileOperations(Thread* t) intercept(t, fsClass, gbaMethodName, "(Ljava/io/File;)I", voidPointer(getFileAttributes)); + + intercept(t, fsClass, "checkAccess", "(Ljava/io/File;I)Z", + voidPointer(checkFileAccess)); intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", voidPointer(getLength)); From d00f4c53901cbad468e23927e83bfce4c207bfd1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 15:41:55 -0700 Subject: [PATCH 141/274] fix BufferedInputStream.read to not read more than specified length --- classpath/java/io/BufferedInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index 6d1c69b0ce..778523d507 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -67,6 +67,7 @@ public class BufferedInputStream extends InputStream { break; } else { count += c; + length -= c; if (in.available() <= 0) { break; From 1722b682773c8497092949ea399edda182249e0f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 15:42:46 -0700 Subject: [PATCH 142/274] handle case of not-yet-started thread in setDaemon --- src/machine.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/machine.h b/src/machine.h index cb425953a9..beeb84363e 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1444,12 +1444,6 @@ class Classpath { dispose() = 0; }; -inline void -runJavaThread(Thread* t) -{ - t->m->classpath->runThread(t); -} - Classpath* makeClasspath(System* system, Allocator* allocator, const char* javaHome, const char* embedPrefix); @@ -1759,6 +1753,16 @@ instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" +inline void +runJavaThread(Thread* t) +{ + if (threadDaemon(t, t->javaThread)) { + atomicOr(&(t->flags), Thread::DaemonFlag); + } + + t->m->classpath->runThread(t); +} + inline object& root(Thread* t, Machine::Root root) { @@ -2812,10 +2816,12 @@ setDaemon(Thread* t, object thread, bool daemon) threadDaemon(t, thread) = daemon; Thread* p = reinterpret_cast(threadPeer(t, thread)); - if (daemon) { - atomicOr(&(p->flags), Thread::DaemonFlag); - } else { - atomicAnd(&(p->flags), ~Thread::DaemonFlag); + if (p) { + if (daemon) { + atomicOr(&(p->flags), Thread::DaemonFlag); + } else { + atomicAnd(&(p->flags), ~Thread::DaemonFlag); + } } if (daemon) { From 8cbe323d52b2e520d1dc55b112d82dd9310909b6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 15:43:27 -0700 Subject: [PATCH 143/274] update Avian_avian_Machine_dumpHeap to reflect classpath refactoring --- src/builtin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index 75de37c759..55b4c3f02a 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -126,7 +126,8 @@ Avian_avian_Machine_dumpHeap fclose(out); } else { object message = makeString(t, "file not found: %s", n); - t->exception = makeRuntimeException(t, message); + t->exception = t->m->classpath->makeThrowable + (t, Machine::RuntimeExceptionType, message); } } From 7164743009576b64d71a93edb1199e9464e20453 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 15:44:09 -0700 Subject: [PATCH 144/274] fix Array.makeObjectArray regression --- src/classpath-avian.cpp | 2 +- test/Arrays.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 509e13ece4..8bc2560086 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -366,7 +366,7 @@ Avian_java_lang_reflect_Array_makeObjectArray int length = arguments[1]; return reinterpret_cast - (makeObjectArray(t, elementType, length)); + (makeObjectArray(t, jclassVmClass(t, elementType), length)); } extern "C" JNIEXPORT int64_t JNICALL diff --git a/test/Arrays.java b/test/Arrays.java index acc6e8a9c6..96f5f598f0 100644 --- a/test/Arrays.java +++ b/test/Arrays.java @@ -71,5 +71,11 @@ public class Arrays { expect(array[1023] == -1); expect(array[1022] == 0); } + + { Integer[] array = (Integer[]) + java.lang.reflect.Array.newInstance(Integer.class, 1); + array[0] = Integer.valueOf(42); + expect(array[0].intValue() == 42); + } } } From af8e043989e36832b01751c8a375accd1183b37e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 16:05:56 -0700 Subject: [PATCH 145/274] fix windows cross build --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 6583457df3..23469d9e43 100644 --- a/makefile +++ b/makefile @@ -468,7 +468,7 @@ driver-source = $(src)/main.cpp driver-object = $(build)/main.o driver-dynamic-objects = \ $(build)/main-dynamic.o \ - $(build)/$(build-system).o \ + $(build)/$(system).o \ $(build)/finder.o boot-source = $(src)/boot.cpp From 4a3b5ad1ab1c2d5f5c425e3befadfd002a028035 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 20:05:22 -0700 Subject: [PATCH 146/274] fix windows cross openjdk-src build This mainly involves some makefile ugliness to work around bugs in the native Windows OpenJDK code involving conflicting static and not-static declarations which GCC 4.0 and later justifiably reject but MSVC tolerates. --- makefile | 31 ++++++++++++++++------------ openjdk-src.mk | 1 + src/classpath-openjdk.cpp | 2 ++ src/openjdk/caseSensitive/WS2tcpip.h | 1 + 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 src/openjdk/caseSensitive/WS2tcpip.h diff --git a/makefile b/makefile index 23469d9e43..200d132d71 100644 --- a/makefile +++ b/makefile @@ -268,18 +268,18 @@ ifeq ($(platform),windows) ifeq (,$(filter mingw32 cygwin,$(build-platform))) openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive - cxx = x86_64-w64-mingw32-g++ -m32 - cc = x86_64-w64-mingw32-gcc -m32 - dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 - ar = x86_64-w64-mingw32-ar - ranlib = x86_64-w64-mingw32-ranlib - strip = x86_64-w64-mingw32-strip --strip-all - # cxx = i586-mingw32msvc-g++ - # cc = i586-mingw32msvc-gcc - # dlltool = i586-mingw32msvc-dlltool - # ar = i586-mingw32msvc-ar - # ranlib = i586-mingw32msvc-ranlib - # strip = i586-mingw32msvc-strip + # cxx = x86_64-w64-mingw32-g++ -m32 + # cc = x86_64-w64-mingw32-gcc -m32 + # dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 + # ar = x86_64-w64-mingw32-ar + # ranlib = x86_64-w64-mingw32-ranlib + # strip = x86_64-w64-mingw32-strip --strip-all + cxx = i586-mingw32msvc-g++ + cc = i586-mingw32msvc-gcc + dlltool = i586-mingw32msvc-dlltool + ar = i586-mingw32msvc-ar + ranlib = i586-mingw32msvc-ranlib + strip = i586-mingw32msvc-strip --strip-all else build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" @@ -824,8 +824,10 @@ $(openjdk-objects): $(build)/openjdk/%.o: $(openjdk-src)/%.c \ $(openjdk-headers-dep) @echo "compiling $(@)" @mkdir -p $(dir $(@)) + sed 's/^static jclass ia_class;//' < $(<) > $(build)/openjdk/$(notdir $(<)) $(cc) -fPIC $(openjdk-extra-cflags) $(openjdk-cflags) \ - $(optimization-cflags) -w -c $(<) $(call output,$(@)) + $(optimization-cflags) -w -c $(build)/openjdk/$(notdir $(<)) \ + $(call output,$(@)) $(openjdk-local-objects): $(build)/openjdk/%.o: $(src)/openjdk/%.c \ $(openjdk-headers-dep) @@ -843,6 +845,9 @@ ifeq ($(platform),windows) sed 's/^#ifdef _WIN64/#if 1/' \ < "$(openjdk-src)/windows/native/java/net/net_util_md.h" \ > $(build)/openjdk/net_util_md.h + cp "$(openjdk-src)/windows/native/java/net/NetworkInterface.h" \ + $(build)/openjdk/NetworkInterface.h + echo 'static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);' >> $(build)/openjdk/NetworkInterface.h endif @touch $(@) diff --git a/openjdk-src.mk b/openjdk-src.mk index df23e4772c..26d0c27644 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -221,6 +221,7 @@ ifeq ($(platform),windows) "-I$(openjdk-src)/windows/native/java/io" \ "-I$(openjdk-src)/windows/native/java/net" \ "-I$(openjdk-src)/windows/native/java/util" \ + "-I$(openjdk-src)/windows/native/sun/nio/ch" \ "-I$(openjdk-src)/windows/javavm/include" \ "-I$(root)/win32/include" \ -D_JNI_IMPLEMENTATION_ \ diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 9c115aaa2f..177dd077ef 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -54,6 +54,8 @@ typedef int socklen_t; +# define RTLD_DEFAULT 0 + #else // not PLATFORM_WINDOWS # include diff --git a/src/openjdk/caseSensitive/WS2tcpip.h b/src/openjdk/caseSensitive/WS2tcpip.h new file mode 100644 index 0000000000..5caab3e7f6 --- /dev/null +++ b/src/openjdk/caseSensitive/WS2tcpip.h @@ -0,0 +1 @@ +#include "ws2tcpip.h" From 3d56a3211d69025c3420a8d4518843c356ad1933 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 20:29:56 -0700 Subject: [PATCH 147/274] revert part of earlier comment involving setDaemon and runJavaThread The code added to runJavaThread was unecessary and harmful since it allowed the global daemon thread count to become permanently out-of-sync with the actual number of daemon threads. --- src/machine.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/machine.h b/src/machine.h index beeb84363e..bb57952fd2 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1756,10 +1756,6 @@ instanceOf(Thread* t, object class_, object o); inline void runJavaThread(Thread* t) { - if (threadDaemon(t, t->javaThread)) { - atomicOr(&(t->flags), Thread::DaemonFlag); - } - t->m->classpath->runThread(t); } From 768fc7cf7d2fecab6f0df3f6e81e6435fccdea60 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 1 Dec 2010 20:31:54 -0700 Subject: [PATCH 148/274] fix posix openjdk-src build --- openjdk-src.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openjdk-src.mk b/openjdk-src.mk index 26d0c27644..04edd8d73f 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -287,8 +287,10 @@ else openjdk-cflags += "-I$(openjdk-src)/solaris/javavm/export" \ "-I$(openjdk-src)/solaris/native/common" \ "-I$(openjdk-src)/solaris/native/java/io" \ + "-I$(openjdk-src)/solaris/native/java/lang" \ "-I$(openjdk-src)/solaris/native/java/net" \ "-I$(openjdk-src)/solaris/native/java/util" \ + "-I$(openjdk-src)/solaris/native/sun/nio/ch" \ "-I$(openjdk-src)/solaris/javavm/include" \ "-I$(openjdk-src)/solaris/hpi/include" endif From 0bd6822ed75d1627897c2a54f188bc18ccab286f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Dec 2010 13:42:13 -0700 Subject: [PATCH 149/274] fix PowerPC build --- src/compile-powerpc.S | 10 +++++----- src/compile.cpp | 8 +++++++- src/thunks.cpp | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index b732f893ea..b1cd0ba928 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,12 +24,12 @@ # define GLOBAL(x) x #endif -#define THREAD_STACK 2152 -#define THREAD_CONTINUATION 2156 +#define THREAD_STACK 2144 +#define THREAD_CONTINUATION 2148 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 -#define THREAD_EXCEPTION_OFFSET 2164 -#define THREAD_EXCEPTION_HANDLER 2168 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 +#define THREAD_EXCEPTION_OFFSET 2156 +#define THREAD_EXCEPTION_HANDLER 2160 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/compile.cpp b/src/compile.cpp index 53e31367f1..83c4532a47 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2662,6 +2662,12 @@ makeNew64(Thread* t, object class_) return reinterpret_cast(makeNew(t, class_)); } +uint64_t +getJClass64(Thread* t, object class_) +{ + return reinterpret_cast(getJClass(t, class_)); +} + void gcIfNecessary(MyThread* t) { @@ -4401,7 +4407,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, frame->pushObject (c->call (c->constant - (getThunk(t, getJClassThunk), Compiler::AddressType), + (getThunk(t, getJClass64Thunk), Compiler::AddressType), 0, frame->trace(0, 0), BytesPerWord, diff --git a/src/thunks.cpp b/src/thunks.cpp index 9de7aaf263..4d863ecca4 100644 --- a/src/thunks.cpp +++ b/src/thunks.cpp @@ -48,5 +48,5 @@ THUNK(instanceOf64) THUNK(makeNewGeneral64) THUNK(makeNew64) THUNK(set) -THUNK(getJClass) +THUNK(getJClass64) THUNK(gcIfNecessary) From c7b73e23ae13e5bea6e9919fa999f7e6826d83e6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 3 Dec 2010 18:24:19 -0700 Subject: [PATCH 150/274] protect classes in avian package from obfuscation --- vm.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/vm.pro b/vm.pro index 87e6f5fa03..edfd2e1679 100644 --- a/vm.pro +++ b/vm.pro @@ -76,6 +76,7 @@ # the VM references these classes by name, so protect them from obfuscation: -keepnames public class java.lang.** +-keepnames public class avian.** # Don't optimize calls to ResourceBundle -keep,allowshrinking,allowobfuscation public class java.util.ResourceBundle { From b1b433b63a0d1b95b06bda3b930e108aec8d7ed2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 17:37:13 -0700 Subject: [PATCH 151/274] remove debug code from GetMethodID --- src/jnienv.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index b315dac3ae..5f74c6dd9f 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -444,10 +444,7 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec) ENTER(t, Thread::ActiveState); object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) { - printTrace(t, t->exception); - return 0; - } + if (UNLIKELY(t->exception)) return 0; assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); From d19cab9ac91522a3ab0dee6e6e486652af21fbdc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 17:38:10 -0700 Subject: [PATCH 152/274] update readme.txt to cover OpenJDK and ARM support --- readme.txt | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/readme.txt b/readme.txt index 18cdf325dd..e826ba97e3 100644 --- a/readme.txt +++ b/readme.txt @@ -51,7 +51,7 @@ Supported Platforms Avian can currently target the following platforms: - Linux (i386 and x86_64) + Linux (i386, x86_64 and ARM) Windows (i386 and x86_64) Mac OS X (i386, x86_64 and 32-bit PowerPC) @@ -73,10 +73,17 @@ been tested. The build is directed by a single makefile and may be influenced via certain flags described below, all of which are optional. - $ make platform={linux,windows,darwin} arch={i386,x86_64,powerpc} \ - process={compile,interpret} mode={debug,debug-fast,fast,small} \ - bootimage={true,false} heapdump={true,false} tails={true,false} \ - continuations={true,false} + $ make \ + platform={linux,windows,darwin} \ + arch={i386,x86_64,powerpc,arm} \ + process={compile,interpret} \ + mode={debug,debug-fast,fast,small} \ + bootimage={true,false} \ + heapdump={true,false} \ + tails={true,false} \ + continuations={true,false} \ + openjdk= \ + openjdk-src= * platform - the target platform default: output of $(uname -s | tr [:upper:] [:lower:]), @@ -119,6 +126,18 @@ certain flags described below, all of which are optional. only valid for process=compile builds. default: false + * openjdk - if set, use OpenJDK class library instead of the default + Avian class library. See "Building with the OpenJDK Class + Library" below for details. + default: not set + + * openjdk-src - if this and the openjdk option above are both set, + build an embeddable VM using the OpenJDK class library. The JNI + components of the OpenJDK class library will be built from the + sources found under the specified directory. See "Building with + the OpenJDK Class Library" below for details. + default: not set + These flags determine the name of the directory used for the build. The name always starts with ${platform}-${arch}, and each non-default build option is appended to the name. For example, a debug build with @@ -291,7 +310,7 @@ Step 3: Make an object file out of the jar. Step 4: Write a driver which starts the VM and runs the desired main method. Note the bootJar function, which will be called by the VM to get a handle to the embedded jar. We tell the VM about this jar by -setting the classpath to "[bootJar]". +setting the boot classpath to "[bootJar]". $ cat >main.cpp <("-Djava.class.path=[bootJar]"); + options[0].optionString = const_cast("-Xbootclasspath:[bootJar]"); JavaVM* vm; void* env; From b5ae66b10f2b9da9e2747a3e858ec17e10073f41 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 17:40:18 -0700 Subject: [PATCH 153/274] update openjdk.pro to get avian-swt-examples working --- openjdk.pro | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/openjdk.pro b/openjdk.pro index 8067305599..96b9599fd6 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -20,6 +20,16 @@ protected ClassLoader(java.lang.ClassLoader); } +-keep class avian.SystemClassLoader { + protected java.net.URL findResource(java.lang.String); + } + +-keepnames class java.lang.ClassLoader { + public java.lang.Class loadClass(java.lang.String); + private static java.net.URL getBootstrapResource(java.lang.String); + private static java.util.Enumeration getBootstrapResources(java.lang.String); + } + -keep class java.util.Properties { public java.lang.Object setProperty(java.lang.String, java.lang.String); } @@ -50,6 +60,9 @@ # these class names are used to disambiguate JNI method lookups: +-keepnames public class java.net.URL +-keepnames public class java.util.Enumeration +-keepnames public class java.security.ProtectionDomain -keepnames public class java.security.PrivilegedAction -keepnames public class java.security.PrivilegedExceptionAction -keepnames public class java.security.AccessControlContext @@ -76,6 +89,15 @@ public byte[] getBytes(java.lang.String); } +-keepclassmembers class java.util.zip.Inflater { + long strm; + boolean needDict; + boolean finished; + byte[] buf; + int off; + int len; + } + -keepclassmembers class java.io.FileDescriptor { private int fd; } @@ -110,6 +132,8 @@ public static java.io.PrintStream err; # avoid inlining due to access check using fixed offset into call stack: static java.lang.Class getCallerClass(); + # called from jni_util.c: + static java.lang.String getProperty(java.lang.String); } # refered to by name from native code: @@ -133,3 +157,31 @@ long handle; private int jniVersion; } + +-keep class java.nio.charset.Charset { + # called from jni_util.c: + boolean isSupported(java.lang.String); + } + +# Charsets are loaded via reflection. If you need others besides +# UTF-8, you'll need to add them (e.g. sun.nio.cs.ISO_8859_1). +-keep class sun.nio.cs.UTF_8 + +# loaded reflectively to handle embedded resources: +-keep class avian.resource.Handler + +# refered to symbolically in MethodAccessorGenerator: +-keep class sun.reflect.MethodAccessorImpl { + ; + } +-keep class sun.reflect.ConstructorAccessorImpl { + ; + } +-keep class sun.reflect.SerializationConstructorAccessorImpl { + ; + } + +# refered to by name in LocaleData to load resources: +-keep class sun.util.resources.CalendarData +-keep class sun.text.resources.FormatData + From 1271678d413b9645c1993c1ed4fcfee42c8dfb63 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 17:40:50 -0700 Subject: [PATCH 154/274] various fixes for embedded resource loading in OpenJDK build --- classpath/avian/SystemClassLoader.java | 13 ++++++ classpath/java/lang/ClassLoader.java | 4 ++ makefile | 11 +++-- src/boot.cpp | 26 ------------ src/classpath-openjdk.cpp | 58 ++++++++++++++++++++++---- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index 3054afe15a..d9e53604b0 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -12,6 +12,10 @@ package avian; import java.net.URL; import java.net.MalformedURLException; +import java.util.Collection; +import java.util.Collections; +import java.util.ArrayList; +import java.util.Enumeration; public class SystemClassLoader extends ClassLoader { private native VMClass findVMClass(String name) @@ -40,4 +44,13 @@ public class SystemClassLoader extends ClassLoader { } return null; } + + protected Enumeration findResources(String name) { + Collection urls = new ArrayList(1); + URL url = findResource(name); + if (url != null) { + urls.add(url); + } + return Collections.enumeration(urls); + } } diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index dbd376b62f..54b7a723b7 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -99,6 +99,10 @@ public abstract class ClassLoader { return null; } + protected Enumeration findResources(String name) throws IOException { + return Collections.enumeration(new ArrayList(0)); + } + public URL getResource(String path) { URL url = null; if (parent != null) { diff --git a/makefile b/makefile index 200d132d71..8b8a1593d3 100644 --- a/makefile +++ b/makefile @@ -93,6 +93,7 @@ ifneq ($(openjdk),) javahome-files += lib/currency.data endif javahome-object = $(build)/javahome-jar.o + boot-javahome-object = $(build)/boot-javahome.o else options := $(options)-openjdk test-executable = $(executable-dynamic) @@ -673,6 +674,9 @@ $(build)/main-dynamic.o: $(driver-source) $(boot-object): $(boot-source) $(compile-object) +$(boot-javahome-object): $(src)/boot-javahome.cpp + $(compile-object) + $(build)/binaryToObject-main.o: $(src)/binaryToObject/main.cpp $(build-cxx) -c $(^) -o $(@) @@ -726,7 +730,8 @@ $(generator-objects): $(build)/%-build.o: $(src)/%.cpp $(jni-objects): $(build)/%.o: $(classpath-src)/%.cpp $(compile-object) -$(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) +$(static-library): $(vm-objects) $(classpath-objects) $(vm-heapwalk-objects) \ + $(javahome-object) $(boot-javahome-object) @echo "creating $(@)" rm -rf $(@) $(ar) cru $(@) $(^) @@ -743,7 +748,7 @@ $(bootimage-object): $(bootimage-bin) $(converter) executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ - $(javahome-object) + $(javahome-object) $(boot-javahome-object) $(executable): $(executable-objects) @echo "linking $(@)" @@ -792,7 +797,7 @@ endif $(dynamic-library): $(vm-objects) $(dynamic-object) $(classpath-objects) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-object) \ - $(classpath-libraries) $(javahome-object) + $(classpath-libraries) $(javahome-object) $(boot-javahome-object) @echo "linking $(@)" ifdef msvc $(ld) $(shared) $(lflags) $(^) -out:$(@) -PDB:$(@).pdb \ diff --git a/src/boot.cpp b/src/boot.cpp index f6a1cd8d20..e677b81bde 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -81,29 +81,3 @@ extern "C" { #undef SYMBOL #endif//BOOT_CLASSPATH - -#ifdef BOOT_JAVAHOME - -#if (defined __MINGW32__) || (defined _MSC_VER) -# define SYMBOL(x) binary_javahome_jar_##x -#else -# define SYMBOL(x) _binary_javahome_jar_##x -#endif - -extern "C" { - - extern const uint8_t SYMBOL(start)[]; - extern const uint8_t SYMBOL(end)[]; - - EXPORT const uint8_t* - javahomeJar(unsigned* size) - { - *size = SYMBOL(end) - SYMBOL(start); - return SYMBOL(start); - } - -} - -#undef SYMBOL - -#endif//BOOT_JAVAHOME diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 177dd077ef..d1986e6125 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -380,6 +380,10 @@ class MyClasspath : public Classpath { { globalMachine = t->m; + resolveSystemClass(t, root(t, Machine::BootLoader), + className(t, type(t, Machine::ClassLoaderType))); + if (UNLIKELY(t->exception)) return; + #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t); if (UNLIKELY(t->exception)) return; @@ -391,10 +395,6 @@ class MyClasspath : public Classpath { } #endif // not AVIAN_OPENJDK_SRC - resolveSystemClass(t, root(t, Machine::BootLoader), - className(t, type(t, Machine::ClassLoaderType))); - if (UNLIKELY(t->exception)) return; - object constructor = resolveMethod (t, type(t, Machine::ClassLoaderType), "", "(Ljava/lang/ClassLoader;)V"); @@ -694,7 +694,7 @@ checkFileAccess } int64_t JNICALL -getLength +getFileLength (Thread* t, object method, uintptr_t* arguments) { MyClasspath* cp = static_cast(t->m->classpath); @@ -1012,13 +1012,49 @@ closeFile(Thread* t, object method, uintptr_t* arguments) } } +int64_t JNICALL +getBootstrapResource(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + object m = findMethodOrNull + (t, type(t, Machine::SystemClassLoaderType), + "findResource", "(Ljava/lang/String;)Ljava/net/URL;"); + + if (m) { + return reinterpret_cast + (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); + } else { + return 0; + } +} + +int64_t JNICALL +getBootstrapResources(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + PROTECT(t, name); + + object m = findMethodOrNull + (t, type(t, Machine::SystemClassLoaderType), + "findResources", "(Ljava/lang/String;)Ljava/util/Enumeration;"); + + if (m) { + return reinterpret_cast + (t->m->processor->invoke(t, m, root(t, Machine::BootLoader), name)); + } else { + return 0; + } +} + // only safe to call during bootstrap when there's only one thread // running: void intercept(Thread* t, object c, const char* name, const char* spec, void* function) { - object m = findMethodOrNull(t, c, name, spec); + object m = findMethodOrNull(t, c, name, spec); if (m) { PROTECT(t, m); @@ -1121,8 +1157,16 @@ interceptFileOperations(Thread* t) voidPointer(checkFileAccess)); intercept(t, fsClass, "getLength", "(Ljava/io/File;)J", - voidPointer(getLength)); + voidPointer(getFileLength)); } + + intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource", + "(Ljava/lang/String;)Ljava/net/URL;", + voidPointer(getBootstrapResource)); + + intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResources", + "(Ljava/lang/String;)Ljava/util/Enumeration;", + voidPointer(getBootstrapResources)); } unsigned From ceae61a6a8b3f7d903dffbee126be83b4368777f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 18:01:38 -0700 Subject: [PATCH 155/274] fix misspelling in openjdk.pro --- openjdk.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openjdk.pro b/openjdk.pro index 96b9599fd6..f2cf30abc4 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -181,7 +181,7 @@ ; } -# refered to by name in LocaleData to load resources: +# referred to by name in LocaleData to load resources: -keep class sun.util.resources.CalendarData -keep class sun.text.resources.FormatData From 019e032f4f421bd86116230da1cf456ce73f8975 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 18:04:25 -0700 Subject: [PATCH 156/274] add boot-javahome.cpp This should have been included in an earlier commit. --- src/boot-javahome.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/boot-javahome.cpp diff --git a/src/boot-javahome.cpp b/src/boot-javahome.cpp new file mode 100644 index 0000000000..8f32d545c7 --- /dev/null +++ b/src/boot-javahome.cpp @@ -0,0 +1,45 @@ +/* Copyright (c) 2010, 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. */ + +#ifdef _MSC_VER + +typedef unsigned char uint8_t; + +#else +# include "stdint.h" +#endif + +#ifdef BOOT_JAVAHOME + +#if (defined __MINGW32__) || (defined _MSC_VER) +# define EXPORT __declspec(dllexport) +# define SYMBOL(x) binary_javahome_jar_##x +#else +# define EXPORT __attribute__ ((visibility("default"))) +# define SYMBOL(x) _binary_javahome_jar_##x +#endif + +extern "C" { + + extern const uint8_t SYMBOL(start)[]; + extern const uint8_t SYMBOL(end)[]; + + EXPORT const uint8_t* + javahomeJar(unsigned* size) + { + *size = SYMBOL(end) - SYMBOL(start); + return SYMBOL(start); + } + +} + +#undef SYMBOL + +#endif//BOOT_JAVAHOME From 800463bb450c2aeb8fb3918f5678dda80e78bf34 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 18:56:19 -0700 Subject: [PATCH 157/274] clarify Continuations.java JavaDoc comment --- classpath/avian/Continuations.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 42565830d4..359262feac 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -53,8 +53,8 @@ import java.util.concurrent.Callable; * causes the current continuation to be replaced with the calling * continuation. When the last method in this new continuation * returns, it returns to the native frame which created the current - * context, which may not be the same as the context in which that - * continuation was created. + * context, which may or may not be the same as the context in which + * that continuation was created. * *

We define the return type of a continuation context as the * return type of the first method called in that context. A From a2f14dce6faa437369aff4519a24a5f8522af497 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 20:20:48 -0700 Subject: [PATCH 158/274] increment version number to 0.4 --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 8b8a1593d3..393afb7123 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ MAKEFLAGS = -s name = avian -version = 0.3 +version = 0.4 build-arch := $(shell uname -m | sed 's/^i.86$$/i386/' | sed 's/^arm.*$$/arm/') ifeq (Power,$(filter Power,$(build-arch))) From a5742f5985fff61464449520868ac32ad4ebef26 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 20:21:09 -0700 Subject: [PATCH 159/274] update copyright years --- classpath/avian/Addendum.java | 2 +- classpath/avian/ClassAddendum.java | 2 +- classpath/avian/Continuations.java | 2 +- classpath/avian/PersistentSet.java | 2 +- classpath/avian/SystemClassLoader.java | 2 +- classpath/avian/resource/Handler.java | 2 +- classpath/java-io.cpp | 2 +- classpath/java-lang.cpp | 2 +- classpath/java-nio.cpp | 2 +- classpath/java/io/BufferedInputStream.java | 2 +- classpath/java/io/File.java | 2 +- classpath/java/io/FileInputStream.java | 2 +- classpath/java/io/FileOutputStream.java | 2 +- classpath/java/io/InputStreamReader.java | 2 +- classpath/java/io/ObjectInputStream.java | 2 +- classpath/java/io/ObjectOutputStream.java | 2 +- classpath/java/io/OutputStreamWriter.java | 2 +- classpath/java/lang/Class.java | 2 +- classpath/java/lang/ClassLoader.java | 2 +- classpath/java/lang/Enum.java | 2 +- classpath/java/lang/Long.java | 2 +- classpath/java/lang/Object.java | 2 +- classpath/java/lang/OutOfMemoryError.java | 2 +- classpath/java/lang/Runtime.java | 2 +- classpath/java/lang/StackTraceElement.java | 2 +- classpath/java/lang/String.java | 2 +- classpath/java/lang/System.java | 2 +- classpath/java/lang/Thread.java | 2 +- classpath/java/lang/ThreadGroup.java | 2 +- classpath/java/lang/ref/ReferenceQueue.java | 2 +- classpath/java/lang/reflect/Constructor.java | 2 +- classpath/java/lang/reflect/Field.java | 2 +- classpath/java/lang/reflect/Method.java | 2 +- classpath/java/lang/reflect/Proxy.java | 2 +- classpath/java/net/Socket.java | 2 +- classpath/java/nio/channels/SelectableChannel.java | 2 +- classpath/java/nio/channels/Selector.java | 2 +- classpath/java/nio/channels/ServerSocketChannel.java | 2 +- classpath/java/nio/channels/SocketChannel.java | 2 +- classpath/java/nio/channels/SocketSelector.java | 2 +- classpath/java/security/AllPermission.java | 2 +- classpath/java/security/Permission.java | 2 +- classpath/java/util/Arrays.java | 2 +- classpath/java/util/Collections.java | 2 +- classpath/java/util/HashMap.java | 2 +- classpath/java/util/Map.java | 2 +- classpath/java/util/Properties.java | 2 +- classpath/java/util/ResourceBundle.java | 2 +- classpath/java/util/TreeMap.java | 2 +- classpath/java/util/WeakHashMap.java | 2 +- classpath/java/util/logging/Logger.java | 2 +- classpath/java/util/regex/Pattern.java | 2 +- classpath/java/util/zip/InflaterInputStream.java | 2 +- license.txt | 2 +- src/arch.h | 2 +- src/arm.S | 2 +- src/arm.h | 2 +- src/assembler.h | 2 +- src/binaryToObject/elf.cpp | 2 +- src/binaryToObject/mach-o.cpp | 2 +- src/boot.cpp | 2 +- src/bootimage.cpp | 2 +- src/bootimage.h | 2 +- src/builtin.cpp | 2 +- src/common.h | 2 +- src/compile-powerpc.S | 2 +- src/compile-x86.S | 2 +- src/compile.cpp | 2 +- src/compiler.cpp | 2 +- src/compiler.h | 2 +- src/continuations-x86.S | 2 +- src/finder.cpp | 2 +- src/heap.cpp | 2 +- src/heap.h | 2 +- src/heapdump.cpp | 2 +- src/interpret.cpp | 2 +- src/jnienv.cpp | 2 +- src/machine.cpp | 2 +- src/machine.h | 2 +- src/main.cpp | 2 +- src/posix.cpp | 2 +- src/powerpc.cpp | 2 +- src/powerpc.h | 2 +- src/process.cpp | 2 +- src/process.h | 2 +- src/processor.h | 2 +- src/system.h | 2 +- src/type-generator.cpp | 2 +- src/util.cpp | 2 +- src/util.h | 2 +- src/windows.cpp | 2 +- src/x86.cpp | 2 +- src/x86.h | 2 +- 93 files changed, 93 insertions(+), 93 deletions(-) diff --git a/classpath/avian/Addendum.java b/classpath/avian/Addendum.java index 433b81e3c3..248ee68ec1 100644 --- a/classpath/avian/Addendum.java +++ b/classpath/avian/Addendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/ClassAddendum.java b/classpath/avian/ClassAddendum.java index adc45bbeb3..4382e7f717 100644 --- a/classpath/avian/ClassAddendum.java +++ b/classpath/avian/ClassAddendum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index 359262feac..387ebd31ac 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/PersistentSet.java b/classpath/avian/PersistentSet.java index c5efdad641..5683327aee 100644 --- a/classpath/avian/PersistentSet.java +++ b/classpath/avian/PersistentSet.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/SystemClassLoader.java b/classpath/avian/SystemClassLoader.java index d9e53604b0..6edd8b7a68 100644 --- a/classpath/avian/SystemClassLoader.java +++ b/classpath/avian/SystemClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/avian/resource/Handler.java b/classpath/avian/resource/Handler.java index 00068e0795..51e8d1a838 100644 --- a/classpath/avian/resource/Handler.java +++ b/classpath/avian/resource/Handler.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index f134d6dc0c..06dd0cc375 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 81fcd6c1c2..5c023242cd 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 25d2d673b0..2e5d37bb1a 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index 778523d507..b20309fd51 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index 86ef77c6a3..3c97db5e4a 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java index 4c0d576368..9c614e2f7e 100644 --- a/classpath/java/io/FileInputStream.java +++ b/classpath/java/io/FileInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java index 5a485e04f3..60190e0757 100644 --- a/classpath/java/io/FileOutputStream.java +++ b/classpath/java/io/FileOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/InputStreamReader.java b/classpath/java/io/InputStreamReader.java index a2049b1b62..98f145cd92 100644 --- a/classpath/java/io/InputStreamReader.java +++ b/classpath/java/io/InputStreamReader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 8447e10efa..20fa5cdfb8 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 90743a5b32..80cac7857b 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/io/OutputStreamWriter.java b/classpath/java/io/OutputStreamWriter.java index 1c94a774ac..3cd061f9b4 100644 --- a/classpath/java/io/OutputStreamWriter.java +++ b/classpath/java/io/OutputStreamWriter.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Class.java b/classpath/java/lang/Class.java index 1a6ea4a382..b550ae5509 100644 --- a/classpath/java/lang/Class.java +++ b/classpath/java/lang/Class.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 54b7a723b7..5dc6505877 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Enum.java b/classpath/java/lang/Enum.java index b1920ac31d..e09bd73c2c 100644 --- a/classpath/java/lang/Enum.java +++ b/classpath/java/lang/Enum.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Long.java b/classpath/java/lang/Long.java index c7c9767380..033ca8b111 100644 --- a/classpath/java/lang/Long.java +++ b/classpath/java/lang/Long.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Object.java b/classpath/java/lang/Object.java index 24e6d2dd4b..6a0a00937b 100644 --- a/classpath/java/lang/Object.java +++ b/classpath/java/lang/Object.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/OutOfMemoryError.java b/classpath/java/lang/OutOfMemoryError.java index 977da303e3..138897399c 100644 --- a/classpath/java/lang/OutOfMemoryError.java +++ b/classpath/java/lang/OutOfMemoryError.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Runtime.java b/classpath/java/lang/Runtime.java index 55f16cd456..30dc0b6612 100644 --- a/classpath/java/lang/Runtime.java +++ b/classpath/java/lang/Runtime.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/StackTraceElement.java b/classpath/java/lang/StackTraceElement.java index 9b933412e9..87dd6d7897 100644 --- a/classpath/java/lang/StackTraceElement.java +++ b/classpath/java/lang/StackTraceElement.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 8624690f5b..788400dbac 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index c060493e7c..954c62d116 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 6e8ea0cae4..0606f51377 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/ThreadGroup.java b/classpath/java/lang/ThreadGroup.java index 95ad3383b1..a08c73f9ec 100644 --- a/classpath/java/lang/ThreadGroup.java +++ b/classpath/java/lang/ThreadGroup.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/ref/ReferenceQueue.java b/classpath/java/lang/ref/ReferenceQueue.java index 068a5bfbc1..8650f15d6e 100644 --- a/classpath/java/lang/ref/ReferenceQueue.java +++ b/classpath/java/lang/ref/ReferenceQueue.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java index 7c52df5955..908e84b452 100644 --- a/classpath/java/lang/reflect/Constructor.java +++ b/classpath/java/lang/reflect/Constructor.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java index 038ccea54b..4638c61990 100644 --- a/classpath/java/lang/reflect/Field.java +++ b/classpath/java/lang/reflect/Field.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java index b97b648070..2c0addfaae 100644 --- a/classpath/java/lang/reflect/Method.java +++ b/classpath/java/lang/reflect/Method.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index 804450f123..27fc88582d 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/net/Socket.java b/classpath/java/net/Socket.java index 9fbc1e4523..0f3a39ea6e 100644 --- a/classpath/java/net/Socket.java +++ b/classpath/java/net/Socket.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index 7cec3b69aa..a8dc302dc7 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/Selector.java b/classpath/java/nio/channels/Selector.java index 942357c773..f3be166d8b 100644 --- a/classpath/java/nio/channels/Selector.java +++ b/classpath/java/nio/channels/Selector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 61dfe60559..7aa806886c 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index db20896f1c..4dbc352558 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/nio/channels/SocketSelector.java b/classpath/java/nio/channels/SocketSelector.java index 8ad7bbafd8..27daf2670b 100644 --- a/classpath/java/nio/channels/SocketSelector.java +++ b/classpath/java/nio/channels/SocketSelector.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/security/AllPermission.java b/classpath/java/security/AllPermission.java index b35004f609..4a18ebbddf 100644 --- a/classpath/java/security/AllPermission.java +++ b/classpath/java/security/AllPermission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/security/Permission.java b/classpath/java/security/Permission.java index 528795a127..f622253976 100644 --- a/classpath/java/security/Permission.java +++ b/classpath/java/security/Permission.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index cf05144d7d..dc607189d9 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index eb7c5d462c..050c1ebb02 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index e767b166d8..2931b52300 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Map.java b/classpath/java/util/Map.java index cd20bbc809..36f79a07f1 100644 --- a/classpath/java/util/Map.java +++ b/classpath/java/util/Map.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 1ff67dcf16..b71caa14ee 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/ResourceBundle.java b/classpath/java/util/ResourceBundle.java index 4dc52443f6..a07d693af4 100644 --- a/classpath/java/util/ResourceBundle.java +++ b/classpath/java/util/ResourceBundle.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java index b3141422cd..6100dbce80 100644 --- a/classpath/java/util/TreeMap.java +++ b/classpath/java/util/TreeMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/WeakHashMap.java b/classpath/java/util/WeakHashMap.java index 81365b9816..862de6e7e1 100644 --- a/classpath/java/util/WeakHashMap.java +++ b/classpath/java/util/WeakHashMap.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/logging/Logger.java b/classpath/java/util/logging/Logger.java index ed2a8ce4d6..a1a64de307 100644 --- a/classpath/java/util/logging/Logger.java +++ b/classpath/java/util/logging/Logger.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index c9827c1f70..bb9a6e26f8 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/classpath/java/util/zip/InflaterInputStream.java b/classpath/java/util/zip/InflaterInputStream.java index 1548c7eff4..a8cbeca173 100644 --- a/classpath/java/util/zip/InflaterInputStream.java +++ b/classpath/java/util/zip/InflaterInputStream.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/license.txt b/license.txt index 3596960926..6e84838c86 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008-2009, Avian Contributors +Copyright (c) 2008-2010, 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 diff --git a/src/arch.h b/src/arch.h index a49cf5078f..f06dcef0f9 100644 --- a/src/arch.h +++ b/src/arch.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/arm.S b/src/arm.S index fe068824b0..6536017d60 100644 --- a/src/arm.S +++ b/src/arm.S @@ -1,5 +1,5 @@ /* arm.S: JNI gluecode for ARM/Linux - Copyright (c) 2008-2009, Avian Contributors + Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/arm.h b/src/arm.h index f510d3e960..0c5c5cc2e5 100644 --- a/src/arm.h +++ b/src/arm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/assembler.h b/src/assembler.h index 70002768ca..1752de74f2 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 2e58f08e27..8af5c0cd58 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index 527130a8db..d832703200 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/boot.cpp b/src/boot.cpp index e677b81bde..1535584ace 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/bootimage.cpp b/src/bootimage.cpp index cda4abd2a0..d19bbf81df 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/bootimage.h b/src/bootimage.h index ada3ce41d9..14e436ba3d 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/builtin.cpp b/src/builtin.cpp index 55b4c3f02a..3c0365ea7b 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/common.h b/src/common.h index 7cf95a85e3..57dea834ef 100644 --- a/src/common.h +++ b/src/common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index b1cd0ba928..d0cf0e14f4 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/compile-x86.S b/src/compile-x86.S index 7dd9349f40..07da66ae3f 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/compile.cpp b/src/compile.cpp index 83c4532a47..3bafb38eff 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/compiler.cpp b/src/compiler.cpp index f82c7a48a2..7610d5a79d 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/compiler.h b/src/compiler.h index d4484c719e..e0c94b1b2d 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/continuations-x86.S b/src/continuations-x86.S index c55679d0ba..f0688a9e51 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/finder.cpp b/src/finder.cpp index 519f1efa6d..543c45e312 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/heap.cpp b/src/heap.cpp index 02211204b2..f8969caa98 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/heap.h b/src/heap.h index 6b392a1de6..a045fd9526 100644 --- a/src/heap.h +++ b/src/heap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/heapdump.cpp b/src/heapdump.cpp index 100a3c7b3d..2f70e80c5f 100644 --- a/src/heapdump.cpp +++ b/src/heapdump.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/interpret.cpp b/src/interpret.cpp index 530af13b44..1634463ea1 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5f74c6dd9f..7579b9891e 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/machine.cpp b/src/machine.cpp index 73ceca8032..ec1c06ae61 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/machine.h b/src/machine.h index bb57952fd2..4c65230095 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/main.cpp b/src/main.cpp index bafca2a515..8cdb435dd0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/posix.cpp b/src/posix.cpp index 2339b666dc..b4b833cb62 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/powerpc.cpp b/src/powerpc.cpp index ce8a6bbb4b..ff83fbe807 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Avian Contributors +/* Copyright (c) 2009-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/powerpc.h b/src/powerpc.h index d252039b89..c5bf0613b5 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/process.cpp b/src/process.cpp index e4835592a7..cab5fb8b4f 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/process.h b/src/process.h index 2405734657..27f7788a6b 100644 --- a/src/process.h +++ b/src/process.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/processor.h b/src/processor.h index ee3983f01c..0b71ed1782 100644 --- a/src/processor.h +++ b/src/processor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/system.h b/src/system.h index 5cf7211ab9..95e025f433 100644 --- a/src/system.h +++ b/src/system.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/type-generator.cpp b/src/type-generator.cpp index a0ae158816..aed82c3f35 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/util.cpp b/src/util.cpp index 0e9bd6d4b7..511389ade8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/util.h b/src/util.h index ecd9a54a6b..40a70b5bfb 100644 --- a/src/util.h +++ b/src/util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/windows.cpp b/src/windows.cpp index 8b93f96e5c..52c95f2bd0 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/x86.cpp b/src/x86.cpp index 65ac67ce30..2501ac754c 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided diff --git a/src/x86.h b/src/x86.h index f5602b8015..a125e4425c 100644 --- a/src/x86.h +++ b/src/x86.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2009, Avian Contributors +/* Copyright (c) 2008-2010, Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided From d408040b2c4a0da2a118e91d0df562519f9c96c3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 5 Dec 2010 20:39:17 -0700 Subject: [PATCH 160/274] add trademark notice to readme.txt and specify Proguard 4.6 in example --- readme.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index e826ba97e3..6a611da785 100644 --- a/readme.txt +++ b/readme.txt @@ -486,7 +486,7 @@ EOF Step 5: Run ProGuard with stage1 as input and stage2 as output. - $ java -jar ../../proguard4.4/lib/proguard.jar \ + $ java -jar ../../proguard4.6/lib/proguard.jar \ -injars stage1 -outjars stage2 @../vm.pro @hello.pro (note: pass -dontusemixedcaseclassnames to ProGuard when building on @@ -596,3 +596,12 @@ executable, and optionally strip its symbols. $ g++ -rdynamic *.o -ldl -lpthread -lz -o hello $ strip --strip-all hello + + +Trademarks +---------- + +Oracle and Java are registered trademarks of Oracle and/or its +affiliates. Other names may be trademarks of their respective owners. + +The Avian project is not affiliated with Oracle. From 61fe7efd6d7eccf842cb9e3b9865b842a76f0df3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Dec 2010 09:33:07 -0700 Subject: [PATCH 161/274] specify -mmacosx-version-min=10.4 for 32-bit OS X builds --- makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/makefile b/makefile index 393afb7123..ef5fb8b04e 100644 --- a/makefile +++ b/makefile @@ -225,20 +225,20 @@ ifeq ($(platform),darwin) ifneq (,$(filter i386 x86_64,$(build-arch))) converter-cflags += -DOPPOSITE_ENDIAN endif - openjdk-extra-cflags += -arch ppc - cflags += -arch ppc - asmflags += -arch ppc - lflags += -arch ppc + openjdk-extra-cflags += -arch ppc -mmacosx-version-min=10.4 + cflags += -arch ppc -mmacosx-version-min=10.4 + asmflags += -arch ppc -mmacosx-version-min=10.4 + lflags += -arch ppc -mmacosx-version-min=10.4 endif ifeq ($(arch),i386) ifeq ($(build-arch),powerpc) converter-cflags += -DOPPOSITE_ENDIAN endif - openjdk-extra-cflags += -arch i386 - cflags += -arch i386 - asmflags += -arch i386 - lflags += -arch i386 + openjdk-extra-cflags += -arch i386 -mmacosx-version-min=10.4 + cflags += -arch i386 -mmacosx-version-min=10.4 + asmflags += -arch i386 -mmacosx-version-min=10.4 + lflags += -arch i386 -mmacosx-version-min=10.4 endif ifeq ($(arch),x86_64) From 378f7086b7099bf4b46c7af5f979545a7565693f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Dec 2010 15:57:11 -0700 Subject: [PATCH 162/274] fix return address code offset calculation on ARM We have to be careful about how we calculate return addresses on ARM due to padding introduced by constant pools interspersed with code. When calculating the offset of code where we're inserting a constant pool, we want the offset of the end of the pool for jump targets, but we want the offset just prior to the beginning of the pool (i.e. the offset of the instruction responsible for jumping past the pool) when calculating a return address. --- src/arm.cpp | 15 ++++++++------- src/assembler.h | 2 +- src/compiler.cpp | 5 +++-- src/powerpc.cpp | 2 +- src/x86.cpp | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 46e87a3b23..3d858e9e4d 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -320,8 +320,8 @@ expect(Context* c, bool v) class Offset: public Promise { public: - Offset(Context* c, MyBlock* block, unsigned offset): - c(c), block(block), offset(offset) + Offset(Context* c, MyBlock* block, unsigned offset, bool forTrace): + c(c), block(block), offset(offset), forTrace(forTrace) { } virtual bool resolved() { @@ -332,19 +332,20 @@ class Offset: public Promise { assert(c, resolved()); unsigned o = offset - block->offset; - return block->start + padding(block, o) + o; + return block->start + padding(block, forTrace ? o - BytesPerWord : o) + o; } Context* c; MyBlock* block; unsigned offset; + bool forTrace; }; Promise* -offset(Context* c) +offset(Context* c, bool forTrace = false) { return new (c->zone->allocate(sizeof(Offset))) - Offset(c, c->lastBlock, c->code.length()); + Offset(c, c->lastBlock, c->code.length(), forTrace); } bool @@ -2271,8 +2272,8 @@ class MyAssembler: public Assembler { } } - virtual Promise* offset() { - return ::offset(&c); + virtual Promise* offset(bool forTrace) { + return ::offset(&c, forTrace); } virtual Block* endBlock(bool startNew) { diff --git a/src/assembler.h b/src/assembler.h index 1752de74f2..4c5f67b1a9 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -414,7 +414,7 @@ class Assembler { virtual void writeTo(uint8_t* dst) = 0; - virtual Promise* offset() = 0; + virtual Promise* offset(bool forTrace = false) = 0; virtual Block* endBlock(bool startNew) = 0; diff --git a/src/compiler.cpp b/src/compiler.cpp index 7610d5a79d..b6cf197157 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -3098,7 +3098,8 @@ codePromise(Context* c, Event* e) CodePromise* codePromise(Context* c, Promise* offset) { - return new (c->zone->allocate(sizeof(CodePromise))) CodePromise(c, offset); + return new (c->zone->allocate(sizeof(CodePromise))) + CodePromise(c, offset); } void @@ -3357,7 +3358,7 @@ class CallEvent: public Event { apply(c, op, BytesPerWord, address->source, address->source); if (traceHandler) { - traceHandler->handleTrace(codePromise(c, c->assembler->offset()), + traceHandler->handleTrace(codePromise(c, c->assembler->offset(true)), stackArgumentIndex); } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index ff83fbe807..9973ccc544 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2377,7 +2377,7 @@ class MyAssembler: public Assembler { } } - virtual Promise* offset() { + virtual Promise* offset(bool) { return ::offset(&c); } diff --git a/src/x86.cpp b/src/x86.cpp index 2501ac754c..4c11e8adfe 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3536,7 +3536,7 @@ class MyAssembler: public Assembler { } } - virtual Promise* offset() { + virtual Promise* offset(bool) { return local::offset(&c); } From 314bdae80da0f3f1a3ecc4687f9e4f40a559ecd1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Dec 2010 18:16:19 -0700 Subject: [PATCH 163/274] freeze BranchEvent operands to ensure they aren't clobbered as temporaries --- src/compiler.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index b6cf197157..23778520d6 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4747,9 +4747,17 @@ class BranchEvent: public Event { apply(c, Jump, BytesPerWord, address->source, address->source); } } else { + freezeSource(c, size, first); + freezeSource(c, size, second); + freezeSource(c, BytesPerWord, address); + apply(c, type, size, first->source, first->nextWord->source, size, second->source, second->nextWord->source, BytesPerWord, address->source, address->source); + + thawSource(c, BytesPerWord, address); + thawSource(c, size, second); + thawSource(c, size, first); } } @@ -4914,13 +4922,13 @@ class BoundsCheckEvent: public Event { CodePromise* nextPromise = codePromise (c, static_cast(0)); - index->source->freeze(c, index); + freezeSource(c, BytesPerWord, index); ConstantSite next(nextPromise); apply(c, JumpIfGreater, 4, index->source, index->source, 4, &length, &length, BytesPerWord, &next, &next); - index->source->thaw(c, index); + thawSource(c, BytesPerWord, index); if (constant == 0) { outOfBoundsPromise->offset = a->offset(); From 544cebb7f00a0ad91d3509a423cab81efb2420b8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 7 Dec 2010 18:17:41 -0700 Subject: [PATCH 164/274] use MyBlock::start when computing constant pool offsets, not MyBlock::offset --- src/arm.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 3d858e9e4d..bac3bc10a0 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -701,12 +701,16 @@ resolve(MyBlock* b) if (b->next == 0 or b->next->poolEventHead) { append = true; } else { - int32_t v = (b->offset + b->size + b->next->size + BytesPerWord - 8) - - (c->poolOffsetHead->offset + c->poolOffsetHead->block->offset); + int32_t v = (b->start + b->size + b->next->size + BytesPerWord - 8) + - (c->poolOffsetHead->offset + c->poolOffsetHead->block->start); append = (v != (v & PoolOffsetMask)); if (DebugPool) { + fprintf(stderr, + "current %p %d %d next %p %d %d\n", + b, b->start, b->size, b->next, b->start + b->size, + b->next->size); fprintf(stderr, "offset %p %d is of distance %d to next block; append? %d\n", c->poolOffsetHead, c->poolOffsetHead->offset, v, append); @@ -714,6 +718,13 @@ resolve(MyBlock* b) } if (append) { +#ifndef NDEBUG + int32_t v = (b->start + b->size - 8) + - (c->poolOffsetHead->offset + c->poolOffsetHead->block->start); + + expect(c, v == (v & PoolOffsetMask)); +#endif // not NDEBUG + appendPoolEvent(c, b, b->size, c->poolOffsetHead, c->poolOffsetTail); if (DebugPool) { From bc2b4802ec81cc0ac4ace401887c98b828366dd8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 8 Dec 2010 21:36:02 -0700 Subject: [PATCH 165/274] add todo comment to classpath-common.h --- src/classpath-common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/classpath-common.h b/src/classpath-common.h index 45b93850ed..3ca61210a0 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -172,6 +172,8 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, // library is built in to this executable if (runOnLoad and not t->m->triedBuiltinOnLoad) { t->m->triedBuiltinOnLoad = true; + // todo: release the classLock before calling this to + // avoid the possibility of deadlock: runOnLoadIfFound(t, t->m->libraries); } return t->m->libraries; From d381ece44be06ce2b27d15cee5605fbb5130f27a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 8 Dec 2010 21:38:16 -0700 Subject: [PATCH 166/274] rework loadLibrary interception to handle builtins properly --- src/classpath-openjdk.cpp | 215 ++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 115 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index d1986e6125..eda7ac90de 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -174,7 +174,7 @@ class MyClasspath : public Classpath { MyClasspath(System* s, Allocator* allocator, const char* javaHome, const char* embedPrefix): - allocator(allocator) + allocator(allocator), ranNetOnLoad(0) { class StringBuilder { public: @@ -239,30 +239,6 @@ class MyClasspath : public Classpath { #endif sb.append('\0'); - this->zipLibrary = sb.pointer; - sb.append(this->libraryPath); - sb.append("/"); - sb.append(SO_PREFIX); - sb.append("zip"); - sb.append(SO_SUFFIX); - sb.append('\0'); - - this->netLibrary = sb.pointer; - sb.append(this->libraryPath); - sb.append("/"); - sb.append(SO_PREFIX); - sb.append("net"); - sb.append(SO_SUFFIX); - sb.append('\0'); - - this->nioLibrary = sb.pointer; - sb.append(this->libraryPath); - sb.append("/"); - sb.append(SO_PREFIX); - sb.append("nio"); - sb.append(SO_SUFFIX); - sb.append('\0'); - this->tzMappings = sb.pointer; sb.append(javaHome); sb.append("/lib/tzmappings"); @@ -445,9 +421,6 @@ class MyClasspath : public Classpath { const char* javaHome; const char* classpath; const char* libraryPath; - const char* zipLibrary; - const char* netLibrary; - const char* nioLibrary; const char* tzMappings; const char* embedPrefix; unsigned tzMappingsLength; @@ -455,6 +428,7 @@ class MyClasspath : public Classpath { unsigned filePathField; unsigned fileDescriptorFdField; unsigned fileInputStreamFdField; + bool ranNetOnLoad; char buffer[BufferSize]; }; @@ -595,44 +569,37 @@ getFileAttributes stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); - if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) - or pathEqual(cp->netLibrary, RUNTIME_ARRAY_BODY(p)) - or pathEqual(cp->nioLibrary, RUNTIME_ARRAY_BODY(p))) - { - return Exists | Regular; - } else { - EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); - if (ef.jar) { - if (ef.jarLength == 0) { + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return Exists | Directory; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { return Exists | Directory; } - Finder* finder = getFinder(t, ef.jar, ef.jarLength); - if (finder) { - if (ef.pathLength == 0) { - return Exists | Directory; - } - - unsigned length; - System::FileType type = finder->stat(ef.path, &length, true); - switch (type) { - case System::TypeUnknown: return Exists; - case System::TypeDoesNotExist: return 0; - case System::TypeFile: return Exists | Regular; - case System::TypeDirectory: return Exists | Directory; - default: abort(t); - } - } else { - return 0; + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeUnknown: return Exists; + case System::TypeDoesNotExist: return 0; + case System::TypeFile: return Exists | Regular; + case System::TypeDirectory: return Exists | Directory; + default: abort(t); } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file); - - return (r ? intValue(t, r) : 0); + return 0; } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file); + + return (r ? intValue(t, r) : 0); } } @@ -652,44 +619,37 @@ checkFileAccess stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); - if (pathEqual(cp->zipLibrary, RUNTIME_ARRAY_BODY(p)) - or pathEqual(cp->netLibrary, RUNTIME_ARRAY_BODY(p)) - or pathEqual(cp->nioLibrary, RUNTIME_ARRAY_BODY(p))) - { - return mask == Read; - } else { - EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); - if (ef.jar) { - if (ef.jarLength == 0) { + EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); + if (ef.jar) { + if (ef.jarLength == 0) { + return mask == Read; + } + + Finder* finder = getFinder(t, ef.jar, ef.jarLength); + if (finder) { + if (ef.pathLength == 0) { return mask == Read; } - Finder* finder = getFinder(t, ef.jar, ef.jarLength); - if (finder) { - if (ef.pathLength == 0) { - return mask == Read; - } - - unsigned length; - System::FileType type = finder->stat(ef.path, &length, true); - switch (type) { - case System::TypeDoesNotExist: return false; - case System::TypeUnknown: - case System::TypeFile: - case System::TypeDirectory: return mask == Read; - default: abort(t); - } - } else { - return 0; + unsigned length; + System::FileType type = finder->stat(ef.path, &length, true); + switch (type) { + case System::TypeDoesNotExist: return false; + case System::TypeUnknown: + case System::TypeFile: + case System::TypeDirectory: return mask == Read; + default: abort(t); } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file, mask); - - return (r ? booleanValue(t, r) : false); + return 0; } + } else { + object r = t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file, mask); + + return (r ? booleanValue(t, r) : false); } } @@ -1048,6 +1008,50 @@ getBootstrapResources(Thread* t, object, uintptr_t* arguments) } } +extern "C" JNIEXPORT jint JNICALL +net_JNI_OnLoad(JavaVM*, void*); + +void JNICALL +loadLibrary(Thread* t, object, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[1]); + RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); + stringChars(t, name, RUNTIME_ARRAY_BODY(n)); + + bool absolute = arguments[2]; + +#ifdef AVIAN_OPENJDK_SRC + if (not absolute) { + if (strcmp(n, "net") == 0) { + bool ran; + + { ACQUIRE(t, t->m->classLock); + + local::MyClasspath* c = static_cast + (t->m->classpath); + + ran = c->ranNetOnLoad; + c->ranNetOnLoad = true; + } + + if (not ran) { + net_JNI_OnLoad(t->m, 0); + } + + return; + } else if (strcmp(n, "zip") == 0 + or strcmp(n, "nio") == 0) + { + return; + } + } +#endif // AVIAN_OPENJDK_SRC + + loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, + RUNTIME_ARRAY_BODY(n), not absolute, false); +} + // only safe to call during bootstrap when there's only one thread // running: void @@ -1160,6 +1164,10 @@ interceptFileOperations(Thread* t) voidPointer(getFileLength)); } + intercept(t, type(t, Machine::ClassLoaderType), "loadLibrary", + "(Ljava/lang/Class;Ljava/lang/String;Z)V", + voidPointer(loadLibrary)); + intercept(t, type(t, Machine::ClassLoaderType), "getBootstrapResource", "(Ljava/lang/String;)Ljava/net/URL;", voidPointer(getBootstrapResource)); @@ -2060,9 +2068,6 @@ EXPORT(JVM_ActiveProcessorCount)() return 1; } -extern "C" JNIEXPORT jint JNICALL -net_JNI_OnLoad(JavaVM*, void*); - extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_LoadLibrary)(const char* path) { @@ -2071,26 +2076,6 @@ EXPORT(JVM_LoadLibrary)(const char* path) RUNTIME_ARRAY(char, p, strlen(path) + 1); replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); -#ifdef AVIAN_OPENJDK_SRC - if (local::pathEqual - (static_cast(t->m->classpath)->zipLibrary, - RUNTIME_ARRAY_BODY(p)) - or local::pathEqual - (static_cast(t->m->classpath)->nioLibrary, - RUNTIME_ARRAY_BODY(p))) - { - return t->m->libraries; - } else if (local::pathEqual - (static_cast(t->m->classpath)->netLibrary, - RUNTIME_ARRAY_BODY(p))) - { - net_JNI_OnLoad(t->m, 0); - return t->m->libraries; - } -#endif // AVIAN_OPENJDK_SRC - - ENTER(t, Thread::ActiveState); - return loadLibrary (t, static_cast(t->m->classpath)->libraryPath, RUNTIME_ARRAY_BODY(p), false, false); From cda1ae81c89b555ed35ec735fcb6ad5cb8a596a7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 8 Dec 2010 21:39:20 -0700 Subject: [PATCH 167/274] protect networking and time zone classes from obfuscation/shrinking --- openjdk.pro | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/openjdk.pro b/openjdk.pro index f2cf30abc4..81031f3bc9 100644 --- a/openjdk.pro +++ b/openjdk.pro @@ -26,6 +26,7 @@ -keepnames class java.lang.ClassLoader { public java.lang.Class loadClass(java.lang.String); + static void loadLibrary(java.lang.Class, java.lang.String, boolean); private static java.net.URL getBootstrapResource(java.lang.String); private static java.util.Enumeration getBootstrapResources(java.lang.String); } @@ -89,6 +90,10 @@ public byte[] getBytes(java.lang.String); } +-keepclassmembers class java.lang.Boolean { + public boolean getBoolean(java.lang.String); + } + -keepclassmembers class java.util.zip.Inflater { long strm; boolean needDict; @@ -102,6 +107,26 @@ private int fd; } +-keep class java.net.InetAddress { + ; + } +-keep class java.net.Inet4Address { + ; + } +-keep class java.net.Inet4AddressImpl +-keep class java.net.Inet6Address { + ; + } +-keep class java.net.Inet6AddressImpl +-keep class java.net.InetSocketAddress { + public InetSocketAddress(java.net.InetAddress, int); + } +-keep class java.net.ServerSocket + +-keepclassmembers class java.net.PlainSocketImpl { + ; + } + -keepclassmembers class java.io.FileInputStream { private java.io.FileDescriptor fd; } @@ -183,5 +208,6 @@ # referred to by name in LocaleData to load resources: -keep class sun.util.resources.CalendarData +-keep class sun.util.resources.TimeZoneNames -keep class sun.text.resources.FormatData From 3d49173b0b211249bdef215d58322cc68a4396fb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 9 Dec 2010 19:38:12 -0700 Subject: [PATCH 168/274] avoid inifinite recursion if java.lang.Object is missing; refactoring When trying to create an array class, we try to resolve java.lang.Object so we can use its vtable in the array class. However, if Object is missing, we'll try to create and throw a ClassNotFoundException, which requires creating an array to store the stack trace, which requires creating an array class, which requires resolving Object, etc.. This commit short-circuits this process by telling resolveClass not to create and throw an exception if it can't find Object. While doing the above work, I noticed that the implementations of Classpath::makeThrowable in classpath-avian.cpp and classpath-openjdk.cpp were identical, so I made makeThrowable a top-level function. Finally, I discovered that Thread.setDaemon can only be called before the target thread has been started, which allowed me to simplify the code to track daemon threads in the VM. --- classpath/java/lang/Thread.java | 8 +- src/builtin.cpp | 12 +-- src/classpath-avian.cpp | 45 ++-------- src/classpath-common.h | 10 +-- src/classpath-openjdk.cpp | 50 +++-------- src/compile.cpp | 31 +++---- src/interpret.cpp | 137 +++++++++++----------------- src/jnienv.cpp | 20 ++--- src/machine.cpp | 83 ++++++----------- src/machine.h | 153 ++++++++++++++++++++------------ src/process.cpp | 2 +- 11 files changed, 219 insertions(+), 332 deletions(-) diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java index 0606f51377..2d321193a0 100644 --- a/classpath/java/lang/Thread.java +++ b/classpath/java/lang/Thread.java @@ -239,12 +239,12 @@ public class Thread implements Runnable { } public synchronized void setDaemon(boolean v) { - if (v != daemon) { - setDaemon(this, v); + if (getState() != State.NEW) { + throw new IllegalStateException(); } - } - private static native void setDaemon(Thread t, boolean increment); + daemon = v; + } public static native void yield(); diff --git a/src/builtin.cpp b/src/builtin.cpp index 3c0365ea7b..dd8ece531a 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -40,8 +40,7 @@ search(Thread* t, object loader, object name, return reinterpret_cast(r); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return 0; } } @@ -93,8 +92,7 @@ Avian_avian_SystemClassLoader_resourceExists return r; } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return 0; } } @@ -126,8 +124,7 @@ Avian_avian_Machine_dumpHeap fclose(out); } else { object message = makeString(t, "file not found: %s", n); - t->exception = t->m->classpath->makeThrowable - (t, Machine::RuntimeExceptionType, message); + t->exception = makeThrowable(t, Machine::RuntimeExceptionType, message); } } @@ -183,8 +180,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open return reinterpret_cast(r); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return 0; } } diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 8bc2560086..51f5058713 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -65,27 +65,6 @@ class MyClasspath : public Classpath { } } - virtual object - makeThrowable - (Thread* t, Machine::Type type, object message, object trace, object cause) - { - PROTECT(t, message); - PROTECT(t, trace); - PROTECT(t, cause); - - if (trace == 0) { - trace = makeTrace(t); - } - - object result = make(t, vm::type(t, type)); - - set(t, result, ThrowableMessage, message); - set(t, result, ThrowableTrace, trace); - set(t, result, ThrowableCause, cause); - - return result; - } - virtual void boot(Thread*) { @@ -330,7 +309,7 @@ Avian_java_lang_reflect_Method_invoke object v = t->m->processor->invokeArray(t, method, instance, args); if (t->exception) { - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::InvocationTargetExceptionType, 0, 0, t->exception); } return reinterpret_cast(v); @@ -348,12 +327,10 @@ Avian_java_lang_reflect_Array_getLength if (LIKELY(elementSize)) { return cast(array, BytesPerWord); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalArgumentExceptionType); + t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); } } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); } return 0; } @@ -462,8 +439,7 @@ Avian_java_lang_System_identityHashCode if (LIKELY(o)) { return objectHash(t, o); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return 0; } } @@ -604,16 +580,6 @@ Avian_java_lang_Thread_enumerate return count; } -extern "C" JNIEXPORT void JNICALL -Avian_java_lang_Thread_setDaemon -(Thread* t, object, uintptr_t* arguments) -{ - object thread = reinterpret_cast(arguments[0]); - bool daemon = arguments[1] != 0; - - setDaemon(t, thread, daemon); -} - extern "C" JNIEXPORT void JNICALL Avian_avian_Classes_acquireClassLock (Thread* t, object, uintptr_t*) @@ -682,8 +648,7 @@ Avian_avian_Classes_isAssignableFrom if (LIKELY(that)) { return vm::isAssignableFrom(t, this_, that); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return 0; } } diff --git a/src/classpath-common.h b/src/classpath-common.h index 3ca61210a0..7d17a74673 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -101,7 +101,7 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, return; } else { - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::IndexOutOfBoundsExceptionType); return; } @@ -111,13 +111,11 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, } } } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); return; } - t->exception = t->m->classpath->makeThrowable - (t, Machine::ArrayStoreExceptionType); + t->exception = makeThrowable(t, Machine::ArrayStoreExceptionType); } void @@ -223,7 +221,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, } } else { object message = makeString(t, "library not found: %s", name); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::UnsatisfiedLinkErrorType, message); } diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index eda7ac90de..c18445d298 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -330,27 +330,6 @@ class MyClasspath : public Classpath { release(t, t->javaThread); } - virtual object - makeThrowable - (Thread* t, Machine::Type type, object message, object trace, object cause) - { - PROTECT(t, message); - PROTECT(t, trace); - PROTECT(t, cause); - - if (trace == 0) { - trace = makeTrace(t); - } - - object result = make(t, vm::type(t, type)); - - set(t, result, ThrowableMessage, message); - set(t, result, ThrowableTrace, trace); - set(t, result, ThrowableCause, cause); - - return result; - } - virtual void boot(Thread* t) { @@ -709,22 +688,19 @@ openFile(Thread* t, object method, uintptr_t* arguments) EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::FileNotFoundExceptionType); + t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); return; } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::FileNotFoundExceptionType); + t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); return; } System::Region* r = finder->find(ef.path); if (r == 0) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::FileNotFoundExceptionType); + t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); return; } @@ -792,8 +768,7 @@ readByteFromFile(Thread* t, object method, uintptr_t* arguments) return -1; } } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IoExceptionType); + t->exception = makeThrowable(t, Machine::IoExceptionType); return 0; } } else { @@ -847,8 +822,7 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) return length; } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IoExceptionType); + t->exception = makeThrowable(t, Machine::IoExceptionType); return 0; } } else { @@ -892,8 +866,7 @@ skipBytesInFile(Thread* t, object method, uintptr_t* arguments) return count; } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IoExceptionType); + t->exception = makeThrowable(t, Machine::IoExceptionType); return 0; } } else { @@ -927,8 +900,7 @@ availableBytesInFile(Thread* t, object method, uintptr_t* arguments) return static_cast(regionRegion(t, region))->length() - regionPosition(t, region); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IoExceptionType); + t->exception = makeThrowable(t, Machine::IoExceptionType); return 0; } } else { @@ -1735,8 +1707,7 @@ Avian_sun_misc_Unsafe_allocateMemory if (p) { return reinterpret_cast(p); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::OutOfMemoryErrorType); + t->exception = makeThrowable(t, Machine::OutOfMemoryErrorType); return 0; } } @@ -2474,8 +2445,7 @@ EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) return makeLocalReference (t, getJClass(t, type(t, Machine::JvoidType))); default: - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalArgumentExceptionType); + t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); return 0; } } @@ -2494,7 +2464,7 @@ EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, (t, loader ? *loader : root(t, Machine::BootLoader), name); if (t->exception) { if (throwError) { - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::NoClassDefFoundErrorType, throwableMessage(t, t->exception), throwableTrace(t, t->exception), diff --git a/src/compile.cpp b/src/compile.cpp index 3bafb38eff..6cdd70f5e7 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2150,8 +2150,7 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) return methodAddress(t, target); } } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2422,7 +2421,7 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) return reinterpret_cast(makeObjectArray(t, class_, length)); } else { object message = makeString(t, "%d", length); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } @@ -2472,7 +2471,7 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length) return reinterpret_cast(constructor(t, length)); } else { object message = makeString(t, "%d", length); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); unwind(t); } @@ -2507,8 +2506,7 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) if (LIKELY(o)) { set(t, o, offset, value); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2519,8 +2517,7 @@ acquireMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { acquire(t, o); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2531,8 +2528,7 @@ releaseMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { release(t, o); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); unwind(t); } } @@ -2548,7 +2544,7 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1]; if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { object message = makeString(t, "%d", RUNTIME_ARRAY_BODY(counts)[i]); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); return 0; } @@ -2603,7 +2599,7 @@ throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType); atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { @@ -2621,8 +2617,7 @@ throw_(MyThread* t, object o) if (LIKELY(o)) { t->exception = o; } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); } // printTrace(t, t->exception); @@ -2638,8 +2633,7 @@ checkCast(MyThread* t, object class_, object o) (t, "%s as %s", &byteArrayBody(t, className(t, objectClass(t, o)), 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = t->m->classpath->makeThrowable - (t, Machine::ClassCastExceptionType, message); + t->exception = makeThrowable(t, Machine::ClassCastExceptionType, message); unwind(t); } } @@ -6837,7 +6831,7 @@ callContinuation(MyThread* t, object continuation, object result, action = Call; } } else { - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::IncompatibleContinuationExceptionType); action = Throw; } @@ -7175,8 +7169,7 @@ class SegFaultHandler: public System::SignalHandler { if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); - t->exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, Machine::NullPointerExceptionType); atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { // not enough memory available for a new NPE and stack trace diff --git a/src/interpret.cpp b/src/interpret.cpp index 1634463ea1..e9d4c418c1 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -438,8 +438,7 @@ checkStack(Thread* t, object method) + codeMaxStack(t, methodCode(t, method)) > Thread::StackSizeInWords / 2)) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::StackOverflowErrorType); + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); } } @@ -864,13 +863,12 @@ interpret(Thread* t) } else { object message = makeString (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -888,13 +886,12 @@ interpret(Thread* t) } else { object message = makeString (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -935,7 +932,7 @@ interpret(Thread* t) pushObject(t, makeObjectArray(t, class_, count)); } else { object message = makeString(t, "%d", count); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } @@ -957,8 +954,7 @@ interpret(Thread* t) if (LIKELY(array)) { pushInt(t, cast(array, BytesPerWord)); } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -986,8 +982,7 @@ interpret(Thread* t) case athrow: { exception = popObject(t); if (UNLIKELY(exception == 0)) { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } goto throw_; @@ -1005,7 +1000,7 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } @@ -1019,14 +1014,13 @@ interpret(Thread* t) object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1046,7 +1040,7 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, booleanArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } @@ -1058,14 +1052,13 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, byteArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1086,13 +1079,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1110,13 +1102,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, charArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1134,7 +1125,7 @@ interpret(Thread* t) &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ClassCastExceptionType, message); goto throw_; } @@ -1172,13 +1163,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1196,13 +1186,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, doubleArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1376,13 +1365,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1400,13 +1388,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, floatArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1518,8 +1505,7 @@ interpret(Thread* t) } } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1611,13 +1597,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1642,13 +1627,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, intArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1915,8 +1899,7 @@ interpret(Thread* t) (t, method, objectClass(t, peekObject(t, sp - parameterFootprint))); goto invoke; } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1941,8 +1924,7 @@ interpret(Thread* t) goto invoke; } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -1973,8 +1955,7 @@ interpret(Thread* t) code = findVirtualMethod(t, method, class_); goto invoke; } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2110,13 +2091,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2141,13 +2121,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, longArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2373,8 +2352,7 @@ interpret(Thread* t) if (LIKELY(o)) { acquire(t, o); } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2384,8 +2362,7 @@ interpret(Thread* t) if (LIKELY(o)) { release(t, o); } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2403,7 +2380,7 @@ interpret(Thread* t) counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { object message = makeString(t, "%d", counts[i]); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } @@ -2477,7 +2454,7 @@ interpret(Thread* t) pushObject(t, array); } else { object message = makeString(t, "%d", count); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::NegativeArraySizeExceptionType, message); goto throw_; } @@ -2540,8 +2517,7 @@ interpret(Thread* t) break; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2552,8 +2528,7 @@ interpret(Thread* t) if (LIKELY(o)) { cast(o, fieldOffset(t, field)) = value; } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2563,8 +2538,7 @@ interpret(Thread* t) if (LIKELY(o)) { set(t, o, fieldOffset(t, field), value); } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } } break; @@ -2694,13 +2668,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -2718,13 +2691,12 @@ interpret(Thread* t) } else { object message = makeString(t, "%d not in [0,%d)", index, shortArrayLength(t, array)); - exception = t->m->classpath->makeThrowable + exception = makeThrowable (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); goto throw_; } } else { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); goto throw_; } } goto loop; @@ -3166,8 +3138,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::StackOverflowErrorType); + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; } @@ -3192,8 +3163,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > Thread::StackSizeInWords / 2)) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::StackOverflowErrorType); + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; } @@ -3217,8 +3187,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) > Thread::StackSizeInWords / 2)) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::StackOverflowErrorType); + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; } diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 7579b9891e..38598a385a 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -31,26 +31,17 @@ AttachCurrentThread(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { - *t = m->processor->makeThread(m, 0, m->rootThread); - m->system->attach(&((*t)->runnable)); - - enter(*t, Thread::ActiveState); - enter(*t, Thread::IdleState); - - m->localThread->set(*t); + *t = attachThread(m, false); } return 0; } jint JNICALL -AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void* parameters) +AttachCurrentThreadAsDaemon(Machine* m, Thread** t, void*) { *t = static_cast(m->localThread->get()); if (*t == 0) { - AttachCurrentThread(m, t, parameters); - - ENTER(*t, Thread::ActiveState); - setDaemon(*t, (*t)->javaThread, true); + *t = attachThread(m, true); } return 0; } @@ -2040,13 +2031,12 @@ boot(Thread* t) enter(t, Thread::ActiveState); if (t->exception == 0) { - setRoot(t, Machine::NullPointerException, t->m->classpath->makeThrowable + setRoot(t, Machine::NullPointerException, makeThrowable (t, Machine::NullPointerExceptionType)); if (t->exception == 0) { setRoot(t, Machine::ArrayIndexOutOfBoundsException, - t->m->classpath->makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType)); + makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); } } diff --git a/src/machine.cpp b/src/machine.cpp index ec1c06ae61..ddf27487b1 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1731,11 +1731,13 @@ makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec, PROTECT(t, spec); PROTECT(t, elementClass); + // Load java.lang.Object if present so we can use its vtable, but + // don't throw an exception if we can't find it. This way, we + // avoid infinite recursion due to trying to create an array to + // make a stack trace for a ClassNotFoundException. resolveSystemClass (t, root(t, Machine::BootLoader), - className(t, type(t, Machine::JobjectType))); - - if (UNLIKELY(t->exception)) return 0; + className(t, type(t, Machine::JobjectType)), false); } object vtable = classVirtualTable(t, type(t, Machine::JobjectType)); @@ -2324,18 +2326,16 @@ Thread::init() setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0)); m->localThread->set(this); + + javaThread = m->classpath->makeThread(this, 0); + + threadPeer(this, javaThread) = reinterpret_cast(this); } else { peer = parent->child; parent->child = this; } expect(this, m->system->success(m->system->make(&lock))); - - if (javaThread == 0) { - this->javaThread = m->classpath->makeThread(this, parent); - } - - threadPeer(this, javaThread) = reinterpret_cast(this); } void @@ -2494,36 +2494,6 @@ enter(Thread* t, Thread::State s) } break; case Thread::IdleState: - // The java.lang.Thread implementation may or may not notify the - // VM when the daemon field in the Java object changes, so we sync - // up the native field whenever the thread transitions to idle: - - // todo: this won't always help if some other thread sets the - // daemon field. The thread trying to shut down the VM really - // just needs to count from scratch every time any thread makes a - // transition (i.e. eliminate Machine::daemonCount). - - if (UNLIKELY(((t->flags & Thread::DaemonFlag) != 0) - != threadDaemon(t, t->javaThread))) - { - ACQUIRE_LOCK; - - if (threadDaemon(t, t->javaThread)) { - atomicOr(&(t->flags), Thread::DaemonFlag); - } else { - atomicAnd(&(t->flags), ~Thread::DaemonFlag); - } - - if (t->flags & Thread::DaemonFlag) { - ++ t->m->daemonCount; - } else { - expect(t, t->m->daemonCount); - -- t->m->daemonCount; - } - - t->m->stateLock->notifyAll(t->systemThread); - } - if (LIKELY(t->state == Thread::ActiveState)) { // fast path assert(t, t->m->activeCount > 0); @@ -2563,7 +2533,7 @@ enter(Thread* t, Thread::State s) assert(t, t->m->liveCount > 0); -- t->m->liveCount; - if (threadDaemon(t, t->javaThread)) { + if (t->flags & Thread::DaemonFlag) { -- t->m->daemonCount; } } @@ -3239,7 +3209,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); } else if (throw_ and t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::ClassNotFoundExceptionType, message); } } @@ -3334,7 +3304,7 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) } else { if (t->exception == 0) { object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::ClassNotFoundExceptionType, message); } @@ -3361,8 +3331,7 @@ resolveMethod(Thread* t, object class_, const char* methodName, (t, "%s %s not found in %s", methodName, methodSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = t->m->classpath->makeThrowable - (t, Machine::NoSuchMethodErrorType, message); + t->exception = makeThrowable(t, Machine::NoSuchMethodErrorType, message); return 0; } else { return method; @@ -3395,8 +3364,7 @@ resolveField(Thread* t, object class_, const char* fieldName, (t, "%s %s not found in %s", fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); - t->exception = t->m->classpath->makeThrowable - (t, Machine::NoSuchFieldErrorType, message); + t->exception = makeThrowable(t, Machine::NoSuchFieldErrorType, message); return 0; } else { return field; @@ -3449,7 +3417,7 @@ preInitClass(Thread* t, object c) object message = makeString (t, "%s", &byteArrayBody(t, className(t, c), 0)); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::NoClassDefFoundErrorType, message); } else { classVmFlags(t, c) |= InitFlag; @@ -3467,7 +3435,7 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; @@ -3527,6 +3495,7 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass) } object arrayClass = resolveClass(t, loader, spec); + if (UNLIKELY(t->exception)) return 0; set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, arrayClass); @@ -3539,6 +3508,8 @@ makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass (t, classLoader(t, elementClass), elementClass); + if (UNLIKELY(t->exception)) return 0; + PROTECT(t, arrayClass); object array = makeArray(t, count); @@ -3760,13 +3731,12 @@ collect(Thread* t, Heap::CollectionType type) } if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { - m->finalizeThread = m->processor->makeThread - (m, t->m->classpath->makeThread(t, m->rootThread), m->rootThread); + object javaThread = t->m->classpath->makeThread(t, m->rootThread); + threadDaemon(t, javaThread) = true; - if (not t->m->system->success - (m->system->start(&(m->finalizeThread->runnable)))) - { - m->finalizeThread->exit(); + m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread); + + if (not startThread(t, m->finalizeThread)) { m->finalizeThread = 0; } } @@ -3849,8 +3819,7 @@ void printTrace(Thread* t, object exception) { if (exception == 0) { - exception = t->m->classpath->makeThrowable - (t, Machine::NullPointerExceptionType); + exception = makeThrowable(t, Machine::NullPointerExceptionType); } for (object e = exception; e; e = throwableCause(t, e)) { @@ -3956,8 +3925,6 @@ makeTrace(Thread* t, Thread* target) void runFinalizeThread(Thread* t) { - setDaemon(t, t->javaThread, true); - object list = 0; PROTECT(t, list); diff --git a/src/machine.h b/src/machine.h index 4c65230095..984d4e54db 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1282,6 +1282,9 @@ runJavaThread(Thread* t); void runFinalizeThread(Thread* t); +void +checkDaemon(Thread* t); + class Thread { public: enum State { @@ -1361,6 +1364,8 @@ class Thread { t->m->localThread->set(t); + checkDaemon(t); + if (t == t->m->finalizeThread) { runFinalizeThread(t); } else if (t->javaThread) { @@ -1429,11 +1434,6 @@ class Classpath { virtual void runThread(Thread* t) = 0; - virtual object - makeThrowable - (Thread* t, Machine::Type type, object message = 0, object trace = 0, - object cause = 0) = 0; - virtual void boot(Thread* t) = 0; @@ -1709,19 +1709,6 @@ setObjectClass(Thread*, object o, object value) | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); } -inline Thread* -startThread(Thread* t, object javaThread) -{ - Thread* p = t->m->processor->makeThread(t->m, javaThread, t); - - if (t->m->system->success(t->m->system->start(&(p->runnable)))) { - return p; - } else { - p->exit(); - return 0; - } -} - inline const char* findProperty(Machine* m, const char* name) { @@ -1759,6 +1746,69 @@ runJavaThread(Thread* t) t->m->classpath->runThread(t); } +inline bool +startThread(Thread* t, Thread* p) +{ + return t->m->system->success(t->m->system->start(&(p->runnable))); +} + +inline Thread* +startThread(Thread* t, object javaThread) +{ + Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + + if (startThread(t, p)) { + return p; + } else { + return 0; + } +} + +inline void +registerDaemon(Thread* t) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + atomicOr(&(t->flags), Thread::DaemonFlag); + + ++ t->m->daemonCount; + + t->m->stateLock->notifyAll(t->systemThread); +} + +inline void +checkDaemon(Thread* t) +{ + if (threadDaemon(t, t->javaThread)) { + registerDaemon(t); + } +} + +inline Thread* +attachThread(Machine* m, bool daemon) +{ + Thread* t = m->processor->makeThread(m, 0, m->rootThread); + m->system->attach(&(t->runnable)); + + enter(t, Thread::ActiveState); + + t->javaThread = m->classpath->makeThread(t, m->rootThread); + + threadPeer(t, t->javaThread) = reinterpret_cast(t); + + if (daemon) { + threadDaemon(t, t->javaThread) = true; + + registerDaemon(t); + } + + enter(t, Thread::IdleState); + + m->localThread->set(t); + + return t; +} + inline object& root(Thread* t, Machine::Root root) { @@ -2237,6 +2287,28 @@ findMethodInClass(Thread* t, object class_, object name, object spec) (t, classMethodTable(t, class_), name, spec, methodName, methodSpec); } +inline object +makeThrowable +(Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) +{ + PROTECT(t, message); + PROTECT(t, trace); + PROTECT(t, cause); + + if (trace == 0) { + trace = makeTrace(t); + } + + object result = make(t, vm::type(t, type)); + + set(t, result, ThrowableMessage, message); + set(t, result, ThrowableTrace, trace); + set(t, result, ThrowableCause, cause); + + return result; +} + object findInHierarchyOrNull(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object)); @@ -2254,7 +2326,7 @@ findInHierarchy(Thread* t, object class_, object name, object spec, &byteArrayBody(t, name, 0), &byteArrayBody(t, spec, 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = t->m->classpath->makeThrowable(t, errorType, message); + t->exception = makeThrowable(t, errorType, message); } return o; @@ -2707,12 +2779,10 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - t->exception = t->m->classpath->makeThrowable - (t, Machine::InterruptedExceptionType); + t->exception = makeThrowable(t, Machine::InterruptedExceptionType); } } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalMonitorStateExceptionType); + t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { @@ -2741,8 +2811,7 @@ notify(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalMonitorStateExceptionType); + t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); } } @@ -2759,8 +2828,7 @@ notifyAll(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalMonitorStateExceptionType); + t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); } } @@ -2803,34 +2871,6 @@ interrupt(Thread* t, Thread* target) } } -inline void -setDaemon(Thread* t, object thread, bool daemon) -{ - ACQUIRE_RAW(t, t->m->stateLock); - - if ((threadDaemon(t, thread) != 0) != daemon) { - threadDaemon(t, thread) = daemon; - - Thread* p = reinterpret_cast(threadPeer(t, thread)); - if (p) { - if (daemon) { - atomicOr(&(p->flags), Thread::DaemonFlag); - } else { - atomicAnd(&(p->flags), ~Thread::DaemonFlag); - } - } - - if (daemon) { - ++ t->m->daemonCount; - } else { - expect(t, t->m->daemonCount); - -- t->m->daemonCount; - } - - t->m->stateLock->notifyAll(t->systemThread); - } -} - object intern(Thread* t, object s); @@ -3157,8 +3197,7 @@ primitiveClass(Thread* t, char name) case 'V': return type(t, Machine::JvoidType); case 'Z': return type(t, Machine::JbooleanType); default: - t->exception = t->m->classpath->makeThrowable - (t, Machine::IllegalArgumentExceptionType); + t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); return 0; } } diff --git a/src/process.cpp b/src/process.cpp index cab5fb8b4f..00edbe66b7 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -243,7 +243,7 @@ resolveNative(Thread* t, object method) &byteArrayBody(t, methodName(t, method), 0), &byteArrayBody(t, methodSpec(t, method), 0)); - t->exception = t->m->classpath->makeThrowable + t->exception = makeThrowable (t, Machine::UnsatisfiedLinkErrorType, message); return; } From 2d0ff83653eb4c346048a6a86fe2b7b3fb4e3255 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 9 Dec 2010 21:09:48 -0700 Subject: [PATCH 169/274] fix assertion abort when generating boot image In makeCodeImage, we were passing zero to Promise::Listener::resolve, which would lead to an assertion error if the address of the code image was further from the base of the address space (i.e. zero) than could be spanned by a jump on the target architecture. Since, in this context, we immediately overwrite the value stored, we may pass whatever we want to this function (we're only calling it so we can retrieve the location of the value in the image), and the code image pointer is a better choice for the above reason. --- src/bootimage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index d19bbf81df..252028dd79 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -170,7 +170,8 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, assert(t, value >= code); void* location; - bool flat = addresses->listener->resolve(0, &location); + bool flat = addresses->listener->resolve + (reinterpret_cast(code), &location); uintptr_t offset = value - code; if (flat) { offset |= BootFlatConstant; From 651ad20fc3a280dab5b1c5b9775082f66b0d3c16 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 9 Dec 2010 22:17:57 -0700 Subject: [PATCH 170/274] fix GC safety bugs --- src/classpath-openjdk.cpp | 4 ++-- src/machine.cpp | 5 +++-- src/machine.h | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c18445d298..bb4bdb33e4 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1084,14 +1084,14 @@ interceptFileOperations(Thread* t) (t, root(t, Machine::BootLoader), "java/io/FileInputStream"); if (fileInputStreamClass == 0) return; + PROTECT(t, fileInputStreamClass); + object fileInputStreamFdField = findFieldInClass2 (t, fileInputStreamClass, "fd", "Ljava/io/FileDescriptor;"); if (fileInputStreamFdField == 0) return; cp->fileInputStreamFdField = fieldOffset(t, fileInputStreamFdField); - PROTECT(t, fileInputStreamClass); - intercept(t, fileInputStreamClass, "open", "(Ljava/lang/String;)V", voidPointer(openFile)); diff --git a/src/machine.cpp b/src/machine.cpp index ddf27487b1..98835556bf 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1903,14 +1903,15 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name, PROTECT(t, bootMethod); object n = makeByteArray(t, name); + PROTECT(t, n); + object class_ = vm::type(t, type); + PROTECT(t, class_); set(t, class_, ClassName, n); object vtable; if (vtableLength >= 0) { - PROTECT(t, class_); - vtable = makeArray(t, vtableLength); for (int i = 0; i < vtableLength; ++ i) { arrayBody(t, vtable, i) = bootMethod; diff --git a/src/machine.h b/src/machine.h index 984d4e54db..fbb5771c8c 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1513,7 +1513,8 @@ shutDown(Thread* t); inline void stress(Thread* t) { - if ((t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 + if ((not t->m->unsafe) + and (t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and t->state != Thread::NoState and t->state != Thread::IdleState) { @@ -3166,10 +3167,10 @@ getMethodRuntimeData(Thread* t, object method) inline object getJClass(Thread* t, object c) { + PROTECT(t, c); + object jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); if (jclass == 0) { - PROTECT(t, c); - ACQUIRE(t, t->m->classLock); jclass = classRuntimeDataJclass(t, getClassRuntimeData(t, c)); From 64b11f0c64aeb624803810c771c216cb256c7857 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Dec 2010 01:20:44 -0700 Subject: [PATCH 171/274] close ZipFile when done with it in Zip test --- test/Zip.java | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/test/Zip.java b/test/Zip.java index 665086ea68..8862e767c7 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -27,20 +27,24 @@ public class Zip { ZipFile file = new ZipFile (findJar(new File(System.getProperty("user.dir")))); - byte[] buffer = new byte[4096]; - for (Enumeration e = file.entries(); - e.hasMoreElements();) - { - ZipEntry entry = e.nextElement(); - InputStream in = file.getInputStream(entry); - try { - int size = 0; - int c; while ((c = in.read(buffer)) != -1) size += c; - System.out.println - (entry.getName() + " " + entry.getCompressedSize() + " " + size); - } finally { - in.read(); + try { + byte[] buffer = new byte[4096]; + for (Enumeration e = file.entries(); + e.hasMoreElements();) + { + ZipEntry entry = e.nextElement(); + InputStream in = file.getInputStream(entry); + try { + int size = 0; + int c; while ((c = in.read(buffer)) != -1) size += c; + System.out.println + (entry.getName() + " " + entry.getCompressedSize() + " " + size); + } finally { + in.close(); + } } + } finally { + file.close(); } } From d5d414aa52bbdfe02133c8dc0be7c66bca43421b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 10 Dec 2010 14:01:22 -0700 Subject: [PATCH 172/274] update gprIndex when switching to stack-based argument passing This is necessary when passing a 64-bit value on 32-bit ARM since otherwise we risk using a register for the following argument instead of the stack. --- src/arm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/arm.h b/src/arm.h index 0c5c5cc2e5..e66377e7f6 100644 --- a/src/arm.h +++ b/src/arm.h @@ -101,6 +101,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; } else { // pass argument on stack + gprIndex = GprCount; if (stackIndex & 1) { // 8-byte alignment memset(stack + stackIndex, 0, 4); // probably not necessary, but for good luck ++stackIndex; From 6c53068f4f048cff372c0dc4045bc0cade60189a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 15 Dec 2010 10:41:18 -0700 Subject: [PATCH 173/274] clear Thread::stack before vmInvoke_safeStack in compile-arm.S --- src/compile-arm.S | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/compile-arm.S b/src/compile-arm.S index 555c61476b..c61ebaff37 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -96,6 +96,14 @@ GLOBAL(vmInvoke_returnAddress): // restore frame ldr sp, [sp] + + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + mov r5,#0 + str r5,[r8,#THREAD_STACK] .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): From cac2d2cac549d73b3476505fd5bbcb6a74812a30 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 16 Dec 2010 16:46:25 -0700 Subject: [PATCH 174/274] fix race condition in monitorRelease There was an unlikely but dangerous race condition in monitorRelease such that when a thread released a monitor and then tried to notify the next thread in line, the latter thread might exit before it can be notified. This potentially led to a crash as the former thread tried to acquire and notify the latter thread's private lock after it had been disposed. The solution is to do as we do in the interrupt and join cases: call acquireSystem first and thereby either block the target thread from exiting until we're done or find that it has already exited, in which case nothing needs to be done. I also looked at monitorNotify to see if we have a similar bug there, but in that case the target thread can't exit without first acquiring and releasing the monitor, and since we ensure that no thread can execute monitorNotify without holding the monitor, there's no potential for a race. --- src/machine.h | 64 ++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/machine.h b/src/machine.h index fbb5771c8c..3333cb084a 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2398,6 +2398,36 @@ parameterFootprint(Thread* t, const char* s, bool static_); void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)); +inline bool +zombified(Thread* t) +{ + return t->state == Thread::ZombieState + or t->state == Thread::JoinedState; +} + +inline bool +acquireSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + if (not zombified(target)) { + atomicOr(&(target->flags), Thread::SystemFlag); + return true; + } else { + return false; + } +} + +inline void +releaseSystem(Thread* t, Thread* target) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, not zombified(target)); + + atomicAnd(&(target->flags), ~Thread::SystemFlag); +} + inline bool atomicCompareAndSwapObject(Thread* t, object target, unsigned offset, object old, object new_) @@ -2545,10 +2575,12 @@ monitorRelease(Thread* t, object monitor) Thread* next = monitorAtomicPollAcquire(t, monitor, false); - if (next) { + if (next and acquireSystem(t, next)) { ACQUIRE(t, next->lock); next->lock->notify(t->systemThread); + + releaseSystem(t, next); } } } @@ -2833,36 +2865,6 @@ notifyAll(Thread* t, object o) } } -inline bool -zombified(Thread* t) -{ - return t->state == Thread::ZombieState - or t->state == Thread::JoinedState; -} - -inline bool -acquireSystem(Thread* t, Thread* target) -{ - ACQUIRE_RAW(t, t->m->stateLock); - - if (not zombified(target)) { - atomicOr(&(target->flags), Thread::SystemFlag); - return true; - } else { - return false; - } -} - -inline void -releaseSystem(Thread* t, Thread* target) -{ - ACQUIRE_RAW(t, t->m->stateLock); - - assert(t, not zombified(target)); - - atomicAnd(&(target->flags), ~Thread::SystemFlag); -} - inline void interrupt(Thread* t, Thread* target) { From d18240cbd6679bb706cc2e00a4429b950e9c8eb6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 19 Dec 2010 15:23:19 -0700 Subject: [PATCH 175/274] check for stack overflow on entry to all non-leaf methods We now check for stack overflow in the JIT build as well as the interpreted build, throwing a StackOverflowError if the limit (currently hard-coded to 64KB, but should be easy to make configurable) is exceeded. --- src/bootimage.cpp | 2 +- src/bootimage.h | 2 + src/compile.cpp | 92 +++++++++++++++++++++++++++++++++++++++-- src/compiler.cpp | 25 +++++++---- src/compiler.h | 3 +- src/interpret.cpp | 21 ++++------ src/machine.h | 3 ++ test/StackOverflow.java | 29 +++++++++++++ 8 files changed, 152 insertions(+), 25 deletions(-) create mode 100644 test/StackOverflow.java diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 252028dd79..cd0092f0d5 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -30,7 +30,7 @@ const unsigned HeapCapacity = 768 * 1024 * 1024; // One of the advantages of a bootimage-based build is that reduces // the overhead of major GCs at runtime since we can avoid scanning // the pre-built heap image entirely. However, this only works if we -// can ensure that no part of the heap image (with an exception noted +// can ensure that no part of the heap image (with exceptions noted // below) ever points to runtime-allocated objects. Therefore (most) // references in the heap image are considered immutable, and any // attempt to update them at runtime will cause the process to abort. diff --git a/src/bootimage.h b/src/bootimage.h index 14e436ba3d..a5ed58bb61 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -45,6 +45,7 @@ class BootImage { Thunk defaultVirtual; Thunk native; Thunk aioob; + Thunk stackOverflow; Thunk table; }; @@ -75,6 +76,7 @@ class BootImage { unsigned compileVirtualMethodCall; unsigned invokeNativeCall; unsigned throwArrayIndexOutOfBoundsCall; + unsigned throwStackOverflowCall; #define THUNK(s) unsigned s##Call; #include "thunks.cpp" diff --git a/src/compile.cpp b/src/compile.cpp index 6cdd70f5e7..3268e8c645 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -225,7 +225,8 @@ class MyThread: public Thread { ? parent->arch : makeArchitecture(m->system, useNativeFeatures)), transition(0), - traceContext(0) + traceContext(0), + stackLimit(0) { arch->acquire(); } @@ -245,6 +246,7 @@ class MyThread: public Thread { Assembler::Architecture* arch; Context* transition; TraceContext* traceContext; + uintptr_t stackLimit; }; void @@ -1118,6 +1120,7 @@ class Context { objectPoolCount(0), traceLogCount(0), dirtyRoots(false), + leaf(true), eventLog(t->m->system, t->m->heap, 1024), protector(this) { } @@ -1139,6 +1142,7 @@ class Context { objectPoolCount(0), traceLogCount(0), dirtyRoots(false), + leaf(true), eventLog(t->m->system, t->m->heap, 0), protector(this) { } @@ -1164,6 +1168,7 @@ class Context { unsigned objectPoolCount; unsigned traceLogCount; bool dirtyRoots; + bool leaf; Vector eventLog; MyProtector protector; }; @@ -2099,6 +2104,9 @@ bootNativeThunk(MyThread* t); uintptr_t aioobThunk(MyThread* t); +uintptr_t +stackOverflowThunk(MyThread* t); + uintptr_t virtualThunk(MyThread* t, unsigned index); @@ -2611,6 +2619,14 @@ throwArrayIndexOutOfBounds(MyThread* t) unwind(t); } +void NO_RETURN +throwStackOverflow(MyThread* t) +{ + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); + + unwind(t); +} + void NO_RETURN throw_(MyThread* t, object o) { @@ -4121,6 +4137,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokeinterface: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); ip += 2; @@ -4162,6 +4180,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokespecial: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); if (UNLIKELY(t->exception)) return; @@ -4179,6 +4199,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokestatic: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); @@ -4193,6 +4215,8 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } break; case invokevirtual: { + context->leaf = false; + uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); @@ -5745,7 +5769,9 @@ finish(MyThread* t, Allocator* allocator, Context* context) // parallelism (the downside being that it may end up being a waste // of cycles if another thread compiles the same method in parallel, // which might be mitigated by fine-grained, per-method locking): - unsigned codeSize = c->compile(); + unsigned codeSize = c->compile + (context->leaf ? 0 : stackOverflowThunk(t), + difference(&(t->stackLimit), t)); uintptr_t* code = static_cast (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); @@ -7091,7 +7117,16 @@ object invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread* t = static_cast(thread); - + + uintptr_t stackLimit = t->stackLimit; + uintptr_t stackPosition = reinterpret_cast(&t); + if (stackLimit == 0) { + t->stackLimit = stackPosition - StackSizeInBytes; + } else if (stackPosition < stackLimit) { + t->exception = makeThrowable(t, Machine::StackOverflowErrorType); + return 0; + } + unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); @@ -7111,6 +7146,8 @@ invoke(Thread* thread, object method, ArgumentList* arguments) returnType); } + t->stackLimit = stackLimit; + if (t->exception) { if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); @@ -7243,6 +7280,7 @@ class MyProcessor: public Processor { Thunk defaultVirtual; Thunk native; Thunk aioob; + Thunk stackOverflow; Thunk table; }; @@ -7801,7 +7839,7 @@ isThunkUnsafeStack(MyProcessor::Thunk* thunk, void* ip) bool isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) { - const unsigned NamedThunkCount = 4; + const unsigned NamedThunkCount = 5; MyProcessor::Thunk table[NamedThunkCount + ThunkCount]; @@ -7809,6 +7847,7 @@ isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) table[1] = thunks->defaultVirtual; table[2] = thunks->native; table[3] = thunks->aioob; + table[4] = thunks->stackOverflow; for (unsigned i = 0; i < ThunkCount; ++i) { new (table + NamedThunkCount + i) MyProcessor::Thunk @@ -8137,6 +8176,8 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) = thunkToThunk(image->thunks.defaultVirtual, 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); p->bootThunks.table = thunkToThunk(image->thunks.table, code); updateCall(t, LongCall, code + image->compileMethodCall, @@ -8151,6 +8192,9 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) updateCall(t, LongCall, code + image->throwArrayIndexOutOfBoundsCall, voidPointer(throwArrayIndexOutOfBounds)); + updateCall(t, LongCall, code + image->throwStackOverflowCall, + voidPointer(throwStackOverflow)); + #define THUNK(s) \ updateCall(t, LongJump, code + image->s##Call, voidPointer(s)); @@ -8391,6 +8435,23 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) p->thunks.aioob.length = a->endBlock(false)->resolve(0, 0); } + ThunkContext stackOverflowContext(t, &zone); + + { Assembler* a = stackOverflowContext.context.assembler; + + a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + + p->thunks.stackOverflow.frameSavedOffset = a->length(); + + Assembler::Register thread(t->arch->thread()); + a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); + + Assembler::Constant proc(&(stackOverflowContext.promise)); + a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); + + p->thunks.stackOverflow.length = a->endBlock(false)->resolve(0, 0); + } + ThunkContext tableContext(t, &zone); { Assembler* a = tableContext.context.assembler; @@ -8463,6 +8524,21 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) } } + p->thunks.stackOverflow.start = finish + (t, allocator, stackOverflowContext.context.assembler, "stackOverflow", + p->thunks.stackOverflow.length); + + { void* call; + stackOverflowContext.promise.listener->resolve + (reinterpret_cast(voidPointer(throwStackOverflow)), + &call); + + if (image) { + image->throwStackOverflowCall + = static_cast(call) - imageBase; + } + } + p->thunks.table.start = static_cast (allocator->allocate(p->thunks.table.length * ThunkCount)); @@ -8472,6 +8548,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) = thunkToThunk(p->thunks.defaultVirtual, imageBase); image->thunks.native = thunkToThunk(p->thunks.native, imageBase); image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase); + image->thunks.stackOverflow + = thunkToThunk(p->thunks.stackOverflow, imageBase); image->thunks.table = thunkToThunk(p->thunks.table, imageBase); } @@ -8539,6 +8617,12 @@ aioobThunk(MyThread* t) return reinterpret_cast(processor(t)->thunks.aioob.start); } +uintptr_t +stackOverflowThunk(MyThread* t) +{ + return reinterpret_cast(processor(t)->thunks.stackOverflow.start); +} + bool unresolved(MyThread* t, uintptr_t methodAddress) { diff --git a/src/compiler.cpp b/src/compiler.cpp index 23778520d6..1cbc55bc75 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4919,8 +4919,7 @@ class BoundsCheckEvent: public Event { lengthOffset, NoRegister, 1); length.acquired = true; - CodePromise* nextPromise = codePromise - (c, static_cast(0)); + CodePromise* nextPromise = codePromise(c, static_cast(0)); freezeSource(c, BytesPerWord, index); @@ -5649,7 +5648,7 @@ block(Context* c, Event* head) } unsigned -compile(Context* c) +compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { appendDummy(c); @@ -5660,6 +5659,15 @@ compile(Context* c) Block* firstBlock = block(c, c->firstEvent); Block* block = firstBlock; + if (stackOverflowHandler) { + Assembler::Register stack(c->arch->stack()); + Assembler::Memory stackLimit(c->arch->thread(), stackLimitOffset); + Assembler::Constant handler(resolved(c, stackOverflowHandler)); + a->apply(JumpIfGreaterOrEqual, BytesPerWord, RegisterOperand, &stack, + BytesPerWord, MemoryOperand, &stackLimit, + BytesPerWord, ConstantOperand, &handler); + } + a->allocateFrame(c->alignedFrameSize); for (Event* e = c->firstEvent; e; e = e->next) { @@ -6406,8 +6414,8 @@ class MyCompiler: public Compiler { virtual void checkBounds(Operand* object, unsigned lengthOffset, Operand* index, intptr_t handler) { - appendBoundsCheck(&c, static_cast(object), - lengthOffset, static_cast(index), handler); + appendBoundsCheck(&c, static_cast(object), lengthOffset, + static_cast(index), handler); } virtual void store(unsigned srcSize, Operand* src, unsigned dstSize, @@ -6827,8 +6835,11 @@ class MyCompiler: public Compiler { appendBarrier(&c, StoreLoadBarrier); } - virtual unsigned compile() { - return c.machineCodeSize = local::compile(&c); + virtual unsigned compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) + { + return c.machineCodeSize = local::compile + (&c, stackOverflowHandler, stackLimitOffset); } virtual unsigned poolSize() { diff --git a/src/compiler.h b/src/compiler.h index e0c94b1b2d..1850baca0b 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -188,7 +188,8 @@ class Compiler { virtual void storeStoreBarrier() = 0; virtual void storeLoadBarrier() = 0; - virtual unsigned compile() = 0; + virtual unsigned compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) = 0; virtual unsigned poolSize() = 0; virtual void writeTo(uint8_t* dst) = 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index e9d4c418c1..bc5cb36898 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -30,9 +30,6 @@ class ClassInitList; class Thread: public vm::Thread { public: - static const unsigned StackSizeInBytes = 64 * 1024; - static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; - Thread(Machine* m, object javaThread, vm::Thread* parent): vm::Thread(m, javaThread, parent), ip(0), @@ -78,7 +75,7 @@ pushObject(Thread* t, object o) fprintf(stderr, "push object %p at %d\n", o, t->sp); } - assert(t, t->sp + 1 < Thread::StackSizeInWords / 2); + assert(t, t->sp + 1 < StackSizeInWords / 2); t->stack[(t->sp * 2) ] = ObjectTag; t->stack[(t->sp * 2) + 1] = reinterpret_cast(o); ++ t->sp; @@ -91,7 +88,7 @@ pushInt(Thread* t, uint32_t v) fprintf(stderr, "push int %d at %d\n", v, t->sp); } - assert(t, t->sp + 1 < Thread::StackSizeInWords / 2); + assert(t, t->sp + 1 < StackSizeInWords / 2); t->stack[(t->sp * 2) ] = IntTag; t->stack[(t->sp * 2) + 1] = v; ++ t->sp; @@ -184,7 +181,7 @@ peekObject(Thread* t, unsigned index) index); } - assert(t, index < Thread::StackSizeInWords / 2); + assert(t, index < StackSizeInWords / 2); assert(t, t->stack[index * 2] == ObjectTag); return *reinterpret_cast(t->stack + (index * 2) + 1); } @@ -198,7 +195,7 @@ peekInt(Thread* t, unsigned index) index); } - assert(t, index < Thread::StackSizeInWords / 2); + assert(t, index < StackSizeInWords / 2); assert(t, t->stack[index * 2] == IntTag); return t->stack[(index * 2) + 1]; } @@ -254,7 +251,7 @@ inline object* pushReference(Thread* t, object o) { if (o) { - expect(t, t->sp + 1 < Thread::StackSizeInWords / 2); + expect(t, t->sp + 1 < StackSizeInWords / 2); pushObject(t, o); return reinterpret_cast(t->stack + ((t->sp - 1) * 2) + 1); } else { @@ -436,7 +433,7 @@ checkStack(Thread* t, object method) + codeMaxLocals(t, methodCode(t, method)) + FrameFootprint + codeMaxStack(t, methodCode(t, method)) - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { t->exception = makeThrowable(t, Machine::StackOverflowErrorType); } @@ -3136,7 +3133,7 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; @@ -3161,7 +3158,7 @@ class MyProcessor: public Processor { assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; @@ -3185,7 +3182,7 @@ class MyProcessor: public Processor { or t->state == Thread::ExclusiveState); if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) - > Thread::StackSizeInWords / 2)) + > StackSizeInWords / 2)) { t->exception = makeThrowable(t, Machine::StackOverflowErrorType); return 0; diff --git a/src/machine.h b/src/machine.h index 3333cb084a..d4a381b082 100644 --- a/src/machine.h +++ b/src/machine.h @@ -56,6 +56,9 @@ const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; const unsigned ThreadBackupHeapSizeInWords = ThreadBackupHeapSizeInBytes / BytesPerWord; +const unsigned StackSizeInBytes = 64 * 1024; +const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; + const unsigned ThreadHeapPoolSize = 64; const unsigned FixedFootprintThresholdInBytes diff --git a/test/StackOverflow.java b/test/StackOverflow.java new file mode 100644 index 0000000000..0a26217e65 --- /dev/null +++ b/test/StackOverflow.java @@ -0,0 +1,29 @@ +public class StackOverflow { + private static void test1() { + test1(); + } + + private static void test2() { + test3(); + } + + private static void test3() { + test2(); + } + + public static void main(String[] args) { + try { + test1(); + throw new RuntimeException(); + } catch (StackOverflowError e) { + e.printStackTrace(); + } + + try { + test2(); + throw new RuntimeException(); + } catch (StackOverflowError e) { + e.printStackTrace(); + } + } +} From 306f1282d066caa671cef6853b9dd2a7f506979d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 19 Dec 2010 17:47:21 -0700 Subject: [PATCH 176/274] throw ArithmeticException on divide-by-zero --- src/compile.cpp | 104 +++++++++++++++++++++++++------ src/compiler.cpp | 58 ++++++++++++------ src/compiler.h | 2 +- src/interpret.cpp | 20 ++++++ src/jnienv.cpp | 9 ++- src/machine.h | 1 + src/posix.cpp | 32 ++++++++-- src/system.h | 1 + src/types.def | 2 + src/windows.cpp | 95 ++++++++++++++++++++--------- test/DivideByZero.java | 135 +++++++++++++++++++++++++++++++++++++++++ vm.pro | 1 + 12 files changed, 386 insertions(+), 74 deletions(-) create mode 100644 test/DivideByZero.java diff --git a/src/compile.cpp b/src/compile.cpp index 3268e8c645..686d68e1f0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1017,14 +1017,20 @@ class Context { } } - virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned) { + virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned, + bool* threadParameter) + { + *threadParameter = false; + if (size == 8) { switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideLongThunk); case Remainder: - return local::getThunk(t, moduloLongThunk); + *threadParameter = true; + return local::getThunk(t, moduloLongThunk); case FloatAdd: return local::getThunk(t, addDoubleThunk); @@ -1061,9 +1067,11 @@ class Context { assert(t, size == 4); switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideIntThunk); case Remainder: + *threadParameter = true; return local::getThunk(t, moduloIntThunk); case FloatAdd: @@ -2358,26 +2366,47 @@ absoluteInt(int32_t a) } int64_t -divideLong(int64_t b, int64_t a) +divideLong(MyThread* t, int64_t b, int64_t a) { - return a / b; + if (LIKELY(b)) { + return a / b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -divideInt(int32_t b, int32_t a) +divideInt(MyThread* t, int32_t b, int32_t a) { - return a / b; + if (LIKELY(b)) { + return a / b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -moduloLong(int64_t b, int64_t a) +moduloLong(MyThread* t, int64_t b, int64_t a) { - return a % b; + if (LIKELY(b)) { + return a % b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -moduloInt(int32_t b, int32_t a) { - return a % b; +moduloInt(MyThread* t, int32_t b, int32_t a) +{ + if (LIKELY(b)) { + return a % b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } uint64_t @@ -3949,6 +3978,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case idiv: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->div(4, a, b)); } break; @@ -4262,6 +4297,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case irem: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->rem(4, a, b)); } break; @@ -4459,6 +4500,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ldiv_: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->div(8, a, b)); } break; @@ -4564,6 +4611,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case lrem: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->rem(8, a, b)); } break; @@ -7186,9 +7239,10 @@ invoke(Thread* thread, object method, ArgumentList* arguments) return r; } -class SegFaultHandler: public System::SignalHandler { +class SignalHandler: public System::SignalHandler { public: - SegFaultHandler(): m(0) { } + SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): + m(0), type(type), root(root), fixedSize(fixedSize) { } virtual bool handleSignal(void** ip, void** base, void** stack, void** thread) @@ -7204,14 +7258,14 @@ class SegFaultHandler: public System::SignalHandler { static_cast(*stack) - t->arch->frameReturnAddressSize(), *base, t->continuation, t->trace); - if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { + if (ensure(t, fixedSize + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, type); atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { - // not enough memory available for a new NPE and stack trace - // -- use a preallocated instance instead - t->exception = root(t, Machine::NullPointerException); + // not enough memory available for a new exception and stack + // trace -- use a preallocated instance instead + t->exception = vm::root(t, root); } // printTrace(t, t->exception); @@ -7235,6 +7289,9 @@ class SegFaultHandler: public System::SignalHandler { } Machine* m; + Machine::Type type; + Machine::Root root; + unsigned fixedSize; }; bool @@ -7289,6 +7346,12 @@ class MyProcessor: public Processor { allocator(allocator), roots(0), bootImage(0), + segFaultHandler(Machine::NullPointerExceptionType, + Machine::NullPointerException, + FixedSizeOfNullPointerException), + divideByZeroHandler(Machine::ArithmeticExceptionType, + Machine::ArithmeticException, + FixedSizeOfArithmeticException), codeAllocator(s, 0, 0), callTableSize(0), useNativeFeatures(useNativeFeatures) @@ -7744,6 +7807,10 @@ class MyProcessor: public Processor { segFaultHandler.m = t->m; expect(t, t->m->system->success (t->m->system->handleSegFault(&segFaultHandler))); + + divideByZeroHandler.m = t->m; + expect(t, t->m->system->success + (t->m->system->handleDivideByZero(÷ByZeroHandler))); } virtual void callWithCurrentContinuation(Thread* t, object receiver) { @@ -7798,7 +7865,8 @@ class MyProcessor: public Processor { Allocator* allocator; object roots; BootImage* bootImage; - SegFaultHandler segFaultHandler; + SignalHandler segFaultHandler; + SignalHandler divideByZeroHandler; FixedAllocator codeAllocator; ThunkCollection thunks; ThunkCollection bootThunks; diff --git a/src/compiler.cpp b/src/compiler.cpp index 1cbc55bc75..ed918ae7b2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4336,6 +4336,19 @@ loadLocal(Context* c, unsigned footprint, unsigned index) return c->locals[index].value; } +Value* +register_(Context* c, int number) +{ + assert(c, (1 << number) & (c->arch->generalRegisterMask() + | c->arch->floatRegisterMask())); + + Site* s = registerSite(c, number); + ValueType type = ((1 << number) & c->arch->floatRegisterMask()) + ? ValueFloat: ValueGeneral; + + return value(c, type, s, s); +} + void appendCombine(Context* c, TernaryOperation type, unsigned firstSize, Value* first, @@ -4349,25 +4362,34 @@ appendCombine(Context* c, TernaryOperation type, uint64_t secondRegisterMask; c->arch->planSource(type, firstSize, &firstTypeMask, &firstRegisterMask, - secondSize, &secondTypeMask, &secondRegisterMask, - resultSize, &thunk); + secondSize, &secondTypeMask, &secondRegisterMask, + resultSize, &thunk); if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, firstSize, resultSize, &threadParameter); + + unsigned stackSize = ceiling(secondSize, BytesPerWord) + + ceiling(firstSize, BytesPerWord); + local::push(c, ceiling(secondSize, BytesPerWord), second); local::push(c, ceiling(firstSize, BytesPerWord), first); + if (threadParameter) { + ++ stackSize; + + local::push(c, 1, register_(c, c->arch->thread())); + } + Stack* argumentStack = c->stack; c->stack = oldStack; appendCall - (c, value - (c, ValueGeneral, constantSite - (c, c->client->getThunk(type, firstSize, resultSize))), - 0, 0, result, resultSize, argumentStack, - ceiling(secondSize, BytesPerWord) + ceiling(firstSize, BytesPerWord), - 0); + (c, value(c, ValueGeneral, constantSite(c, handler)), 0, 0, result, + resultSize, argumentStack, stackSize, 0); } else { append (c, new (c->zone->allocate(sizeof(CombineEvent))) @@ -4792,6 +4814,12 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, size, size, &threadParameter); + + assert(c, not threadParameter); + local::push(c, ceiling(size, BytesPerWord), second); local::push(c, ceiling(size, BytesPerWord), first); @@ -4801,9 +4829,8 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, Value* result = value(c, ValueGeneral); appendCall (c, value - (c, ValueGeneral, constantSite(c, c->client->getThunk(type, size, 4))), - 0, 0, result, 4, argumentStack, - ceiling(size, BytesPerWord) * 2, 0); + (c, ValueGeneral, constantSite(c, handler)), 0, 0, result, 4, + argumentStack, ceiling(size, BytesPerWord) * 2, 0); appendBranch(c, thunkBranch(c, type), 4, value (c, ValueGeneral, constantSite(c, static_cast(0))), @@ -6167,14 +6194,7 @@ class MyCompiler: public Compiler { } virtual Operand* register_(int number) { - assert(&c, (1 << number) & (c.arch->generalRegisterMask() - | c.arch->floatRegisterMask())); - - Site* s = registerSite(&c, number); - ValueType type = ((1 << number) & c.arch->floatRegisterMask()) - ? ValueFloat: ValueGeneral; - - return value(&c, type, s, s); + return local::register_(&c, number); } Promise* machineIp() { diff --git a/src/compiler.h b/src/compiler.h index 1850baca0b..282941b722 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -30,7 +30,7 @@ class Compiler { virtual intptr_t getThunk(BinaryOperation op, unsigned size, unsigned resultSize) = 0; virtual intptr_t getThunk(TernaryOperation op, unsigned size, - unsigned resultSize) = 0; + unsigned resultSize, bool* threadParameter) = 0; }; static const unsigned Aligned = 1 << 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index bc5cb36898..fd1bbcbcf3 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1665,6 +1665,11 @@ interpret(Thread* t) case idiv: { int32_t b = popInt(t); int32_t a = popInt(t); + + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } pushInt(t, a / b); } goto loop; @@ -1968,6 +1973,11 @@ interpret(Thread* t) int32_t b = popInt(t); int32_t a = popInt(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushInt(t, a % b); } goto loop; @@ -2187,6 +2197,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a / b); } goto loop; @@ -2269,6 +2284,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a % b); } goto loop; diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 38598a385a..43baf82d92 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2035,8 +2035,13 @@ boot(Thread* t) (t, Machine::NullPointerExceptionType)); if (t->exception == 0) { - setRoot(t, Machine::ArrayIndexOutOfBoundsException, - makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + setRoot(t, Machine::ArithmeticException, + makeThrowable(t, Machine::ArithmeticExceptionType)); + + if (t->exception == 0) { + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + } } } diff --git a/src/machine.h b/src/machine.h index d4a381b082..4070c99e80 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1203,6 +1203,7 @@ class Machine { ShutdownHooks, ObjectsToFinalize, NullPointerException, + ArithmeticException, ArrayIndexOutOfBoundsException, VirtualFileFinders, VirtualFiles diff --git a/src/posix.cpp b/src/posix.cpp index b4b833cb62..4439feea01 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -69,14 +69,17 @@ const int AltSegFaultSignal = InvalidSignal; const unsigned AltSegFaultSignalIndex = 3; const int PipeSignal = SIGPIPE; const unsigned PipeSignalIndex = 4; +const int DivideByZeroSignal = SIGFPE; +const unsigned DivideByZeroSignalIndex = 5; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal, AltSegFaultSignal, - PipeSignal }; + PipeSignal, + DivideByZeroSignal }; -const unsigned SignalCount = 5; +const unsigned SignalCount = 6; class MySystem; MySystem* system; @@ -530,6 +533,8 @@ class MySystem: public System { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + registerHandler(&nullHandler, InterruptSignalIndex); registerHandler(&nullHandler, PipeSignalIndex); registerHandler(&nullHandler, VisitSignalIndex); @@ -631,6 +636,10 @@ class MySystem: public System { return s; } + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroSignalIndex); + } + virtual Status visit(System::Thread* st, System::Thread* sTarget, ThreadVisitor* visitor) { @@ -847,12 +856,25 @@ handleSignal(int signal, siginfo_t* info, void* context) } break; case SegFaultSignal: - case AltSegFaultSignal: { - if (signal == SegFaultSignal) { + case AltSegFaultSignal: + case DivideByZeroSignal: { + switch (signal) { + case SegFaultSignal: index = SegFaultSignalIndex; - } else { + break; + + case AltSegFaultSignal: index = AltSegFaultSignalIndex; + break; + + case DivideByZeroSignal: + index = DivideByZeroSignalIndex; + break; + + default: + abort(); } + bool jump = system->handlers[index]->handleSignal (&ip, &base, &stack, &thread); diff --git a/src/system.h b/src/system.h index 95e025f433..315f7151d2 100644 --- a/src/system.h +++ b/src/system.h @@ -126,6 +126,7 @@ class System { virtual Status make(Monitor**) = 0; virtual Status make(Local**) = 0; virtual Status handleSegFault(SignalHandler* handler) = 0; + virtual Status handleDivideByZero(SignalHandler* handler) = 0; virtual Status visit(Thread* thread, Thread* target, ThreadVisitor* visitor) = 0; virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, diff --git a/src/types.def b/src/types.def index b16cd79bf9..8b8d980ffc 100644 --- a/src/types.def +++ b/src/types.def @@ -205,6 +205,8 @@ (type nullPointerException java/lang/NullPointerException) +(type arithmeticException java/lang/ArithmeticException) + (type illegalStateException java/lang/IllegalStateException) (type illegalArgumentException java/lang/IllegalArgumentException) diff --git a/src/windows.cpp b/src/windows.cpp index 52c95f2bd0..b86d2fa99e 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -49,6 +49,11 @@ class MutexResource { HANDLE m; }; +const unsigned SegFaultIndex = 0; +const unsigned DivideByZeroIndex = 1; + +const unsigned HandlerCount = 2; + class MySystem; MySystem* system; @@ -510,17 +515,57 @@ class MySystem: public System { }; MySystem(const char* crashDumpDirectory): - segFaultHandler(0), - oldSegFaultHandler(0), + oldHandler(0), crashDumpDirectory(crashDumpDirectory) { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + mutex = CreateMutex(0, false, 0); assert(this, mutex); } + bool findHandler() { + for (unsigned i = 0; i < HandlerCount; ++i) { + if (handlers[i]) return true; + } + return false; + } + + int registerHandler(System::SignalHandler* handler, int index) { + if (handler) { + handlers[index] = handler; + + if (oldHandler == 0) { +#ifdef ARCH_x86_32 + oldHandler = SetUnhandledExceptionFilter(handleException); +#elif defined ARCH_x86_64 + AddVectoredExceptionHandler(1, handleException); + oldHandler = reinterpret_cast(1); +#endif + } + + return 0; + } else if (handlers[index]) { + handlers[index] = 0; + + if (not findHandler()) { +#ifdef ARCH_x86_32 + SetUnhandledExceptionFilter(oldHandler); + oldHandler = 0; +#elif defined ARCH_x86_64 + // do nothing, handlers are never "unregistered" anyway +#endif + } + + return 0; + } else { + return 1; + } + } + virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } @@ -578,27 +623,11 @@ class MySystem: public System { } virtual Status handleSegFault(SignalHandler* handler) { - if (handler) { - segFaultHandler = handler; + return registerHandler(handler, SegFaultIndex); + } -#ifdef ARCH_x86_32 - oldSegFaultHandler = SetUnhandledExceptionFilter(handleException); -#elif defined ARCH_x86_64 - AddVectoredExceptionHandler(1, handleException); - oldSegFaultHandler = 0; -#endif - return 0; - } else if (segFaultHandler) { - segFaultHandler = 0; -#ifdef ARCH_x86_32 - SetUnhandledExceptionFilter(oldSegFaultHandler); -#elif defined ARCH_x86_64 - //do nothing, handlers are never "unregistered" anyway -#endif - return 0; - } else { - return 1; - } + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroIndex); } virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, @@ -795,8 +824,8 @@ class MySystem: public System { } HANDLE mutex; - System::SignalHandler* segFaultHandler; - LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler; + SignalHandler* handlers[HandlerCount]; + LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; const char* crashDumpDirectory; }; @@ -867,7 +896,15 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { + System::SignalHandler* handler = 0; if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + handler = system->handlers[SegFaultIndex]; + } else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) + { + handler = system->handlers[DivideByZeroIndex]; + } + + if (handler) { #ifdef ARCH_x86_32 void* ip = reinterpret_cast(e->ContextRecord->Eip); void* base = reinterpret_cast(e->ContextRecord->Ebp); @@ -880,8 +917,8 @@ handleException(LPEXCEPTION_POINTERS e) void* thread = reinterpret_cast(e->ContextRecord->Rbx); #endif - bool jump = system->segFaultHandler->handleSignal - (&ip, &base, &stack, &thread); + bool jump = handler->handleSignal(&ip, &base, &stack, &thread); + #ifdef ARCH_x86_32 e->ContextRecord->Eip = reinterpret_cast(ip); e->ContextRecord->Ebp = reinterpret_cast(base); @@ -897,10 +934,10 @@ handleException(LPEXCEPTION_POINTERS e) if (jump) { return EXCEPTION_CONTINUE_EXECUTION; } + } - if (system->crashDumpDirectory) { - dump(e, system->crashDumpDirectory); - } + if (system->crashDumpDirectory) { + dump(e, system->crashDumpDirectory); } return EXCEPTION_CONTINUE_SEARCH; diff --git a/test/DivideByZero.java b/test/DivideByZero.java new file mode 100644 index 0000000000..80f308adcb --- /dev/null +++ b/test/DivideByZero.java @@ -0,0 +1,135 @@ +public class DivideByZero { + private static int divide(int n, int d) { + return n / d; + } + + private static int modulo(int n, int d) { + return n % d; + } + + private static long divide(long n, long d) { + return n / d; + } + + private static long modulo(long n, long d) { + return n % d; + } + + private static float divide(float n, float d) { + return n / d; + } + + private static float modulo(float n, float d) { + return n % d; + } + + private static double divide(double n, double d) { + return n / d; + } + + private static double modulo(double n, double d) { + return n % d; + } + + public static void main(String[] args) { + try { + int x = 1 / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int x = 1 % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + divide(5F, 0F); + modulo(6F, 0F); + + divide(5D, 0D); + modulo(6D, 0D); + } +} diff --git a/vm.pro b/vm.pro index edfd2e1679..e382722b5a 100644 --- a/vm.pro +++ b/vm.pro @@ -57,6 +57,7 @@ -keep public class java.lang.ClassCastException -keep public class java.lang.ClassNotFoundException -keep public class java.lang.NullPointerException +-keep public class java.lang.ArithmeticException -keep public class java.lang.InterruptedException -keep public class java.lang.StackOverflowError -keep public class java.lang.NoSuchFieldError From 74d2afd707293762f6500058b4d6391cfd99e2dc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 12:11:29 -0700 Subject: [PATCH 177/274] use "no-underscore" naming convention for 64-bit Windows GCC 4.5.1 and later use a naming convention where functions are not prefixed with an underscore, whereas previous versions added the underscore. This change was made to ensure compatibility with Microsoft's compiler. Since GCC 4.5.0 has a serious code generation bug, we now only support later versions, so it makes sense to assume the newer convention. --- readme.txt | 2 +- src/boot.cpp | 4 ++-- src/compile-x86.S | 3 ++- src/x86.S | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/readme.txt b/readme.txt index 6a611da785..f8b7a51e06 100644 --- a/readme.txt +++ b/readme.txt @@ -62,7 +62,7 @@ Building Build requirements include: * GNU make 3.80 or later - * GCC 3.4 or later (4.5 or later for Windows/x86_64) + * GCC 3.4 or later (4.5.1 or later for Windows/x86_64) * JDK 1.5 or later * MinGW 3.4 or later (only if compiling for Windows) * zlib 1.2.3 or later diff --git a/src/boot.cpp b/src/boot.cpp index 1535584ace..7e074c0a14 100644 --- a/src/boot.cpp +++ b/src/boot.cpp @@ -32,7 +32,7 @@ extern "C" void __cxa_pure_virtual(void) { abort(); } #ifdef BOOT_IMAGE -#if (defined __MINGW32__) || (defined _MSC_VER) +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_bootimage_bin_##x #else # define SYMBOL(x) _binary_bootimage_bin_##x @@ -58,7 +58,7 @@ extern "C" { #ifdef BOOT_CLASSPATH -#if (defined __MINGW32__) || (defined _MSC_VER) +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) # define SYMBOL(x) binary_classpath_jar_##x #else # define SYMBOL(x) _binary_classpath_jar_##x diff --git a/src/compile-x86.S b/src/compile-x86.S index 07da66ae3f..41a0d2ae07 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -12,7 +12,8 @@ #define LOCAL(x) .L##x -#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +#if defined __APPLE__ \ + || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x diff --git a/src/x86.S b/src/x86.S index ebee7a4474..552e093bdc 100644 --- a/src/x86.S +++ b/src/x86.S @@ -12,7 +12,8 @@ #define LOCAL(x) .L##x -#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__ +#if defined __APPLE__ \ + || ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__) # define GLOBAL(x) _##x #else # define GLOBAL(x) x From 5d5a18c482283dcd327c342cde7a04050c901691 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 16:49:45 -0700 Subject: [PATCH 178/274] set Thread::exception to null before creating ExceptionInInitializerError If we don't do this, the VM will crash when it tries to create a stack trace for the error because makeObjectArray will return null immediately when it sees there is a pending exception. --- src/machine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/machine.cpp b/src/machine.cpp index 98835556bf..5614a4ccb1 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3436,8 +3436,10 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { + object exception = t->exception; + t->exception = 0; t->exception = makeThrowable - (t, Machine::ExceptionInInitializerErrorType, 0, 0, t->exception); + (t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; @@ -3882,6 +3884,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker) virtual bool visit(Processor::StackWalker* walker) { if (trace == 0) { trace = makeObjectArray(t, walker->count()); + vm_assert(t, trace); } object e = makeTraceElement(t, walker->method(), walker->ip()); From 857dcd13e7b5113178ea615f57f05fac87d6466b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 18:08:52 -0700 Subject: [PATCH 179/274] fix 64-bit constant comparisons on 32-bit platforms --- src/compiler.cpp | 14 +++++++++++--- test/Longs.java | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/compiler.cpp b/src/compiler.cpp index 23778520d6..1a96292b96 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4741,9 +4741,17 @@ class BranchEvent: public Event { if (not unreachable(this)) { if (firstConstant and secondConstant) { - if (shouldJump(c, type, size, firstConstant->value->value(), - secondConstant->value->value())) - { + int64_t firstValue = firstConstant->value->value(); + int64_t secondValue = secondConstant->value->value(); + + if (size > BytesPerWord) { + firstValue |= findConstantSite + (c, first->nextWord)->value->value() << 32; + secondValue |= findConstantSite + (c, second->nextWord)->value->value() << 32; + } + + if (shouldJump(c, type, size, firstValue, secondValue)) { apply(c, Jump, BytesPerWord, address->source, address->source); } } else { diff --git a/test/Longs.java b/test/Longs.java index 8c34fddce9..9beaf8a996 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -60,6 +60,11 @@ public class Longs { } public static void main(String[] args) throws Exception { + { long a = 0x1FFFFFFFFL; + long b = -1; + expect(a != b); + } + expect(Math.abs(-123L) == 123L); expect(readLongFrom(new java.io.InputStream() { From 2e86f0ac5727a856e61138ed94334ad29d8d10cd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Dec 2010 19:00:23 -0700 Subject: [PATCH 180/274] fix race condition leading to deadlock on exit There is a delay between when we tell the OS to start a thread and when it actually starts, and during that time a thread might mistakenly think it was the last to exit, try to shut down the VM, and then block in joinAll when it finds it wasn't the last one after all. The solution is to increment Machine::liveCount and add the new thread to the process tree before starting it -- all while holding Machine::stateLock for atomicity. This helps guarantee that when liveCount is one, we can be sure there's really only one thread running or staged to run. --- src/machine.cpp | 9 +++++---- src/machine.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index 5614a4ccb1..1fade5edbe 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2258,7 +2258,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): vtable(&(m->jniEnvVTable)), m(m), parent(parent), - peer((parent ? parent->child : 0)), + peer(0), child(0), waitNext(0), state(NoState), @@ -2331,9 +2331,6 @@ Thread::init() javaThread = m->classpath->makeThread(this, 0); threadPeer(this, javaThread) = reinterpret_cast(this); - } else { - peer = parent->child; - parent->child = this; } expect(this, m->system->success(m->system->make(&lock))); @@ -2538,6 +2535,7 @@ enter(Thread* t, Thread::State s) -- t->m->daemonCount; } } + t->state = s; t->m->stateLock->notifyAll(t->systemThread); @@ -3739,7 +3737,10 @@ collect(Thread* t, Heap::CollectionType type) m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread); + addThread(t, m->finalizeThread); + if (not startThread(t, m->finalizeThread)) { + removeThread(t, m->finalizeThread); m->finalizeThread = 0; } } diff --git a/src/machine.h b/src/machine.h index 3333cb084a..872416b374 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1753,14 +1753,45 @@ startThread(Thread* t, Thread* p) return t->m->system->success(t->m->system->start(&(p->runnable))); } +inline void +addThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::NoState); + + p->state = Thread::IdleState; + ++ t->m->liveCount; + + p->peer = p->parent->child; + p->parent->child = p; +} + +inline void +removeThread(Thread* t, Thread* p) +{ + ACQUIRE_RAW(t, t->m->stateLock); + + assert(t, p->state == Thread::IdleState); + + -- t->m->liveCount; + + t->m->stateLock->notifyAll(t->systemThread); + + p->parent->child = p->peer; +} + inline Thread* startThread(Thread* t, object javaThread) { Thread* p = t->m->processor->makeThread(t->m, javaThread, t); + addThread(t, p); + if (startThread(t, p)) { return p; } else { + removeThread(t, p); return 0; } } @@ -1791,6 +1822,8 @@ attachThread(Machine* m, bool daemon) Thread* t = m->processor->makeThread(m, 0, m->rootThread); m->system->attach(&(t->runnable)); + addThread(t, t); + enter(t, Thread::ActiveState); t->javaThread = m->classpath->makeThread(t, m->rootThread); From afabe8e07e1b2a5b0cdfbd0b1bed88a94ea68c44 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 27 Dec 2010 15:55:23 -0700 Subject: [PATCH 181/274] rework VM exception handling; throw OOMEs when appropriate This rather large commit modifies the VM to use non-local returns to throw exceptions instead of simply setting Thread::exception and returning frame-by-frame as it used to. This has several benefits: * Functions no longer need to check Thread::exception after each call which might throw an exception (which would be especially tedious and error-prone now that any function which allocates objects directly or indirectly might throw an OutOfMemoryError) * There's no need to audit the code for calls to functions which previously did not throw exceptions but later do * Performance should be improved slightly due to both the reduced need for conditionals and because undwinding now occurs in a single jump instead of a series of returns The main disadvantages are: * Slightly higher overhead for entering and leaving the VM via the JNI and JDK methods * Non-local returns can make the code harder to read * We must be careful to register destructors for stack-allocated resources with the Thread so they can be called prior to a non-local return The non-local return implementation is similar to setjmp/longjmp, except it uses continuation-passing style to avoid the need for cooperation from the C/C++ compiler. Native C++ exceptions would have also been an option, but that would introduce a dependence on libstdc++, which we're trying to avoid for portability reasons. Finally, this commit ensures that the VM throws an OutOfMemoryError instead of aborting when it reaches its memory ceiling. Currently, we treat the ceiling as a soft limit and temporarily exceed it as necessary to allow garbage collection and certain internal allocations to succeed, but refuse to allocate any Java objects until the heap size drops back below the ceiling. --- src/bootimage.cpp | 46 ++- src/builtin.cpp | 31 +- src/classpath-avian.cpp | 50 +-- src/classpath-common.h | 31 +- src/classpath-openjdk.cpp | 828 ++++++++++++++++++++++++-------------- src/compile-x86.S | 4 +- src/compile.cpp | 560 +++++++++++--------------- src/continuations-x86.S | 16 +- src/heap.cpp | 31 +- src/heap.h | 1 + src/interpret.cpp | 267 ++++++------ src/jnienv.cpp | 633 ++++++++++++++++++++--------- src/machine.cpp | 371 +++++++++-------- src/machine.h | 390 ++++++++++++++---- src/process.cpp | 21 +- src/x86.S | 128 +++++- test/OutOfMemory.java | 62 +++ 17 files changed, 2165 insertions(+), 1305 deletions(-) create mode 100644 test/OutOfMemory.java diff --git a/src/bootimage.cpp b/src/bootimage.cpp index cd0092f0d5..4bd1f8a33d 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -92,8 +92,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, (t, root(t, Machine::BootLoader), makeByteArray(t, "%.*s", nameSize - 6, name), true); - if (t->exception) return 0; - PROTECT(t, c); if (classMethodTable(t, c)) { @@ -138,8 +136,6 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass (t, root(t, Machine::BootLoader), referenceName(t, o)); - - if (t->exception) return 0; set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), o); @@ -360,9 +356,9 @@ offset(object a, uintptr_t* b) } void -writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, - unsigned codeCapacity, const char* className, - const char* methodName, const char* methodSpec) +writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, + unsigned codeCapacity, const char* className, + const char* methodName, const char* methodSpec) { Zone zone(t->m->system, t->m->heap, 64 * 1024); @@ -373,8 +369,6 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, object constants = makeCodeImage (t, &zone, image, code, codeMap, className, methodName, methodSpec); - if (t->exception) return; - PROTECT(t, constants); // this map will not be used when the bootimage is loaded, so @@ -505,6 +499,23 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, } } +uint64_t +writeBootImage(Thread* t, uintptr_t* arguments) +{ + FILE* out = reinterpret_cast(arguments[0]); + BootImage* image = reinterpret_cast(arguments[1]); + uint8_t* code = reinterpret_cast(arguments[2]); + unsigned codeCapacity = arguments[3]; + const char* className = reinterpret_cast(arguments[4]); + const char* methodName = reinterpret_cast(arguments[5]); + const char* methodSpec = reinterpret_cast(arguments[6]); + + writeBootImage2 + (t, out, image, code, codeCapacity, className, methodName, methodSpec); + + return 1; +} + } // namespace int @@ -540,15 +551,22 @@ main(int ac, const char** av) return -1; } - writeBootImage - (t, output, &image, code, CodeCapacity, - (ac > 3 ? av[3] : 0), (ac > 4 ? av[4] : 0), (ac > 5 ? av[5] : 0)); + uintptr_t arguments[] = { reinterpret_cast(output), + reinterpret_cast(&image), + reinterpret_cast(code), + CodeCapacity, + reinterpret_cast(ac > 3 ? av[3] : 0), + reinterpret_cast(ac > 4 ? av[4] : 0), + reinterpret_cast(ac > 5 ? av[5] : 0) }; + + run(t, writeBootImage, arguments); fclose(output); if (t->exception) { printTrace(t, t->exception); + return -1; + } else { + return 0; } - - return 0; } diff --git a/src/builtin.cpp b/src/builtin.cpp index dd8ece531a..240ec9628a 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -33,15 +33,9 @@ search(Thread* t, object loader, object name, replace('.', '/', s); } - object r = op(t, loader, n); - if (t->exception) { - return 0; - } - - return reinterpret_cast(r); + return reinterpret_cast(op(t, loader, n)); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } @@ -81,7 +75,7 @@ Avian_avian_SystemClassLoader_resourceExists object name = reinterpret_cast(arguments[1]); if (LIKELY(name)) { - RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); + THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); unsigned length; @@ -92,8 +86,7 @@ Avian_avian_SystemClassLoader_resourceExists return r; } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } @@ -114,17 +107,16 @@ Avian_avian_Machine_dumpHeap object outputFile = reinterpret_cast(*arguments); unsigned length = stringLength(t, outputFile); - char n[length + 1]; - stringChars(t, outputFile, n); - FILE* out = vm::fopen(n, "wb"); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); + stringChars(t, outputFile, RUNTIME_ARRAY_BODY(n)); + FILE* out = vm::fopen(RUNTIME_ARRAY_BODY(n), "wb"); if (out) { { ENTER(t, Thread::ExclusiveState); dumpHeap(t, out); } fclose(out); } else { - object message = makeString(t, "file not found: %s", n); - t->exception = makeThrowable(t, Machine::RuntimeExceptionType, message); + throwNew(t, Machine::RuntimeExceptionType, "file not found: %s", n); } } @@ -146,7 +138,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_getContentLength object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); @@ -170,7 +162,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open object path = reinterpret_cast(*arguments); if (LIKELY(path)) { - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); System::Region* r = t->m->bootFinder->find(RUNTIME_ARRAY_BODY(p)); @@ -180,8 +172,7 @@ Avian_avian_resource_Handler_00024ResourceInputStream_open return reinterpret_cast(r); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 51f5058713..656086f4c1 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -60,9 +60,7 @@ class MyClasspath : public Classpath { (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "(Ljava/lang/Thread;)V"); - if (t->exception == 0) { - t->m->processor->invoke(t, method, 0, t->javaThread); - } + t->m->processor->invoke(t, method, 0, t->javaThread); } virtual void @@ -134,9 +132,8 @@ extern "C" JNIEXPORT int64_t JNICALL Avian_java_lang_Object_getVMClass (Thread* t, object, uintptr_t* arguments) { - object o = reinterpret_cast(arguments[0]); - - return reinterpret_cast(objectClass(t, o)); + return reinterpret_cast + (objectClass(t, reinterpret_cast(arguments[0]))); } extern "C" JNIEXPORT void JNICALL @@ -307,12 +304,16 @@ Avian_java_lang_reflect_Method_invoke object instance = reinterpret_cast(arguments[1]); object args = reinterpret_cast(arguments[2]); - object v = t->m->processor->invokeArray(t, method, instance, args); - if (t->exception) { - t->exception = makeThrowable - (t, Machine::InvocationTargetExceptionType, 0, 0, t->exception); - } - return reinterpret_cast(v); + THREAD_RESOURCE0(t, { + if (t->exception) { + object exception = t->exception; + t->exception = makeThrowable + (t, Machine::InvocationTargetExceptionType, 0, 0, exception); + } + }); + + return reinterpret_cast + (t->m->processor->invokeArray(t, method, instance, args)); } extern "C" JNIEXPORT int64_t JNICALL @@ -327,12 +328,11 @@ Avian_java_lang_reflect_Array_getLength if (LIKELY(elementSize)) { return cast(array, BytesPerWord); } else { - t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); + throwNew(t, Machine::IllegalArgumentExceptionType); } } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); + throwNew(t, Machine::NullPointerExceptionType); } - return 0; } extern "C" JNIEXPORT int64_t JNICALL @@ -394,7 +394,7 @@ Avian_java_lang_System_getVMProperty PROTECT(t, found); unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); int64_t r = 0; @@ -439,8 +439,7 @@ Avian_java_lang_System_identityHashCode if (LIKELY(o)) { return objectHash(t, o); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } @@ -452,7 +451,7 @@ Avian_java_lang_Runtime_load bool mapName = arguments[1]; unsigned length = stringLength(t, name); - RUNTIME_ARRAY(char, n, length + 1); + THREAD_RUNTIME_ARRAY(t, char, n, length + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); loadLibrary(t, "", RUNTIME_ARRAY_BODY(n), mapName, true); @@ -622,11 +621,13 @@ Avian_avian_Classes_defineVMClass uint8_t* buffer = static_cast (t->m->heap->allocate(length)); - memcpy(buffer, &byteArrayBody(t, b, offset), length); - object c = defineClass(t, loader, buffer, length); - t->m->heap->free(buffer, length); + + THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, + t->m->heap->free(buffer, length)); - return reinterpret_cast(c); + memcpy(buffer, &byteArrayBody(t, b, offset), length); + + return reinterpret_cast(defineClass(t, loader, buffer, length)); } extern "C" JNIEXPORT void JNICALL @@ -648,8 +649,7 @@ Avian_avian_Classes_isAssignableFrom if (LIKELY(that)) { return vm::isAssignableFrom(t, this_, that); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - return 0; + throwNew(t, Machine::NullPointerExceptionType); } } diff --git a/src/classpath-common.h b/src/classpath-common.h index 7d17a74673..6efc0a1424 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -101,9 +101,7 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, return; } else { - t->exception = makeThrowable - (t, Machine::IndexOutOfBoundsExceptionType); - return; + throwNew(t, Machine::IndexOutOfBoundsExceptionType); } } else { return; @@ -111,11 +109,11 @@ arrayCopy(Thread* t, object src, int32_t srcOffset, object dst, } } } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); + throwNew(t, Machine::NullPointerExceptionType); return; } - t->exception = makeThrowable(t, Machine::ArrayStoreExceptionType); + throwNew(t, Machine::ArrayStoreExceptionType); } void @@ -158,6 +156,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, { ACQUIRE(t, t->m->classLock); + char* mappedName; unsigned nameLength = strlen(name); if (mapName) { const char* builtins = findProperty(t, "avian.builtins"); @@ -186,15 +185,22 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, const char* suffix = t->m->system->librarySuffix(); unsigned mappedNameLength = nameLength + strlen(prefix) + strlen(suffix); - char* mappedName = static_cast + mappedName = static_cast (t->m->heap->allocate(mappedNameLength + 1)); snprintf(mappedName, mappedNameLength + 1, "%s%s%s", prefix, name, suffix); name = mappedName; nameLength = mappedNameLength; + } else { + mappedName = 0; } + THREAD_RESOURCE2 + (t, char*, mappedName, unsigned, nameLength, if (mappedName) { + t->m->heap->free(mappedName, nameLength + 1); + }); + System::Library* lib = 0; for (Tokenizer tokenizer(path, t->m->system->pathSeparator()); tokenizer.hasMore();) @@ -202,7 +208,7 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, Tokenizer::Token token(tokenizer.next()); unsigned fullNameLength = token.length + 1 + nameLength; - RUNTIME_ARRAY(char, fullName, fullNameLength + 1); + THREAD_RUNTIME_ARRAY(t, char, fullName, fullNameLength + 1); snprintf(RUNTIME_ARRAY_BODY(fullName), fullNameLength + 1, "%*s/%s", token.length, token.s, name); @@ -220,13 +226,8 @@ loadLibrary(Thread* t, const char* path, const char* name, bool mapName, runOnLoadIfFound(t, lib); } } else { - object message = makeString(t, "library not found: %s", name); - t->exception = makeThrowable - (t, Machine::UnsatisfiedLinkErrorType, message); - } - - if (mapName) { - t->m->heap->free(name, nameLength + 1); + throwNew(t, Machine::UnsatisfiedLinkErrorType, "library not found: %s", + name); } return lib; @@ -264,7 +265,7 @@ makeStackTraceElement(Thread* t, object e) object class_ = className(t, methodClass(t, traceElementMethod(t, e))); PROTECT(t, class_); - RUNTIME_ARRAY(char, s, byteArrayLength(t, class_)); + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, class_)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, class_, 0))); class_ = makeString(t, "%s", s); diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index bb4bdb33e4..8882976f3c 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -158,7 +158,7 @@ getClassName(Thread* t, object c) object makeClassNameString(Thread* t, object name) { - RUNTIME_ARRAY(char, s, byteArrayLength(t, name)); + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, name)); replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast(&byteArrayBody(t, name, 0))); @@ -320,9 +320,7 @@ class MyClasspath : public Classpath { object method = resolveMethod (t, root(t, Machine::BootLoader), "java/lang/Thread", "run", "()V"); - if (LIKELY(t->exception == 0)) { - t->m->processor->invoke(t, method, t->javaThread); - } + t->m->processor->invoke(t, method, t->javaThread); acquire(t, t->javaThread); t->flags &= ~Thread::ActiveFlag; @@ -337,11 +335,9 @@ class MyClasspath : public Classpath { resolveSystemClass(t, root(t, Machine::BootLoader), className(t, type(t, Machine::ClassLoaderType))); - if (UNLIKELY(t->exception)) return; #ifdef AVIAN_OPENJDK_SRC interceptFileOperations(t); - if (UNLIKELY(t->exception)) return; #else // not AVIAN_OPENJDK_SRC if (loadLibrary(t, libraryPath, "verify", true, true) == 0 or loadLibrary(t, libraryPath, "java", true, true) == 0) @@ -353,25 +349,22 @@ class MyClasspath : public Classpath { object constructor = resolveMethod (t, type(t, Machine::ClassLoaderType), "", "(Ljava/lang/ClassLoader;)V"); - if (UNLIKELY(t->exception)) return; + PROTECT(t, constructor); t->m->processor->invoke(t, constructor, root(t, Machine::BootLoader), 0); - if (UNLIKELY(t->exception)) return; t->m->processor->invoke (t, constructor, root(t, Machine::AppLoader), root(t, Machine::BootLoader)); - if (UNLIKELY(t->exception)) return; object scl = resolveField (t, type(t, Machine::ClassLoaderType), "scl", "Ljava/lang/ClassLoader;"); - if (UNLIKELY(t->exception)) return; + PROTECT(t, scl); object sclSet = resolveField (t, type(t, Machine::ClassLoaderType), "sclSet", "Z"); - if (UNLIKELY(t->exception)) return; set(t, classStaticTable(t, type(t, Machine::ClassLoaderType)), fieldOffset(t, scl), root(t, Machine::AppLoader)); @@ -453,6 +446,7 @@ getFinder(Thread* t, const char* name, unsigned nameLength) void* p = t->m->libraries->resolve (reinterpret_cast(&byteArrayBody(t, n, 0))); + if (p) { uint8_t* (*function)(unsigned*); memcpy(&function, &p, BytesPerWord); @@ -544,7 +538,7 @@ getFileAttributes object file = reinterpret_cast(arguments[1]); object path = cast(file, cp->filePathField); - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); @@ -573,12 +567,11 @@ getFileAttributes return 0; } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file); - - return (r ? intValue(t, r) : 0); + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file)); } } @@ -594,7 +587,7 @@ checkFileAccess unsigned mask = arguments[2]; object path = cast(file, cp->filePathField); - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); @@ -623,12 +616,11 @@ checkFileAccess return 0; } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file, mask); - - return (r ? booleanValue(t, r) : false); + return booleanValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file, mask)); } } @@ -641,7 +633,7 @@ getFileLength object file = reinterpret_cast(arguments[1]); object path = cast(file, cp->filePathField); - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); @@ -664,12 +656,11 @@ getFileLength return 0; } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file); - - return (r ? longValue(t, r) : 0); + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + reinterpret_cast(arguments[0]), file)); } } @@ -681,27 +672,24 @@ openFile(Thread* t, object method, uintptr_t* arguments) MyClasspath* cp = static_cast(t->m->classpath); - RUNTIME_ARRAY(char, p, stringLength(t, path) + 1); + THREAD_RUNTIME_ARRAY(t, char, p, stringLength(t, path) + 1); stringChars(t, path, RUNTIME_ARRAY_BODY(p)); replace('\\', '/', RUNTIME_ARRAY_BODY(p)); EmbeddedFile ef(cp, RUNTIME_ARRAY_BODY(p), stringLength(t, path)); if (ef.jar) { if (ef.jarLength == 0 or ef.pathLength == 0) { - t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); - return; + throwNew(t, Machine::FileNotFoundExceptionType); } Finder* finder = getFinder(t, ef.jar, ef.jarLength); if (finder == 0) { - t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); - return; + throwNew(t, Machine::FileNotFoundExceptionType); } System::Region* r = finder->find(ef.path); if (r == 0) { - t->exception = makeThrowable(t, Machine::FileNotFoundExceptionType); - return; + throwNew(t, Machine::FileNotFoundExceptionType); } PROTECT(t, this_); @@ -768,16 +756,14 @@ readByteFromFile(Thread* t, object method, uintptr_t* arguments) return -1; } } else { - t->exception = makeThrowable(t, Machine::IoExceptionType); - return 0; + throwNew(t, Machine::IoExceptionType); } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - this_); - - return r ? intValue(t, r) : 0; + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_)); } } @@ -822,16 +808,14 @@ readBytesFromFile(Thread* t, object method, uintptr_t* arguments) return length; } else { - t->exception = makeThrowable(t, Machine::IoExceptionType); - return 0; + throwNew(t, Machine::IoExceptionType); } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - this_, dst, offset, length); - - return r ? intValue(t, r) : 0; + return intValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, dst, offset, length)); } } @@ -866,16 +850,14 @@ skipBytesInFile(Thread* t, object method, uintptr_t* arguments) return count; } else { - t->exception = makeThrowable(t, Machine::IoExceptionType); - return 0; + throwNew(t, Machine::IoExceptionType); } } else { - object r = t->m->processor->invoke - (t, nativeInterceptOriginal - (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - this_, count); - - return r ? longValue(t, r) : 0; + return longValue + (t, t->m->processor->invoke + (t, nativeInterceptOriginal + (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), + this_, count)); } } @@ -900,8 +882,7 @@ availableBytesInFile(Thread* t, object method, uintptr_t* arguments) return static_cast(regionRegion(t, region))->length() - regionPosition(t, region); } else { - t->exception = makeThrowable(t, Machine::IoExceptionType); - return 0; + throwNew(t, Machine::IoExceptionType); } } else { object r = t->m->processor->invoke @@ -987,7 +968,7 @@ void JNICALL loadLibrary(Thread* t, object, uintptr_t* arguments) { object name = reinterpret_cast(arguments[1]); - RUNTIME_ARRAY(char, n, stringLength(t, name) + 1); + THREAD_RUNTIME_ARRAY(t, char, n, stringLength(t, name) + 1); stringChars(t, name, RUNTIME_ARRAY_BODY(n)); bool absolute = arguments[2]; @@ -1207,14 +1188,14 @@ resolveClassBySpec(Thread* t, object loader, const char* spec, { switch (*spec) { case 'L': { - RUNTIME_ARRAY(char, s, specLength - 1); + THREAD_RUNTIME_ARRAY(t, char, s, specLength - 1); memcpy(RUNTIME_ARRAY_BODY(s), spec + 1, specLength - 2); RUNTIME_ARRAY_BODY(s)[specLength - 2] = 0; return resolveClass(t, loader, s); } case '[': { - RUNTIME_ARRAY(char, s, specLength + 1); + THREAD_RUNTIME_ARRAY(t, char, s, specLength + 1); memcpy(RUNTIME_ARRAY_BODY(s), spec, specLength); RUNTIME_ARRAY_BODY(s)[specLength] = 0; return resolveClass(t, loader, s); @@ -1228,11 +1209,7 @@ resolveClassBySpec(Thread* t, object loader, const char* spec, object resolveJType(Thread* t, object loader, const char* spec, unsigned specLength) { - object c = resolveClassBySpec(t, loader, spec, specLength); - - if (UNLIKELY(t->exception)) return 0; - - return getJClass(t, c); + return getJClass(t, resolveClassBySpec(t, loader, spec, specLength)); } object @@ -1258,9 +1235,6 @@ resolveParameterTypes(Thread* t, object loader, object spec, object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); - if (UNLIKELY(t->exception)) { - return 0; - } list = makePair(t, type, list); @@ -1285,9 +1259,6 @@ resolveParameterTypes(Thread* t, object loader, object spec, object type = resolveClassBySpec (t, loader, reinterpret_cast(&byteArrayBody(t, spec, start)), offset - start); - if (UNLIKELY(t->exception)) { - return 0; - } list = makePair(t, type, list); ++ count; @@ -1314,8 +1285,6 @@ resolveParameterJTypes(Thread* t, object loader, object spec, object list = resolveParameterTypes (t, loader, spec, parameterCount, returnTypeSpec); - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, list); object array = makeObjectArray @@ -1356,7 +1325,6 @@ resolveExceptionJTypes(Thread* t, object loader, object addendum) if (objectClass(t, o) == type(t, Machine::ReferenceType)) { o = resolveClass(t, loader, referenceName(t, o)); - if (UNLIKELY(t->exception)) return 0; set(t, addendumPool(t, addendum), SingletonBody + (index * BytesPerWord), o); @@ -1471,12 +1439,15 @@ Avian_sun_misc_Unsafe_defineClass__Ljava_lang_String_2_3BIILjava_lang_ClassLoade object loader = reinterpret_cast(arguments[5]); //object domain = reinterpret_cast(arguments[6]); - uint8_t* buffer = static_cast - (t->m->heap->allocate(length)); - memcpy(buffer, &byteArrayBody(t, data, offset), length); - object c = defineClass(t, loader, buffer, length); + uint8_t* buffer = static_cast(t->m->heap->allocate(length)); - return c ? reinterpret_cast(getJClass(t, c)) : 0; + THREAD_RESOURCE2(t, uint8_t*, buffer, int, length, + t->m->heap->free(buffer, length)); + + memcpy(buffer, &byteArrayBody(t, data, offset), length); + + return reinterpret_cast + (getJClass(t, defineClass(t, loader, buffer, length))); } extern "C" JNIEXPORT int64_t @@ -1487,7 +1458,6 @@ Avian_sun_misc_Unsafe_allocateInstance PROTECT(t, c); initClass(t, c); - if (UNLIKELY(t->exception)) return 0; return reinterpret_cast(make(t, c)); } @@ -1707,8 +1677,7 @@ Avian_sun_misc_Unsafe_allocateMemory if (p) { return reinterpret_cast(p); } else { - t->exception = makeThrowable(t, Machine::OutOfMemoryErrorType); - return 0; + throwNew(t, Machine::OutOfMemoryErrorType); } } @@ -1819,6 +1788,10 @@ Avian_sun_misc_Unsafe_park monitorRelease(t, local::interruptLock(t, t->javaThread)); } +namespace { + +namespace local { + extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetInterfaceVersion)() { @@ -1857,20 +1830,36 @@ EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) notifyAll(t, *o); } +uint64_t +jvmClone(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(makeLocalReference(t, clone(t, *o))); +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_Clone)(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o) }; - return makeLocalReference(t, clone(t, *o)); + return reinterpret_cast(run(t, jvmClone, arguments)); +} + +uint64_t +jvmInternString(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + return reinterpret_cast(makeLocalReference(t, intern(t, *o))); } extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_InternString)(Thread* t, jstring s) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(s) }; - return makeLocalReference(t, intern(t, *s)); + return reinterpret_cast(run(t, jvmInternString, arguments)); } extern "C" JNIEXPORT jlong JNICALL @@ -1885,28 +1874,42 @@ EXPORT(JVM_NanoTime)(Thread* t, jclass) return t->m->system->now() * 1000 * 1000; } +uint64_t +jvmArrayCopy(Thread* t, uintptr_t* arguments) +{ + jobject src = reinterpret_cast(arguments[0]); + jint srcOffset = arguments[1]; + jobject dst = reinterpret_cast(arguments[2]); + jint dstOffset = arguments[3]; + jint length = arguments[4]; + + arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); + + return 1; +} + extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ArrayCopy)(Thread* t, jclass, jobject src, jint srcOffset, jobject dst, jint dstOffset, jint length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(src), + srcOffset, + reinterpret_cast(dst), + dstOffset, + length }; - arrayCopy(t, *src, srcOffset, *dst, dstOffset, length); + run(t, jvmArrayCopy, arguments); } -extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_InitProperties)(Thread* t, jobject properties) +uint64_t +jvmInitProperties(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject properties = reinterpret_cast(arguments[0]); object method = resolveMethod (t, root(t, Machine::BootLoader), "java/util/Properties", "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"); - if (UNLIKELY(t->exception)) { - return 0; - } - PROTECT(t, method); #ifdef PLATFORM_WINDOWS @@ -1970,15 +1973,23 @@ EXPORT(JVM_InitProperties)(Thread* t, jobject properties) while (*p and *p != '=') ++p; if (*p == '=') { - RUNTIME_ARRAY(char, name, (p - start) + 1); + THREAD_RUNTIME_ARRAY(t, char, name, (p - start) + 1); memcpy(name, start, p - start); name[p - start] = 0; local::setProperty (t, method, *properties, RUNTIME_ARRAY_BODY(name), p + 1); } - } + } - return properties; + return reinterpret_cast(properties); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_InitProperties)(Thread* t, jobject properties) +{ + uintptr_t arguments[] = { reinterpret_cast(properties) }; + + return reinterpret_cast(run(t, jvmInitProperties, arguments)); } extern "C" JNIEXPORT void JNICALL @@ -1996,14 +2007,20 @@ EXPORT(JVM_Halt)(jint code) exit(code); } +uint64_t +jvmGC(Thread* t, uintptr_t*) +{ + collect(t, Heap::MajorCollection); + + return 1; +} + extern "C" JNIEXPORT void JNICALL EXPORT(JVM_GC)() { Thread* t = static_cast(local::globalMachine->localThread->get()); - ENTER(t, Thread::ActiveState); - - collect(t, Heap::MajorCollection); + run(t, jvmGC, 0); } extern "C" JNIEXPORT jlong JNICALL @@ -2039,17 +2056,28 @@ EXPORT(JVM_ActiveProcessorCount)() return 1; } +uint64_t +jvmLoadLibrary(Thread* t, uintptr_t* arguments) +{ + const char* path = reinterpret_cast(arguments[0]); + + THREAD_RUNTIME_ARRAY(t, char, p, strlen(path) + 1); + replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); + + return reinterpret_cast + (loadLibrary + (t, static_cast(t->m->classpath)->libraryPath, + RUNTIME_ARRAY_BODY(p), false, false)); +} + extern "C" JNIEXPORT void* JNICALL EXPORT(JVM_LoadLibrary)(const char* path) { Thread* t = static_cast(local::globalMachine->localThread->get()); + + uintptr_t arguments[] = { reinterpret_cast(path) }; - RUNTIME_ARRAY(char, p, strlen(path) + 1); - replace('\\', '/', RUNTIME_ARRAY_BODY(p), path); - - return loadLibrary - (t, static_cast(t->m->classpath)->libraryPath, - RUNTIME_ARRAY_BODY(p), false, false); + return reinterpret_cast(run(t, jvmLoadLibrary, arguments)); } extern "C" JNIEXPORT void JNICALL @@ -2078,13 +2106,23 @@ EXPORT(JVM_IsSupportedJNIVersion)(jint version) extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_IsNaN)(jdouble) { abort(); } -extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) +uint64_t +jvmFillInStackTrace(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject throwable = reinterpret_cast(arguments[0]); object trace = getTrace(t, 1); set(t, *throwable, ThrowableTrace, trace); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_FillInStackTrace)(Thread* t, jobject throwable) +{ + uintptr_t arguments[] = { reinterpret_cast(throwable) }; + + run(t, jvmFillInStackTrace, arguments); } extern "C" JNIEXPORT void JNICALL @@ -2098,14 +2136,24 @@ EXPORT(JVM_GetStackTraceDepth)(Thread* t, jobject throwable) return objectArrayLength(t, throwableTrace(t, *throwable)); } +uint64_t +jvmGetStackTraceElement(Thread* t, uintptr_t* arguments) +{ + jobject throwable = reinterpret_cast(arguments[0]); + jint index = arguments[1]; + + return reinterpret_cast + (makeLocalReference + (t, makeStackTraceElement + (t, objectArrayBody(t, throwableTrace(t, *throwable), index)))); +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetStackTraceElement)(Thread* t, jobject throwable, jint index) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(throwable), index }; - return makeLocalReference - (t, makeStackTraceElement - (t, objectArrayBody(t, throwableTrace(t, *throwable), index))); + return reinterpret_cast(run(t, jvmGetStackTraceElement, arguments)); } extern "C" JNIEXPORT void JNICALL @@ -2171,10 +2219,10 @@ EXPORT(JVM_Yield)(Thread*, jclass) #endif } -extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) +uint64_t +jvmSleep(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jlong milliseconds; memcpy(&milliseconds, arguments, sizeof(jlong)); if (threadSleepLock(t, t->javaThread) == 0) { object lock = makeJobject(t); @@ -2184,6 +2232,17 @@ EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) acquire(t, threadSleepLock(t, t->javaThread)); vm::wait(t, threadSleepLock(t, t->javaThread), milliseconds); release(t, threadSleepLock(t, t->javaThread)); + + return 1; +} + +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Sleep)(Thread* t, jclass, jlong milliseconds) +{ + uintptr_t arguments[sizeof(jlong) / BytesPerWord]; + memcpy(arguments, &milliseconds, sizeof(jlong)); + + run(t, jvmSleep, arguments); } extern "C" JNIEXPORT jobject JNICALL @@ -2197,10 +2256,10 @@ EXPORT(JVM_CurrentThread)(Thread* t, jclass) extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_CountStackFrames)(Thread*, jobject) { abort(); } -extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_Interrupt)(Thread* t, jobject thread) +uint64_t +jvmInterrupt(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject thread = reinterpret_cast(arguments[0]); monitorAcquire(t, local::interruptLock(t, *thread)); Thread* p = reinterpret_cast(threadPeer(t, *thread)); @@ -2210,12 +2269,23 @@ EXPORT(JVM_Interrupt)(Thread* t, jobject thread) threadInterrupted(t, *thread) = true; } monitorRelease(t, local::interruptLock(t, *thread)); + + return 1; } -extern "C" JNIEXPORT jboolean JNICALL -EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) +extern "C" JNIEXPORT void JNICALL +EXPORT(JVM_Interrupt)(Thread* t, jobject thread) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(thread) }; + + run(t, jvmInterrupt, arguments); +} + +uint64_t +jvmIsInterrupted(Thread* t, uintptr_t* arguments) +{ + jobject thread = reinterpret_cast(arguments[0]); + jboolean clear = arguments[1]; monitorAcquire(t, local::interruptLock(t, *thread)); bool v = threadInterrupted(t, *thread); @@ -2227,6 +2297,14 @@ EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) return v; } +extern "C" JNIEXPORT jboolean JNICALL +EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) +{ + uintptr_t arguments[] = { reinterpret_cast(thread), clear }; + + return run(t, jvmIsInterrupted, arguments); +} + extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } @@ -2236,10 +2314,10 @@ EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetAllThreads)(Thread*, jclass) { abort(); } -extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) +uint64_t +jvmDumpThreads(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobjectArray threads = reinterpret_cast(arguments[0]); unsigned threadsLength = objectArrayLength(t, *threads); object arrayClass = resolveObjectArrayClass @@ -2273,7 +2351,15 @@ EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) } } - return makeLocalReference(t, result); + return reinterpret_cast(makeLocalReference(t, result)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_DumpThreads)(Thread* t, jclass, jobjectArray threads) +{ + uintptr_t arguments[] = { reinterpret_cast(threads) }; + + return reinterpret_cast(run(t, jvmDumpThreads, arguments)); } extern "C" JNIEXPORT jclass JNICALL @@ -2282,11 +2368,9 @@ EXPORT(JVM_CurrentLoadedClass)(Thread*) { abort(); } extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_CurrentClassLoader)(Thread*) { abort(); } -extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassContext)(Thread* t) +uint64_t +jvmGetClassContext(Thread* t, uintptr_t*) { - ENTER(t, Thread::ActiveState); - object trace = getTrace(t, 1); PROTECT(t, trace); @@ -2301,7 +2385,13 @@ EXPORT(JVM_GetClassContext)(Thread* t) set(t, context, ArrayBody + (i * BytesPerWord), c); } - return makeLocalReference(t, context); + return reinterpret_cast(makeLocalReference(t, context)); +} + +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassContext)(Thread* t) +{ + return reinterpret_cast(run(t, jvmGetClassContext, 0)); } extern "C" JNIEXPORT jint JNICALL @@ -2366,10 +2456,11 @@ extern "C" JNIEXPORT void JNICALL EXPORT(JVM_SetPrimitiveArrayElement)(Thread*, jobject, jint, jvalue, unsigned char) { abort(); } -extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) +uint64_t +jvmNewArray(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass elementClass = reinterpret_cast(arguments[0]); + jint length = arguments[1]; object c = jclassVmClass(t, *elementClass); @@ -2380,23 +2471,41 @@ EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) switch (*name) { case 'b': if (name[1] == 'o') { - return makeLocalReference(t, makeBooleanArray(t, length)); + return reinterpret_cast + (makeLocalReference(t, makeBooleanArray(t, length))); } else { - return makeLocalReference(t, makeByteArray(t, length)); + return reinterpret_cast + (makeLocalReference(t, makeByteArray(t, length))); } - case 'c': return makeLocalReference(t, makeCharArray(t, length)); - case 'd': return makeLocalReference(t, makeDoubleArray(t, length)); - case 'f': return makeLocalReference(t, makeFloatArray(t, length)); - case 'i': return makeLocalReference(t, makeIntArray(t, length)); - case 'l': return makeLocalReference(t, makeLongArray(t, length)); - case 's': return makeLocalReference(t, makeShortArray(t, length)); + case 'c': return reinterpret_cast + (makeLocalReference(t, makeCharArray(t, length))); + case 'd': return reinterpret_cast + (makeLocalReference(t, makeDoubleArray(t, length))); + case 'f': return reinterpret_cast + (makeLocalReference(t, makeFloatArray(t, length))); + case 'i': return reinterpret_cast + (makeLocalReference(t, makeIntArray(t, length))); + case 'l': return reinterpret_cast + (makeLocalReference(t, makeLongArray(t, length))); + case 's': return reinterpret_cast + (makeLocalReference(t, makeShortArray(t, length))); default: abort(t); } } else { - return makeLocalReference(t, makeObjectArray(t, c, length)); + return reinterpret_cast + (makeLocalReference(t, makeObjectArray(t, c, length))); } } +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_NewArray)(Thread* t, jclass elementClass, jint length) +{ + uintptr_t arguments[] = { reinterpret_cast(elementClass), + length }; + + return reinterpret_cast(run(t, jvmNewArray, arguments)); +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_NewMultiArray)(Thread*, jclass, jintArray) { abort(); } @@ -2445,33 +2554,36 @@ EXPORT(JVM_FindPrimitiveClass)(Thread* t, const char* name) return makeLocalReference (t, getJClass(t, type(t, Machine::JvoidType))); default: - t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); - return 0; + throwNew(t, Machine::IllegalArgumentExceptionType); } } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_ResolveClass)(Thread*, jclass) { abort(); } -extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, - jboolean init, jobject loader, - jboolean throwError) +uint64_t +jvmFindClassFromClassLoader(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + const char* name = reinterpret_cast(arguments[0]); + jboolean init = arguments[1]; + jobject loader = reinterpret_cast(arguments[2]); + jboolean throwError = arguments[3]; + + THREAD_RESOURCE(t, jboolean, throwError, { + if (t->exception and throwError) { + object exception = t->exception; + t->exception = 0; + + t->exception = makeThrowable + (t, Machine::NoClassDefFoundErrorType, + throwableMessage(t, exception), + throwableTrace(t, exception), + throwableCause(t, exception)); + } + }); object c = resolveClass (t, loader ? *loader : root(t, Machine::BootLoader), name); - if (t->exception) { - if (throwError) { - t->exception = makeThrowable - (t, Machine::NoClassDefFoundErrorType, - throwableMessage(t, t->exception), - throwableTrace(t, t->exception), - throwableCause(t, t->exception)); - } - return 0; - } if (init) { PROTECT(t, c); @@ -2479,7 +2591,21 @@ EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, initClass(t, c); } - return makeLocalReference(t, getJClass(t, c)); + return reinterpret_cast(makeLocalReference(t, getJClass(t, c))); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindClassFromClassLoader)(Thread* t, const char* name, + jboolean init, jobject loader, + jboolean throwError) +{ + uintptr_t arguments[] = { reinterpret_cast(name), + init, + reinterpret_cast(loader), + throwError }; + + return reinterpret_cast + (run(t, jvmFindClassFromClassLoader, arguments)); } extern "C" JNIEXPORT jclass JNICALL @@ -2490,13 +2616,14 @@ EXPORT(JVM_FindClassFromBootLoader)(Thread* t, const char* name, } extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, - jclass) { abort(); } +EXPORT(JVM_FindClassFromClass)(Thread*, const char*, jboolean, jclass) +{ abort(); } -extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) +uint64_t +jvmFindLoadedClass(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject loader = reinterpret_cast(arguments[0]); + jstring name = reinterpret_cast(arguments[1]); object spec = makeByteArray(t, stringLength(t, *name) + 1); @@ -2507,18 +2634,40 @@ EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) object c = findLoadedClass(t, *loader, spec); - return c ? makeLocalReference(t, getJClass(t, c)) : 0; + return reinterpret_cast + (c ? makeLocalReference(t, getJClass(t, c)) : 0); +} + +extern "C" JNIEXPORT jclass JNICALL +EXPORT(JVM_FindLoadedClass)(Thread* t, jobject loader, jstring name) +{ + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(name) }; + + return reinterpret_cast(run(t, jvmFindLoadedClass, arguments)); +} + +uint64_t +jvmDefineClass(Thread* t, uintptr_t* arguments) +{ + jobject loader = reinterpret_cast(arguments[0]); + const uint8_t* data = reinterpret_cast(arguments[1]); + jsize length = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, getJClass(t, defineClass(t, *loader, data, length)))); } extern "C" JNIEXPORT jclass JNICALL EXPORT(JVM_DefineClass)(Thread* t, const char*, jobject loader, const uint8_t* data, jsize length, jobject) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(data), + length }; - object c = defineClass(t, *loader, data, length); - - return c ? makeLocalReference(t, getJClass(t, c)) : 0; + return reinterpret_cast(run(t, jvmDefineClass, arguments)); } extern "C" JNIEXPORT jclass JNICALL @@ -2537,10 +2686,10 @@ EXPORT(JVM_GetClassName)(Thread* t, jclass c) return makeLocalReference(t, jclassName(t, *c)); } -extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) +uint64_t +jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass c = reinterpret_cast(arguments[0]); object table = classInterfaceTable(t, jclassVmClass(t, *c)); if (table) { @@ -2556,13 +2705,22 @@ EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) set(t, array, ArrayBody + (i * BytesPerWord), interface); } - return makeLocalReference(t, array); + return reinterpret_cast(makeLocalReference(t, array)); } else { - return makeLocalReference - (t, makeObjectArray(t, type(t, Machine::JclassType), 0)); + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JclassType), 0))); } } +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassInterfaces)(Thread* t, jclass c) +{ + uintptr_t arguments[] = { reinterpret_cast(c) }; + + return reinterpret_cast(run(t, jvmGetClassInterfaces, arguments)); +} + extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_GetClassLoader)(Thread* t, jclass c) { @@ -2618,20 +2776,23 @@ EXPORT(JVM_SetClassSigners)(Thread* t, jclass c, jobjectArray signers) set(t, runtimeData, ClassRuntimeDataSigners, *signers); } -extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) +uint64_t +jvmGetProtectionDomain(Thread* t, uintptr_t*) { - ENTER(t, Thread::ActiveState); - object openJDK = resolveClass (t, root(t, Machine::BootLoader), "avian/OpenJDK"); - if (UNLIKELY(t->exception)) return 0; object method = resolveMethod (t, openJDK, "getProtectionDomain", "()Ljava/security/ProtectionDomain;"); - if (UNLIKELY(t->exception)) return 0; - return makeLocalReference(t, t->m->processor->invoke(t, method, 0)); + return reinterpret_cast + (makeLocalReference(t, t->m->processor->invoke(t, method, 0))); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_GetProtectionDomain)(Thread* t, jclass) +{ + return reinterpret_cast(run(t, jvmGetProtectionDomain, 0)); } extern "C" JNIEXPORT void JNICALL @@ -2694,10 +2855,11 @@ EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) ? makeLocalReference(t, addendumAnnotationTable(t, addendum)) : 0; } -extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) +uint64_t +jvmGetClassDeclaredMethods(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { @@ -2727,26 +2889,17 @@ EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) object parameterTypes = local::resolveParameterJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); - - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, parameterTypes); object returnType = local::resolveJType (t, classLoader(t, jclassVmClass(t, *c)), reinterpret_cast (&byteArrayBody(t, methodSpec(t, vmMethod), returnTypeSpec)), byteArrayLength(t, methodSpec(t, vmMethod)) - 1 - returnTypeSpec); - - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, returnType); object exceptionTypes = local::resolveExceptionJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodAddendum(t, vmMethod)); - - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, exceptionTypes); object signature = t->m->classpath->makeString @@ -2777,18 +2930,28 @@ EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) } } - return makeLocalReference(t, array); + return reinterpret_cast(makeLocalReference(t, array)); } else { - return makeLocalReference - (t, makeObjectArray(t, type(t, Machine::JmethodType), 0)); + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JmethodType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) +EXPORT(JVM_GetClassDeclaredMethods)(Thread* t, jclass c, jboolean publicOnly) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + return reinterpret_cast + (run(t, jvmGetClassDeclaredMethods, arguments)); +} + +uint64_t +jvmGetClassDeclaredFields(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; object table = classFieldTable(t, jclassVmClass(t, *c)); if (table) { PROTECT(t, table); @@ -2815,11 +2978,6 @@ EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) reinterpret_cast (&byteArrayBody(t, fieldSpec(t, vmField), 0)), byteArrayLength(t, fieldSpec(t, vmField)) - 1); - - if (UNLIKELY(t->exception)) { - return 0; - } - PROTECT(t, type); type = getJClass(t, type); @@ -2852,18 +3010,28 @@ EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) } assert(t, ai == objectArrayLength(t, array)); - return makeLocalReference(t, array); + return reinterpret_cast(makeLocalReference(t, array)); } else { - return makeLocalReference - (t, makeObjectArray(t, type(t, Machine::JfieldType), 0)); + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JfieldType), 0))); } } extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, - jboolean publicOnly) +EXPORT(JVM_GetClassDeclaredFields)(Thread* t, jclass c, jboolean publicOnly) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + + return reinterpret_cast + (run(t, jvmGetClassDeclaredFields, arguments)); +} + +uint64_t +jvmGetClassDeclaredConstructors(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + jboolean publicOnly = arguments[1]; object table = classMethodTable(t, jclassVmClass(t, *c)); if (table) { @@ -2889,17 +3057,11 @@ EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, object parameterTypes = local::resolveParameterJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodSpec(t, vmMethod), ¶meterCount, &returnTypeSpec); - - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, parameterTypes); object exceptionTypes = local::resolveExceptionJTypes (t, classLoader(t, jclassVmClass(t, *c)), methodAddendum(t, vmMethod)); - - if (UNLIKELY(t->exception)) return 0; - PROTECT(t, exceptionTypes); object signature = t->m->classpath->makeString @@ -2929,24 +3091,36 @@ EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, } } - return makeLocalReference(t, array); + return reinterpret_cast(makeLocalReference(t, array)); } else { - return makeLocalReference - (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0)); + return reinterpret_cast + (makeLocalReference + (t, makeObjectArray(t, type(t, Machine::JconstructorType), 0))); } } +extern "C" JNIEXPORT jobjectArray JNICALL +EXPORT(JVM_GetClassDeclaredConstructors)(Thread* t, jclass c, + jboolean publicOnly) +{ + uintptr_t arguments[] = { reinterpret_cast(c), publicOnly }; + + return reinterpret_cast + (run(t, jvmGetClassDeclaredConstructors, arguments)); +} + extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetClassAccessFlags)(Thread* t, jclass c) { return EXPORT(JVM_GetClassModifiers)(t, c); } -extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, - jobjectArray arguments) +uint64_t +jvmInvokeMethod(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject method = reinterpret_cast(arguments[0]); + jobject instance = reinterpret_cast(arguments[1]); + jobjectArray args = reinterpret_cast(arguments[2]); object vmMethod = arrayBody (t, classMethodTable @@ -2960,19 +3134,30 @@ EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, object result; if (arguments) { result = t->m->processor->invokeArray - (t, vmMethod, instance ? *instance : 0, *arguments); + (t, vmMethod, instance ? *instance : 0, *args); } else { result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); } - return result ? makeLocalReference(t, result) : 0; + return reinterpret_cast(makeLocalReference(t, result)); } extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, - jobjectArray arguments) +EXPORT(JVM_InvokeMethod)(Thread* t, jobject method, jobject instance, + jobjectArray args) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(method), + reinterpret_cast(instance), + reinterpret_cast(args) }; + + return reinterpret_cast(run(t, jvmInvokeMethod, arguments)); +} + +uint64_t +jvmNewInstanceFromConstructor(Thread* t, uintptr_t* arguments) +{ + jobject constructor = reinterpret_cast(arguments[0]); + jobjectArray args = reinterpret_cast(arguments[1]); object instance = make (t, jclassVmClass(t, jconstructorClazz(t, *constructor))); @@ -2983,17 +3168,24 @@ EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, (t, jclassVmClass(t, jconstructorClazz(t, *constructor))), jconstructorSlot(t, *constructor)); - if (arguments) { - t->m->processor->invokeArray(t, method, instance, *arguments); + if (args) { + t->m->processor->invokeArray(t, method, instance, *args); } else { t->m->processor->invoke(t, method, instance); } - if (UNLIKELY(t->exception)) { - return 0; - } else { - return makeLocalReference(t, instance); - } + return reinterpret_cast(makeLocalReference(t, instance)); +} + +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_NewInstanceFromConstructor)(Thread* t, jobject constructor, + jobjectArray args) +{ + uintptr_t arguments[] = { reinterpret_cast(constructor), + reinterpret_cast(args) }; + + return reinterpret_cast + (run(t, jvmNewInstanceFromConstructor, arguments)); } extern "C" JNIEXPORT jobject JNICALL @@ -3079,33 +3271,72 @@ extern "C" JNIEXPORT jstring JNICALL EXPORT(JVM_ConstantPoolGetStringAt)(Thread*, jobject, jobject, jint) { abort(); } -extern "C" JNIEXPORT jstring JNICALL -EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) +uint64_t +jvmConstantPoolGetUTF8At(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jobject pool = reinterpret_cast(arguments[0]); + jint index = arguments[1]; object array = singletonObject(t, *pool, index - 1); - return makeLocalReference - (t, t->m->classpath->makeString - (t, array, 0, cast(array, BytesPerWord) - 1)); + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1))); } -extern "C" JNIEXPORT jobject JNICALL -EXPORT(JVM_DoPrivileged) -(Thread* t, jclass, jobject action, jobject, jboolean wrapException) +extern "C" JNIEXPORT jstring JNICALL +EXPORT(JVM_ConstantPoolGetUTF8At)(Thread* t, jobject, jobject pool, jint index) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(pool), index }; + + return reinterpret_cast + (run(t, jvmConstantPoolGetUTF8At, arguments)); +} + +void +maybeWrap(Thread* t, bool wrapException) +{ + if (t->exception + and wrapException + and not (instanceOf(t, type(t, Machine::ErrorType), t->exception) + or instanceOf + (t, type(t, Machine::RuntimeExceptionType), t->exception))) + { + object exception = t->exception; + t->exception = 0; + + PROTECT(t, exception); + + object paeClass = resolveClass + (t, root(t, Machine::BootLoader), + "java/security/PrivilegedActionException"); + PROTECT(t, paeClass); + + object paeConstructor = resolveMethod + (t, paeClass, "", "(Ljava/lang/Exception;)V"); + PROTECT(t, paeConstructor); + + object result = make(t, paeClass); + PROTECT(t, result); + + t->m->processor->invoke(t, paeConstructor, result, exception); + + t->exception = result; + } +} + +uint64_t +jvmDoPrivileged(Thread* t, uintptr_t* arguments) +{ + jobject action = reinterpret_cast(arguments[0]); + jboolean wrapException = arguments[1]; // todo: cache these class and method lookups in the t->m->classpath // object: object privilegedAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedAction"); - - if (UNLIKELY(t->exception)) { - return 0; - } object method; if (instanceOf(t, privilegedAction, *action)) { @@ -3115,58 +3346,25 @@ EXPORT(JVM_DoPrivileged) object privilegedExceptionAction = resolveClass (t, root(t, Machine::BootLoader), "java/security/PrivilegedExceptionAction"); - - if (UNLIKELY(t->exception)) { - return 0; - } method = resolveMethod (t, privilegedExceptionAction, "run", "()Ljava/lang/Object;"); } - if (LIKELY(t->exception == 0)) { - object result = t->m->processor->invoke(t, method, *action); + THREAD_RESOURCE(t, jboolean, wrapException, maybeWrap(t, wrapException)); - if (LIKELY(t->exception == 0)) { - return makeLocalReference(t, result); - } else { - if (wrapException and not - (instanceOf(t, type(t, Machine::ErrorType), t->exception) - or instanceOf(t, type(t, Machine::RuntimeExceptionType), - t->exception))) - { - object cause = t->exception; - PROTECT(t, cause); + return reinterpret_cast + (makeLocalReference(t, t->m->processor->invoke(t, method, *action))); +} - t->exception = 0; +extern "C" JNIEXPORT jobject JNICALL +EXPORT(JVM_DoPrivileged) +(Thread* t, jclass, jobject action, jobject, jboolean wrapException) +{ + uintptr_t arguments[] = { reinterpret_cast(action), + wrapException }; - object paeClass = resolveClass - (t, root(t, Machine::BootLoader), - "java/security/PrivilegedActionException"); - - if (LIKELY(t->exception == 0)) { - PROTECT(t, paeClass); - - object paeConstructor = resolveMethod - (t, paeClass, "", "(Ljava/lang/Exception;)V"); - PROTECT(t, paeConstructor); - - if (LIKELY(t->exception == 0)) { - object result = make(t, paeClass); - PROTECT(t, result); - - t->m->processor->invoke(t, paeConstructor, result, cause); - - if (LIKELY(t->exception == 0)) { - t->exception = result; - } - } - } - } - } - } - - return 0; + return reinterpret_cast(run(t, jvmDoPrivileged, arguments)); } extern "C" JNIEXPORT jobject JNICALL @@ -3574,6 +3772,10 @@ extern "C" JNIEXPORT jboolean JNICALL EXPORT(JVM_CX8Field)(JNIEnv*, jobject*, jfieldID*, jlong, jlong) { abort(); } +} // namespace local + +} // namespace + extern "C" JNIEXPORT int jio_vsnprintf(char* dst, size_t size, const char* format, va_list a) { @@ -3622,7 +3824,7 @@ Avian_java_util_TimeZone_getSystemTimeZoneID object country = reinterpret_cast(arguments[1]); - RUNTIME_ARRAY(char, countryChars, stringLength(t, country) + 1); + THREAD_RUNTIME_ARRAY(t, char, countryChars, stringLength(t, country) + 1); stringChars(t, country, RUNTIME_ARRAY_BODY(countryChars)); local::MyClasspath* cp = static_cast(t->m->classpath); @@ -3642,7 +3844,7 @@ Avian_java_util_TimeZone_getSystemTimeZoneID return 0; } - RESOURCE(System::Region*, r, r->dispose()); + THREAD_RESOURCE(t, System::Region*, r, r->dispose()); char tmpPath[MAX_PATH + 1]; GetTempPathA(MAX_PATH, tmpPath); @@ -3653,7 +3855,7 @@ Avian_java_util_TimeZone_getSystemTimeZoneID return 0; } - RESOURCE(char*, tmpDir, rmdir(tmpDir)); + THREAD_RESOURCE(t, char*, tmpDir, rmdir(tmpDir)); char libDir[MAX_PATH + 1]; vm::snprintf(libDir, MAX_PATH, "%s/lib", tmpDir); @@ -3661,7 +3863,7 @@ Avian_java_util_TimeZone_getSystemTimeZoneID return 0; } - RESOURCE(char*, libDir, rmdir(libDir)); + THREAD_RESOURCE(t, char*, libDir, rmdir(libDir)); char file[MAX_PATH + 1]; vm::snprintf(file, MAX_PATH, "%s/tzmappings", libDir); @@ -3670,8 +3872,8 @@ Avian_java_util_TimeZone_getSystemTimeZoneID return 0; } - RESOURCE(char*, file, unlink(file)); - RESOURCE(FILE*, out, fclose(out)); + THREAD_RESOURCE(t, char*, file, unlink(file)); + THREAD_RESOURCE(t, FILE*, out, fclose(out)); if (fwrite(r->start(), 1, r->length(), out) != r->length() or fflush(out) != 0) @@ -3681,9 +3883,9 @@ Avian_java_util_TimeZone_getSystemTimeZoneID char* javaTZ = findJavaTZ_md(tmpDir, RUNTIME_ARRAY_BODY(countryChars)); if (javaTZ) { - object result = makeString(t, "%s", javaTZ); - free(javaTZ); - return reinterpret_cast(result); + THREAD_RESOURCE(t, char*, javaTZ, free(javaTZ)); + + return reinterpret_cast(makeString(t, "%s", javaTZ)); } else { return 0; } diff --git a/src/compile-x86.S b/src/compile-x86.S index 41a0d2ae07..4b79aa4e38 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -23,7 +23,7 @@ #ifdef __x86_64__ -#define THREAD_STACK 2216 +#define THREAD_STACK 2232 #if defined __MINGW32__ || defined __CYGWIN32__ @@ -306,7 +306,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): #elif defined __i386__ -#define THREAD_STACK 2144 +#define THREAD_STACK 2152 #define CALLEE_SAVED_REGISTER_FOOTPRINT 16 diff --git a/src/compile.cpp b/src/compile.cpp index 686d68e1f0..6069a0dc13 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -294,7 +294,6 @@ resolveTarget(MyThread* t, void* stack, object method) PROTECT(t, class_); resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); - if (UNLIKELY(t->exception)) return 0; } if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) { @@ -311,7 +310,6 @@ resolveTarget(MyThread* t, object class_, unsigned index) PROTECT(t, class_); resolveSystemClass(t, root(t, Machine::BootLoader), className(t, class_)); - if (UNLIKELY(t->exception)) return 0; } return arrayBody(t, classVirtualTable(t, class_), index); @@ -910,6 +908,17 @@ class BootContext { class Context { public: + class MyResource: public Thread::Resource { + public: + MyResource(Context* c): Resource(c->thread), c(c) { } + + virtual void release() { + c->dispose(); + } + + Context* c; + }; + class MyProtector: public Thread::Protector { public: MyProtector(Context* c): Protector(c->thread), c(c) { } @@ -1125,6 +1134,9 @@ class Context { visitTable(makeVisitTable(t, &zone, method)), rootTable(makeRootTable(t, &zone, method)), subroutineTable(0), + executableAllocator(0), + executableStart(0), + executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), @@ -1147,6 +1159,9 @@ class Context { visitTable(0), rootTable(0), subroutineTable(0), + executableAllocator(0), + executableStart(0), + executableSize(0), objectPoolCount(0), traceLogCount(0), dirtyRoots(false), @@ -1156,8 +1171,19 @@ class Context { { } ~Context() { - if (compiler) compiler->dispose(); + dispose(); + } + + void dispose() { + if (compiler) { + compiler->dispose(); + } + assembler->dispose(); + + if (executableAllocator) { + executableAllocator->free(executableStart, executableSize); + } } MyThread* thread; @@ -1173,6 +1199,9 @@ class Context { uint16_t* visitTable; uintptr_t* rootTable; Subroutine** subroutineTable; + Allocator* executableAllocator; + void* executableStart; + unsigned executableSize; unsigned objectPoolCount; unsigned traceLogCount; bool dirtyRoots; @@ -1249,10 +1278,8 @@ class Frame { } ~Frame() { - if (t->exception == 0) { - if (level > 1) { - context->eventLog.append(PopContextEvent); - } + if (level > 1) { + context->eventLog.append(PopContextEvent); } } @@ -2100,6 +2127,15 @@ unwind(MyThread* t) vmJump(ip, base, stack, t, 0, 0); } +class MyCheckpoint: public Thread::Checkpoint { + public: + MyCheckpoint(MyThread* t): Checkpoint(t) { } + + virtual void unwind() { + local::unwind(static_cast(t)); + } +}; + uintptr_t defaultThunk(MyThread* t); @@ -2135,7 +2171,6 @@ void tryInitClass(MyThread* t, object class_) { initClass(t, class_); - if (UNLIKELY(t->exception)) unwind(t); } FixedAllocator* @@ -2157,17 +2192,12 @@ findInterfaceMethodFromInstance(MyThread* t, object method, object instance) compile(t, codeAllocator(t), 0, target); } - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } - return methodAddress(t, target); + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; } + return methodAddress(t, target); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2371,8 +2401,7 @@ divideLong(MyThread* t, int64_t b, int64_t a) if (LIKELY(b)) { return a / b; } else { - t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); - unwind(t); + throwNew(t, Machine::ArithmeticExceptionType); } } @@ -2382,8 +2411,7 @@ divideInt(MyThread* t, int32_t b, int32_t a) if (LIKELY(b)) { return a / b; } else { - t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); - unwind(t); + throwNew(t, Machine::ArithmeticExceptionType); } } @@ -2393,8 +2421,7 @@ moduloLong(MyThread* t, int64_t b, int64_t a) if (LIKELY(b)) { return a % b; } else { - t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); - unwind(t); + throwNew(t, Machine::ArithmeticExceptionType); } } @@ -2404,8 +2431,7 @@ moduloInt(MyThread* t, int32_t b, int32_t a) if (LIKELY(b)) { return a % b; } else { - t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); - unwind(t); + throwNew(t, Machine::ArithmeticExceptionType); } } @@ -2457,10 +2483,7 @@ makeBlankObjectArray(MyThread* t, object class_, int32_t length) if (length >= 0) { return reinterpret_cast(makeObjectArray(t, class_, length)); } else { - object message = makeString(t, "%d", length); - t->exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); - unwind(t); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } @@ -2507,10 +2530,7 @@ makeBlankArray(MyThread* t, unsigned type, int32_t length) return reinterpret_cast(constructor(t, length)); } else { - object message = makeString(t, "%d", length); - t->exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); - unwind(t); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", length); } } @@ -2543,8 +2563,7 @@ setMaybeNull(MyThread* t, object o, unsigned offset, object value) if (LIKELY(o)) { set(t, o, offset, value); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2554,8 +2573,7 @@ acquireMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { acquire(t, o); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2565,8 +2583,7 @@ releaseMonitorForObject(MyThread* t, object o) if (LIKELY(o)) { release(t, o); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); - unwind(t); + throwNew(t, Machine::NullPointerExceptionType); } } @@ -2576,13 +2593,12 @@ makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* countStack, { PROTECT(t, class_); - RUNTIME_ARRAY(int32_t, counts, dimensions); + THREAD_RUNTIME_ARRAY(t, int32_t, counts, dimensions); for (int i = dimensions - 1; i >= 0; --i) { RUNTIME_ARRAY_BODY(counts)[i] = countStack[dimensions - i - 1]; if (UNLIKELY(RUNTIME_ARRAY_BODY(counts)[i] < 0)) { - object message = makeString(t, "%d", RUNTIME_ARRAY_BODY(counts)[i]); - t->exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); + throwNew(t, Machine::NegativeArraySizeExceptionType, "%d", + RUNTIME_ARRAY_BODY(counts)[i]); return 0; } } @@ -2600,14 +2616,9 @@ uint64_t makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, int32_t offset) { - object r = makeMultidimensionalArray2 - (t, class_, static_cast(t->stack) + offset, dimensions); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } + return reinterpret_cast + (makeMultidimensionalArray2 + (t, class_, static_cast(t->stack) + offset, dimensions)); } unsigned @@ -2636,50 +2647,40 @@ throwArrayIndexOutOfBounds(MyThread* t) { if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); - t->exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType); - atomicAnd(&(t->flags), ~Thread::TracingFlag); + THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); + + throwNew(t, Machine::ArrayIndexOutOfBoundsExceptionType); } else { // not enough memory available for a new exception and stack trace // -- use a preallocated instance instead - t->exception = root(t, Machine::ArrayIndexOutOfBoundsException); + throw_(t, root(t, Machine::ArrayIndexOutOfBoundsException)); } - - unwind(t); } void NO_RETURN throwStackOverflow(MyThread* t) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); - - unwind(t); + throwNew(t, Machine::StackOverflowErrorType); } void NO_RETURN throw_(MyThread* t, object o) { if (LIKELY(o)) { - t->exception = o; + vm::throw_(t, o); } else { - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); + throwNew(t, Machine::NullPointerExceptionType); } - - // printTrace(t, t->exception); - - unwind(t); } void checkCast(MyThread* t, object class_, object o) { if (UNLIKELY(o and not isAssignableFrom(t, class_, objectClass(t, o)))) { - object message = makeString - (t, "%s as %s", + throwNew + (t, Machine::ClassCastExceptionType, "%s as %s", &byteArrayBody(t, className(t, objectClass(t, o)), 0), &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeThrowable(t, Machine::ClassCastExceptionType, message); - unwind(t); } } @@ -3115,7 +3116,7 @@ integerBranch(MyThread* t, Frame* frame, object code, unsigned& ip, } saveStateAndCompile(t, frame, newIp); - return t->exception == 0; + return true; } bool @@ -3182,7 +3183,7 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, } saveStateAndCompile(t, frame, newIp); - return t->exception == 0; + return true; } bool @@ -3221,7 +3222,7 @@ void compile(MyThread* t, Frame* initialFrame, unsigned ip, int exceptionHandlerStart) { - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, initialFrame->context->method))); Frame myFrame(initialFrame, RUNTIME_ARRAY_BODY(stackMap)); Frame* frame = &myFrame; @@ -3457,7 +3458,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; Compiler::Operand* length = frame->popInt(); @@ -3528,7 +3528,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; Compiler::Operand* instance = c->peek(1, 0); @@ -3565,8 +3564,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not floatBranch(t, frame, code, ip, 8, false, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3582,8 +3579,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not floatBranch(t, frame, code, ip, 8, true, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3682,8 +3677,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popInt(); if (not floatBranch(t, frame, code, ip, 4, false, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3697,8 +3690,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popInt(); if (not floatBranch(t, frame, code, ip, 4, true, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -3756,7 +3747,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; if ((fieldFlags(t, field) & ACC_VOLATILE) and BytesPerWord == 4 @@ -4004,7 +3994,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case if_icmpeq: @@ -4045,7 +4034,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case ifeq: @@ -4087,7 +4075,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case ifnull: @@ -4107,7 +4094,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, } saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; } break; case iinc: { @@ -4161,7 +4147,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; frame->pushInt (c->call @@ -4178,7 +4163,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, ip += 2; object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -4219,7 +4203,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; object class_ = methodClass(t, context->method); if (isSpecialMethod(t, target, class_)) { @@ -4239,7 +4222,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, methodFlags(t, target) & ACC_STATIC); @@ -4255,7 +4237,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object target = resolveMethod(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); @@ -4389,7 +4370,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, c->jmp(frame->machineIp(newIp)); saveStateAndCompile(t, frame, newIp); - if (UNLIKELY(t->exception)) return; frame->endSubroutine(start); } break; @@ -4423,8 +4403,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, Compiler::Operand* b = frame->popLong(); if (not integerBranch(t, frame, code, ip, 8, a, b)) { - if (UNLIKELY(t->exception)) return; - frame->pushInt (c->call (c->constant @@ -4459,7 +4437,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, object v = singletonObject(t, pool, index - 1); if (objectClass(t, v) == type(t, Machine::ReferenceType)) { v = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; } if (objectClass(t, v) == type(t, Machine::ClassType)) { @@ -4561,7 +4538,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (pairCount) { Compiler::Operand* start = 0; - RUNTIME_ARRAY(uint32_t, ipTable, pairCount); + THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, pairCount); for (int32_t i = 0; i < pairCount; ++i) { unsigned index = ip + (i * 8); int32_t key = codeReadInt32(t, code, index); @@ -4590,7 +4567,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, for (int32_t i = 0; i < pairCount; ++i) { compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - if (UNLIKELY(t->exception)) return; c->restoreState(state); } @@ -4704,7 +4680,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint8_t dimensions = codeBody(t, code, ip++); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; PROTECT(t, class_); unsigned offset @@ -4731,7 +4706,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; if (classVmFlags(t, class_) & (WeakReferenceFlag | HasFinalizerFlag)) { frame->pushObject @@ -4786,7 +4760,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, context->method, index - 1); - if (UNLIKELY(t->exception)) return; object staticTable = 0; @@ -4986,7 +4959,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, int32_t top = codeReadInt32(t, code, ip); Compiler::Operand* start = 0; - RUNTIME_ARRAY(uint32_t, ipTable, top - bottom + 1); + THREAD_RUNTIME_ARRAY(t, uint32_t, ipTable, top - bottom + 1); for (int32_t i = 0; i < top - bottom + 1; ++i) { unsigned index = ip + (i * 4); uint32_t newIp = base + codeReadInt32(t, code, index); @@ -5032,7 +5005,6 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, for (int32_t i = 0; i < top - bottom + 1; ++i) { compile(t, frame, RUNTIME_ARRAY_BODY(ipTable)[i]); - if (UNLIKELY(t->exception)) return; c->restoreState(state); } @@ -5154,7 +5126,6 @@ translateExceptionHandlerTable(MyThread* t, Compiler* c, object method, if (exceptionHandlerCatchType(oldHandler)) { type = resolveClassInPool (t, method, exceptionHandlerCatchType(oldHandler) - 1); - if (UNLIKELY(t->exception)) return 0; } else { type = 0; } @@ -5277,7 +5248,7 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, unsigned mapSize = frameMapSizeInWords(t, context->method); - RUNTIME_ARRAY(uintptr_t, roots, mapSize); + THREAD_RUNTIME_ARRAY(t, uintptr_t, roots, mapSize); if (originalRoots) { memcpy(RUNTIME_ARRAY_BODY(roots), originalRoots, mapSize * BytesPerWord); } else { @@ -5708,7 +5679,7 @@ makeGeneralFrameMapTable(MyThread* t, Context* context, uint8_t* start, pathIndex = subroutine->tableIndex; - RUNTIME_ARRAY(SubroutineTrace*, traces, p->subroutineTraceCount); + THREAD_RUNTIME_ARRAY(t, SubroutineTrace*, traces, p->subroutineTraceCount); unsigned i = 0; for (SubroutineTrace* trace = p->subroutineTrace; trace; trace = trace->next) @@ -5826,11 +5797,16 @@ finish(MyThread* t, Allocator* allocator, Context* context) (context->leaf ? 0 : stackOverflowThunk(t), difference(&(t->stackLimit), t)); - uintptr_t* code = static_cast - (allocator->allocate(pad(codeSize) + pad(c->poolSize()) + BytesPerWord)); + unsigned total = pad(codeSize) + pad(c->poolSize()) + BytesPerWord; + + uintptr_t* code = static_cast(allocator->allocate(total)); code[0] = codeSize; uint8_t* start = reinterpret_cast(code + 1); + context->executableAllocator = allocator; + context->executableStart = code; + context->executableSize = total; + if (context->objectPool) { object pool = allocate3 (t, allocator, Machine::ImmortalAllocation, @@ -5868,7 +5844,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) object newExceptionHandlerTable = translateExceptionHandlerTable (t, c, context->method, reinterpret_cast(start)); - if (UNLIKELY(t->exception)) return; + PROTECT(t, newExceptionHandlerTable); object newLineNumberTable = translateLineNumberTable @@ -5885,7 +5861,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) } if (context->traceLogCount) { - RUNTIME_ARRAY(TraceElement*, elements, context->traceLogCount); + THREAD_RUNTIME_ARRAY(t, TraceElement*, elements, context->traceLogCount); unsigned index = 0; unsigned pathFootprint = 0; unsigned mapCount = 0; @@ -5978,7 +5954,7 @@ compile(MyThread* t, Context* context) c->init(codeLength(t, methodCode(t, context->method)), footprint, locals, alignedFrameSize(t, context->method)); - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame(context, RUNTIME_ARRAY_BODY(stackMap)); @@ -6029,7 +6005,6 @@ compile(MyThread* t, Context* context) Compiler::State* state = c->saveState(); compile(t, &frame, 0); - if (UNLIKELY(t->exception)) return; context->dirtyRoots = false; unsigned eventIndex = calculateFrameMaps(t, context, 0, 0); @@ -6040,7 +6015,7 @@ compile(MyThread* t, Context* context) unsigned visitCount = exceptionHandlerTableLength(t, eht); - RUNTIME_ARRAY(bool, visited, visitCount); + THREAD_RUNTIME_ARRAY(t, bool, visited, visitCount); memset(RUNTIME_ARRAY_BODY(visited), 0, visitCount * sizeof(bool)); while (visitCount) { @@ -6059,7 +6034,7 @@ compile(MyThread* t, Context* context) RUNTIME_ARRAY_BODY(visited)[i] = true; progress = true; - RUNTIME_ARRAY(uint8_t, stackMap, + THREAD_RUNTIME_ARRAY(t, uint8_t, stackMap, codeMaxStack(t, methodCode(t, context->method))); Frame frame2(&frame, RUNTIME_ARRAY_BODY(stackMap)); @@ -6082,7 +6057,6 @@ compile(MyThread* t, Context* context) } compile(t, &frame2, exceptionHandlerIp(eh), start); - if (UNLIKELY(t->exception)) return; context->eventLog.append(PopContextEvent); @@ -6112,47 +6086,41 @@ compileMethod2(MyThread* t, void* ip) object node = findCallNode(t, ip); object target = callNodeTarget(t, node); - if (LIKELY(t->exception == 0)) { - PROTECT(t, node); - PROTECT(t, target); + PROTECT(t, node); + PROTECT(t, target); - t->trace->targetMethod = target; + t->trace->targetMethod = target; - compile(t, codeAllocator(t), 0, target); + THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0); - t->trace->targetMethod = 0; - } + compile(t, codeAllocator(t), 0, target); - if (UNLIKELY(t->exception)) { - return 0; + uintptr_t address; + if ((methodFlags(t, target) & ACC_NATIVE) + and useLongJump(t, reinterpret_cast(ip))) + { + address = bootNativeThunk(t); } else { - uintptr_t address; - if ((methodFlags(t, target) & ACC_NATIVE) - and useLongJump(t, reinterpret_cast(ip))) - { - address = bootNativeThunk(t); - } else { - address = methodAddress(t, target); - } - uint8_t* updateIp = static_cast(ip); - - UnaryOperation op; - if (callNodeFlags(t, node) & TraceElement::LongCall) { - if (callNodeFlags(t, node) & TraceElement::TailCall) { - op = AlignedLongJump; - } else { - op = AlignedLongCall; - } - } else if (callNodeFlags(t, node) & TraceElement::TailCall) { - op = AlignedJump; - } else { - op = AlignedCall; - } - - updateCall(t, op, updateIp, reinterpret_cast(address)); - - return reinterpret_cast(address); + address = methodAddress(t, target); } + uint8_t* updateIp = static_cast(ip); + + UnaryOperation op; + if (callNodeFlags(t, node) & TraceElement::LongCall) { + if (callNodeFlags(t, node) & TraceElement::TailCall) { + op = AlignedLongJump; + } else { + op = AlignedLongCall; + } + } else if (callNodeFlags(t, node) & TraceElement::TailCall) { + op = AlignedJump; + } else { + op = AlignedCall; + } + + updateCall(t, op, updateIp, reinterpret_cast(address)); + + return reinterpret_cast(address); } uint64_t @@ -6166,13 +6134,7 @@ compileMethod(MyThread* t) ip = t->arch->frameIp(t->stack); } - void* r = compileMethod2(t, ip); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } + return reinterpret_cast(compileMethod2(t, ip)); } void* @@ -6190,28 +6152,22 @@ compileVirtualMethod2(MyThread* t, object class_, unsigned index) } t->trace->targetMethod = arrayBody(t, classVirtualTable(t, c), index); + THREAD_RESOURCE0(t, static_cast(t)->trace->targetMethod = 0;); + PROTECT(t, class_); object target = resolveTarget(t, class_, index); PROTECT(t, target); - if (LIKELY(t->exception == 0)) { - compile(t, codeAllocator(t), 0, target); - } + compile(t, codeAllocator(t), 0, target); - t->trace->targetMethod = 0; - - if (UNLIKELY(t->exception)) { - return 0; + void* address = reinterpret_cast(methodAddress(t, target)); + if (methodFlags(t, target) & ACC_NATIVE) { + t->trace->nativeMethod = target; } else { - void* address = reinterpret_cast(methodAddress(t, target)); - if (methodFlags(t, target) & ACC_NATIVE) { - t->trace->nativeMethod = target; - } else { - classVtable(t, class_, methodOffset(t, target)) = address; - } - return address; + classVtable(t, class_, methodOffset(t, target)) = address; } + return address; } uint64_t @@ -6223,13 +6179,7 @@ compileVirtualMethod(MyThread* t) unsigned index = t->virtualCallIndex; t->virtualCallIndex = 0; - void* r = compileVirtualMethod2(t, class_, index); - - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - return reinterpret_cast(r); - } + return reinterpret_cast(compileVirtualMethod2(t, class_, index)); } uint64_t @@ -6253,9 +6203,9 @@ invokeNativeSlow(MyThread* t, object method, void* function) } unsigned count = methodParameterCount(t, method) + 2; - RUNTIME_ARRAY(uintptr_t, args, footprint); + THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned argOffset = 0; - RUNTIME_ARRAY(uint8_t, types, count); + THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); unsigned typeOffset = 0; RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); @@ -6337,6 +6287,10 @@ invokeNativeSlow(MyThread* t, object method, void* function) { ENTER(t, Thread::IdleState); + bool noThrow = t->checkpoint->noThrow; + t->checkpoint->noThrow = true; + THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); + result = t->m->system->call (function, RUNTIME_ARRAY_BODY(args), @@ -6360,43 +6314,45 @@ invokeNativeSlow(MyThread* t, object method, void* function) &byteArrayBody(t, methodName(t, method), 0)); } - if (LIKELY(t->exception == 0)) { - switch (returnCode) { - case ByteField: - case BooleanField: - result = static_cast(result); - break; + if (UNLIKELY(t->exception)) { + object exception = t->exception; + t->exception = 0; + vm::throw_(t, exception); + } - case CharField: - result = static_cast(result); - break; + switch (returnCode) { + case ByteField: + case BooleanField: + result = static_cast(result); + break; - case ShortField: - result = static_cast(result); - break; + case CharField: + result = static_cast(result); + break; - case FloatField: - case IntField: - result = static_cast(result); - break; + case ShortField: + result = static_cast(result); + break; - case LongField: - case DoubleField: - break; + case FloatField: + case IntField: + result = static_cast(result); + break; - case ObjectField: - result = static_cast(result) ? *reinterpret_cast - (static_cast(result)) : 0; - break; + case LongField: + case DoubleField: + break; - case VoidField: - result = 0; - break; + case ObjectField: + result = static_cast(result) ? *reinterpret_cast + (static_cast(result)) : 0; + break; - default: abort(t); - } - } else { + case VoidField: result = 0; + break; + + default: abort(t); } while (t->reference != reference) { @@ -6442,41 +6398,35 @@ invokeNative(MyThread* t) uint64_t result = 0; t->trace->targetMethod = t->trace->nativeMethod; + + THREAD_RESOURCE0(t, { + static_cast(t)->trace->targetMethod = 0; + static_cast(t)->trace->nativeMethod = 0; + }); - if (LIKELY(t->exception == 0)) { - resolveNative(t, t->trace->nativeMethod); + resolveNative(t, t->trace->nativeMethod); - if (LIKELY(t->exception == 0)) { - result = invokeNative2(t, t->trace->nativeMethod); - } - } + result = invokeNative2(t, t->trace->nativeMethod); unsigned parameterFootprint = methodParameterFootprint (t, t->trace->targetMethod); - t->trace->targetMethod = 0; - t->trace->nativeMethod = 0; + uintptr_t* stack = static_cast(t->stack); - if (UNLIKELY(t->exception)) { - unwind(t); - } else { - uintptr_t* stack = static_cast(t->stack); - - if (TailCalls - and t->arch->argumentFootprint(parameterFootprint) - > t->arch->stackAlignmentInWords()) - { - stack += t->arch->argumentFootprint(parameterFootprint) - - t->arch->stackAlignmentInWords(); - } - - stack += t->arch->frameReturnAddressSize(); - - transition(t, t->arch->frameIp(t->stack), stack, t->base, t->continuation, - t->trace); - - return result; + if (TailCalls + and t->arch->argumentFootprint(parameterFootprint) + > t->arch->stackAlignmentInWords()) + { + stack += t->arch->argumentFootprint(parameterFootprint) + - t->arch->stackAlignmentInWords(); } + + stack += t->arch->frameReturnAddressSize(); + + transition(t, t->arch->frameIp(t->stack), stack, t->base, t->continuation, + t->trace); + + return result; } void @@ -6807,7 +6757,7 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) } unsigned argumentCount = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, arguments, argumentCount); + THREAD_RUNTIME_ARRAY(t, uintptr_t, arguments, argumentCount); va_list a; va_start(a, stack); for (unsigned i = 0; i < argumentCount; ++i) { RUNTIME_ARRAY_BODY(arguments)[i] = va_arg(a, uintptr_t); @@ -6832,8 +6782,7 @@ callContinuation(MyThread* t, object continuation, object result, enum { Call, Unwind, - Rewind, - Throw + Rewind } action; object nextContinuation = 0; @@ -6894,25 +6843,15 @@ callContinuation(MyThread* t, object continuation, object result, "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); - if (method) { - setRoot(t, RewindMethod, method); + setRoot(t, RewindMethod, method); - compile(t, local::codeAllocator(t), 0, method); - - if (UNLIKELY(t->exception)) { - action = Throw; - } - } else { - action = Throw; - } + compile(t, local::codeAllocator(t), 0, method); } } else { action = Call; } } else { - t->exception = makeThrowable - (t, Machine::IncompatibleContinuationExceptionType); - action = Throw; + throwNew(t, Machine::IncompatibleContinuationExceptionType); } } else { action = Call; @@ -6942,12 +6881,6 @@ callContinuation(MyThread* t, object continuation, object result, continuation, result, exception); } break; - case Throw: { - transition(t, ip, stack, base, threadContinuation, t->trace); - - vmJump(ip, base, stack, t, 0, 0); - } break; - default: abort(t); } @@ -6981,24 +6914,16 @@ callWithCurrentContinuation(MyThread* t, object receiver) } } - if (LIKELY(t->exception == 0)) { - method = findInterfaceMethod - (t, root(t, ReceiveMethod), objectClass(t, receiver)); - PROTECT(t, method); + method = findInterfaceMethod + (t, root(t, ReceiveMethod), objectClass(t, receiver)); + PROTECT(t, method); - compile(t, local::codeAllocator(t), 0, method); + compile(t, local::codeAllocator(t), 0, method); - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); - } - } + t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); } - if (LIKELY(t->exception == 0)) { - jumpAndInvoke(t, method, base, stack, receiver, t->continuation); - } else { - unwind(t); - } + jumpAndInvoke(t, method, base, stack, receiver, t->continuation); } void @@ -7024,22 +6949,16 @@ dynamicWind(MyThread* t, object before, object thunk, object after) } } - if (LIKELY(t->exception == 0)) { - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); + t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); - object newContext = makeContinuationContext - (t, continuationContext(t, t->continuation), before, after, - t->continuation, t->trace->originalMethod); + object newContext = makeContinuationContext + (t, continuationContext(t, t->continuation), before, after, + t->continuation, t->trace->originalMethod); - set(t, t->continuation, ContinuationContext, newContext); - } + set(t, t->continuation, ContinuationContext, newContext); } - if (LIKELY(t->exception == 0)) { - jumpAndInvoke(t, root(t, WindMethod), base, stack, before, thunk, after); - } else { - unwind(t); - } + jumpAndInvoke(t, root(t, WindMethod), base, stack, before, thunk, after); } class ArgumentList { @@ -7176,10 +7095,12 @@ invoke(Thread* thread, object method, ArgumentList* arguments) if (stackLimit == 0) { t->stackLimit = stackPosition - StackSizeInBytes; } else if (stackPosition < stackLimit) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } + THREAD_RESOURCE(t, uintptr_t, stackLimit, + static_cast(t)->stackLimit = stackLimit); + unsigned returnCode = methodReturnCode(t, method); unsigned returnType = fieldType(t, returnCode); @@ -7187,6 +7108,8 @@ invoke(Thread* thread, object method, ArgumentList* arguments) { MyThread::CallTrace trace(t, method); + MyCheckpoint checkpoint(t); + assert(t, arguments->position == arguments->size); result = vmInvoke @@ -7199,13 +7122,14 @@ invoke(Thread* thread, object method, ArgumentList* arguments) returnType); } - t->stackLimit = stackLimit; - if (t->exception) { if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { collect(t, Heap::MinorCollection); } - return 0; + + object exception = t->exception; + t->exception = 0; + vm::throw_(t, exception); } object r; @@ -7526,7 +7450,7 @@ class MyProcessor: public Processor { virtual object invokeArray(Thread* t, object method, object this_, object arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); @@ -7539,8 +7463,8 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, arguments); @@ -7550,18 +7474,14 @@ class MyProcessor: public Processor { compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - - return 0; + return local::invoke(t, method, &list); } virtual object invokeList(Thread* t, object method, object this_, bool indirectObjects, va_list arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); @@ -7574,8 +7494,8 @@ class MyProcessor: public Processor { (&byteArrayBody(t, methodSpec(t, method), 0)); unsigned size = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, spec, indirectObjects, arguments); @@ -7585,11 +7505,7 @@ class MyProcessor: public Processor { compile(static_cast(t), local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - - return 0; + return local::invoke(t, method, &list); } virtual object @@ -7597,34 +7513,29 @@ class MyProcessor: public Processor { const char* methodName, const char* methodSpec, object this_, va_list arguments) { - if (UNLIKELY(t->exception)) return 0; + assert(t, t->exception == 0); assert(t, t->state == Thread::ActiveState or t->state == Thread::ExclusiveState); unsigned size = parameterFootprint(t, methodSpec, this_ == 0); - RUNTIME_ARRAY(uintptr_t, array, size); - RUNTIME_ARRAY(bool, objectMask, size); + THREAD_RUNTIME_ARRAY(t, uintptr_t, array, size); + THREAD_RUNTIME_ARRAY(t, bool, objectMask, size); ArgumentList list (t, RUNTIME_ARRAY_BODY(array), size, RUNTIME_ARRAY_BODY(objectMask), this_, methodSpec, false, arguments); object method = resolveMethod (t, loader, className, methodName, methodSpec); - if (LIKELY(t->exception == 0)) { - assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - PROTECT(t, method); + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + + PROTECT(t, method); - compile(static_cast(t), - local::codeAllocator(static_cast(t)), 0, method); + compile(static_cast(t), + local::codeAllocator(static_cast(t)), 0, method); - if (LIKELY(t->exception == 0)) { - return local::invoke(t, method, &list); - } - } - - return 0; + return local::invoke(t, method, &list); } virtual void dispose(Thread* vmt) { @@ -8762,7 +8673,6 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (bootContext == 0) { initClass(t, methodClass(t, method)); - if (UNLIKELY(t->exception)) return; } if (methodAddress(t, method) != defaultThunk(t)) { @@ -8790,7 +8700,6 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, Context context(t, bootContext, clone); compile(t, &context); - if (UNLIKELY(t->exception)) return; { object ehTable = codeExceptionHandlerTable(t, methodCode(t, clone)); @@ -8804,7 +8713,6 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, if (exceptionHandlerCatchType(handler)) { resolveClassInPool (t, clone, exceptionHandlerCatchType(handler) - 1); - if (UNLIKELY(t->exception)) return; } } } @@ -8817,7 +8725,6 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, } finish(t, allocator, &context); - if (UNLIKELY(t->exception)) return; if (DebugMethodTree) { fprintf(stderr, "insert method at %p\n", @@ -8849,6 +8756,11 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext, = reinterpret_cast(methodCompiled(t, clone)); } + // we've compiled the method and inserted it into the tree without + // error, so we ensure that the executable area not be deallocated + // when we dispose of the context: + context.executableAllocator = 0; + treeUpdate(t, root(t, MethodTree), methodCompiled(t, clone), method, root(t, MethodTreeSentinal), compareIpToMethodBounds); } diff --git a/src/continuations-x86.S b/src/continuations-x86.S index f0688a9e51..de30be72ac 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 2224 +#define THREAD_CONTINUATION 2240 #define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232 -#define THREAD_EXCEPTION_OFFSET 2240 -#define THREAD_EXCEPTION_HANDLER 2248 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2248 +#define THREAD_EXCEPTION_OFFSET 2256 +#define THREAD_EXCEPTION_HANDLER 2264 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 2148 +#define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 -#define THREAD_EXCEPTION_OFFSET 2156 -#define THREAD_EXCEPTION_HANDLER 2160 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/heap.cpp b/src/heap.cpp index f8969caa98..7f923da02d 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -68,6 +68,7 @@ void assert(Context*, bool); System* system(Context*); void* tryAllocate(Context* c, unsigned size); +void* allocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); void outOfMemory(Context*); @@ -360,7 +361,9 @@ class Segment { break; } } else { - outOfMemory(context); + data = static_cast + (local::allocate + (context, (footprint(capacity_)) * BytesPerWord)); } } } @@ -1710,7 +1713,7 @@ collect(Context* c) } void* -tryAllocate(Context* c, unsigned size) +allocate(Context* c, unsigned size, bool limit) { ACQUIRE(c->lock); @@ -1718,7 +1721,7 @@ tryAllocate(Context* c, unsigned size) size = pad(size) + 2 * BytesPerWord; } - if (size + c->count < c->limit) { + if ((not limit) or size + c->count < c->limit) { void* p = c->system->tryAllocate(size); if (p) { c->count += size; @@ -1735,6 +1738,18 @@ tryAllocate(Context* c, unsigned size) return 0; } +void* +tryAllocate(Context* c, unsigned size) +{ + return allocate(c, size, true); +} + +void* +allocate(Context* c, unsigned size) +{ + return allocate(c, size, false); +} + void free(Context* c, const void* p, unsigned size) { @@ -1787,16 +1802,16 @@ class MyHeap: public Heap { c.immortalHeapEnd = start + sizeInWords; } + virtual bool limitExceeded() { + return c.count > c.limit; + } + virtual void* tryAllocate(unsigned size) { return local::tryAllocate(&c, size); } virtual void* allocate(unsigned size) { - void* p = local::tryAllocate(&c, size); - if (p == 0) { - c.client->outOfMemory(); - } - return p; + return local::allocate(&c, size); } virtual void free(const void* p, unsigned size) { diff --git a/src/heap.h b/src/heap.h index a045fd9526..3f454d6be0 100644 --- a/src/heap.h +++ b/src/heap.h @@ -54,6 +54,7 @@ class Heap: public Allocator { virtual void setClient(Client* client) = 0; virtual void setImmortalHeap(uintptr_t* start, unsigned sizeInWords) = 0; + virtual bool limitExceeded() = 0; virtual void collect(CollectionType type, unsigned footprint) = 0; virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords, bool objectMask, unsigned* totalInBytes) = 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index fd1bbcbcf3..7ca4fcb0a2 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -375,7 +375,7 @@ popFrame(Thread* t) if (UNLIKELY(methodVmFlags(t, method) & ClassInitFlag) and t->classInitList and t->classInitList->class_ == methodClass(t, method)) - { + { t->classInitList->pop(); postInitClass(t, methodClass(t, method)); @@ -435,7 +435,7 @@ checkStack(Thread* t, object method) + codeMaxStack(t, methodCode(t, method)) > StackSizeInWords / 2)) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); + throwNew(t, Machine::StackOverflowErrorType); } } @@ -570,9 +570,9 @@ invokeNativeSlow(Thread* t, object method, void* function) } unsigned count = methodParameterCount(t, method) + 2; - RUNTIME_ARRAY(uintptr_t, args, footprint); + THREAD_RUNTIME_ARRAY(t, uintptr_t, args, footprint); unsigned argOffset = 0; - RUNTIME_ARRAY(uint8_t, types, count); + THREAD_RUNTIME_ARRAY(t, uint8_t, types, count); unsigned typeOffset = 0; RUNTIME_ARRAY_BODY(args)[argOffset++] = reinterpret_cast(t); @@ -613,6 +613,10 @@ invokeNativeSlow(Thread* t, object method, void* function) { ENTER(t, Thread::IdleState); + bool noThrow = t->checkpoint->noThrow; + t->checkpoint->noThrow = true; + THREAD_RESOURCE(t, bool, noThrow, t->checkpoint->noThrow = noThrow); + result = t->m->system->call (function, RUNTIME_ARRAY_BODY(args), @@ -633,7 +637,9 @@ invokeNativeSlow(Thread* t, object method, void* function) popFrame(t); if (UNLIKELY(t->exception)) { - return VoidField; + object exception = t->exception; + t->exception = 0; + throw_(t, exception); } pushResult(t, returnCode, result, true); @@ -648,10 +654,6 @@ invokeNative(Thread* t, object method) resolveNative(t, method); - if (UNLIKELY(t->exception)) { - return VoidField; - } - object native = methodRuntimeDataNative(t, getMethodRuntimeData(t, method)); if (nativeFast(t, native)) { pushFrame(t, method); @@ -673,10 +675,6 @@ invokeNative(Thread* t, object method) popFrame(t); - if (UNLIKELY(t->exception)) { - return VoidField; - } - pushResult(t, methodReturnCode(t, method), result, false); return methodReturnCode(t, method); @@ -802,10 +800,8 @@ pushField(Thread* t, object target, object field) } object -interpret(Thread* t) +interpret3(Thread* t, const int base) { - const int base = t->frame; - unsigned instruction = nop; unsigned& ip = t->ip; unsigned& sp = t->sp; @@ -858,10 +854,9 @@ interpret(Thread* t) { pushObject(t, objectArrayBody(t, array, index)); } else { - object message = makeString - (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, objectArrayLength(t, array)); goto throw_; } } else { @@ -881,10 +876,9 @@ interpret(Thread* t) { set(t, array, ArrayBody + (index * BytesPerWord), value); } else { - object message = makeString - (t, "%d not in [0,%d)", index, objectArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, objectArrayLength(t, array)); goto throw_; } } else { @@ -924,13 +918,11 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; pushObject(t, makeObjectArray(t, class_, count)); } else { - object message = makeString(t, "%d", count); exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); + (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; @@ -995,10 +987,9 @@ interpret(Thread* t) { pushInt(t, booleanArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - booleanArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { @@ -1008,11 +999,9 @@ interpret(Thread* t) { pushInt(t, byteArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - byteArrayLength(t, array)); - exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } @@ -1035,10 +1024,9 @@ interpret(Thread* t) { booleanArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - booleanArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, booleanArrayLength(t, array)); goto throw_; } } else { @@ -1047,10 +1035,9 @@ interpret(Thread* t) { byteArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - byteArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, + "%d not in [0,%d)", index, byteArrayLength(t, array)); goto throw_; } } @@ -1074,10 +1061,9 @@ interpret(Thread* t) { pushInt(t, charArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - charArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, charArrayLength(t, array)); goto throw_; } } else { @@ -1097,10 +1083,9 @@ interpret(Thread* t) { charArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - charArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, charArrayLength(t, array)); goto throw_; } } else { @@ -1117,13 +1102,11 @@ interpret(Thread* t) if (UNLIKELY(exception)) goto throw_; if (not instanceOf(t, class_, peekObject(t, sp - 1))) { - object message = makeString - (t, "%s as %s", + exception = makeThrowable + (t, Machine::ClassCastExceptionType, "%s as %s", &byteArrayBody (t, className(t, objectClass(t, peekObject(t, sp - 1))), 0), &byteArrayBody(t, className(t, class_), 0)); - exception = makeThrowable - (t, Machine::ClassCastExceptionType, message); goto throw_; } } @@ -1158,10 +1141,9 @@ interpret(Thread* t) { pushLong(t, doubleArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - doubleArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, doubleArrayLength(t, array)); goto throw_; } } else { @@ -1181,10 +1163,9 @@ interpret(Thread* t) { memcpy(&doubleArrayBody(t, array, index), &value, sizeof(uint64_t)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - doubleArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, doubleArrayLength(t, array)); goto throw_; } } else { @@ -1360,10 +1341,9 @@ interpret(Thread* t) { pushInt(t, floatArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - floatArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, floatArrayLength(t, array)); goto throw_; } } else { @@ -1383,10 +1363,9 @@ interpret(Thread* t) { memcpy(&floatArrayBody(t, array, index), &value, sizeof(uint32_t)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - floatArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, floatArrayLength(t, array)); goto throw_; } } else { @@ -1476,7 +1455,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); @@ -1511,7 +1489,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, fieldFlags(t, field) & ACC_STATIC); @@ -1592,10 +1569,9 @@ interpret(Thread* t) { pushInt(t, intArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - intArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, intArrayLength(t, array)); goto throw_; } } else { @@ -1622,10 +1598,9 @@ interpret(Thread* t) { intArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - intArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, intArrayLength(t, array)); goto throw_; } } else { @@ -1874,7 +1849,6 @@ interpret(Thread* t) if (peekObject(t, sp - 1)) { object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; if (instanceOf(t, class_, popObject(t))) { pushInt(t, 1); @@ -1893,7 +1867,6 @@ interpret(Thread* t) ip += 2; object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -1910,7 +1883,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -1935,7 +1907,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, method); if (UNLIKELY(classInit(t, methodClass(t, method), 3))) goto invoke; @@ -1947,7 +1918,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object method = resolveMethod(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; unsigned parameterFootprint = methodParameterFootprint(t, method); if (LIKELY(peekObject(t, sp - parameterFootprint))) { @@ -2096,10 +2066,9 @@ interpret(Thread* t) { pushLong(t, longArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - longArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, longArrayLength(t, array)); goto throw_; } } else { @@ -2126,10 +2095,9 @@ interpret(Thread* t) { longArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - longArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, longArrayLength(t, array)); goto throw_; } } else { @@ -2170,7 +2138,6 @@ interpret(Thread* t) if (objectClass(t, v) == type(t, Machine::ReferenceType)) { object class_ = resolveClassInPool (t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; pushObject(t, getJClass(t, class_)); } else if (objectClass(t, v) == type(t, Machine::ClassType)) { @@ -2389,16 +2356,14 @@ interpret(Thread* t) uint8_t dimensions = codeBody(t, code, ip++); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, class_); int32_t counts[dimensions]; for (int i = dimensions - 1; i >= 0; --i) { counts[i] = popInt(t); if (UNLIKELY(counts[i] < 0)) { - object message = makeString(t, "%d", counts[i]); exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); + (t, Machine::NegativeArraySizeExceptionType, "%d", counts[i]); goto throw_; } } @@ -2416,7 +2381,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object class_ = resolveClassInPool(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; PROTECT(t, class_); if (UNLIKELY(classInit(t, class_, 3))) goto invoke; @@ -2470,9 +2434,8 @@ interpret(Thread* t) pushObject(t, array); } else { - object message = makeString(t, "%d", count); exception = makeThrowable - (t, Machine::NegativeArraySizeExceptionType, message); + (t, Machine::NegativeArraySizeExceptionType, "%d", count); goto throw_; } } goto loop; @@ -2491,7 +2454,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, (fieldFlags(t, field) & ACC_STATIC) == 0); PROTECT(t, field); @@ -2582,7 +2544,6 @@ interpret(Thread* t) uint16_t index = codeReadInt16(t, code, ip); object field = resolveField(t, frameMethod(t, frame), index - 1); - if (UNLIKELY(exception)) goto throw_; assert(t, fieldFlags(t, field) & ACC_STATIC); @@ -2683,10 +2644,9 @@ interpret(Thread* t) { pushInt(t, shortArrayBody(t, array, index)); } else { - object message = makeString(t, "%d not in [0,%d)", index, - shortArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, shortArrayLength(t, array)); goto throw_; } } else { @@ -2706,10 +2666,9 @@ interpret(Thread* t) { shortArrayBody(t, array, index) = value; } else { - object message = makeString(t, "%d not in [0,%d)", index, - shortArrayLength(t, array)); exception = makeThrowable - (t, Machine::ArrayIndexOutOfBoundsExceptionType, message); + (t, Machine::ArrayIndexOutOfBoundsExceptionType, "%d not in [0,%d)", + index, shortArrayLength(t, array)); goto throw_; } } else { @@ -2771,7 +2730,6 @@ interpret(Thread* t) resolveClass(t, classLoader(t, methodClass(t, frameMethod(t, frame))), className(t, class_)); - if (UNLIKELY(exception)) goto throw_; ip -= 3; } goto loop; @@ -2822,11 +2780,8 @@ interpret(Thread* t) invoke: { if (methodFlags(t, code) & ACC_NATIVE) { invokeNative(t, code); - if (UNLIKELY(exception)) goto throw_; } else { checkStack(t, code); - if (UNLIKELY(exception)) goto throw_; - pushFrame(t, code); } } goto loop; @@ -2851,6 +2806,39 @@ interpret(Thread* t) return 0; } +uint64_t +interpret2(vm::Thread* t, uintptr_t* arguments) +{ + int base = arguments[0]; + bool* success = reinterpret_cast(arguments[1]); + + object r = interpret3(static_cast(t), base); + *success = true; + return reinterpret_cast(r); +} + +object +interpret(Thread* t) +{ + const int base = t->frame; + + while (true) { + bool success = false; + uintptr_t arguments[] = { base, reinterpret_cast(&success) }; + + uint64_t r = run(t, interpret2, arguments); + if (success) { + if (t->exception) { + object exception = t->exception; + t->exception = 0; + throw_(t, exception); + } else { + return reinterpret_cast(r); + } + } + } +} + void pushArguments(Thread* t, object this_, const char* spec, bool indirectObjects, va_list a) @@ -2957,47 +2945,45 @@ invoke(Thread* t, object method) if (methodFlags(t, method) & ACC_NATIVE) { unsigned returnCode = invokeNative(t, method); - if (LIKELY(t->exception == 0)) { - switch (returnCode) { - case ByteField: - case BooleanField: - case CharField: - case ShortField: - case FloatField: - case IntField: - result = makeInt(t, popInt(t)); - break; + switch (returnCode) { + case ByteField: + case BooleanField: + case CharField: + case ShortField: + case FloatField: + case IntField: + result = makeInt(t, popInt(t)); + break; - case LongField: - case DoubleField: - result = makeLong(t, popLong(t)); - break; + case LongField: + case DoubleField: + result = makeLong(t, popLong(t)); + break; - case ObjectField: - result = popObject(t); - break; + case ObjectField: + result = popObject(t); + break; - case VoidField: - result = 0; - break; + case VoidField: + result = 0; + break; - default: - abort(t); - }; - } + default: + abort(t); + }; } else { checkStack(t, method); - if (LIKELY(t->exception == 0)) { - pushFrame(t, method); - result = interpret(t); - if (LIKELY(t->exception == 0)) { - popFrame(t); - } - } - } + pushFrame(t, method); - if (UNLIKELY(t->exception)) { - return 0; + result = interpret(t); + + if (LIKELY(t->exception == 0)) { + popFrame(t); + } else { + object exception = t->exception; + t->exception = 0; + throw_(t, exception); + } } return result; @@ -3155,8 +3141,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > StackSizeInWords / 2)) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast @@ -3180,8 +3165,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + methodParameterFootprint(t, method) + 1 > StackSizeInWords / 2)) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } const char* spec = reinterpret_cast @@ -3204,8 +3188,7 @@ class MyProcessor: public Processor { if (UNLIKELY(t->sp + parameterFootprint(vmt, methodSpec, false) > StackSizeInWords / 2)) { - t->exception = makeThrowable(t, Machine::StackOverflowErrorType); - return 0; + throwNew(t, Machine::StackOverflowErrorType); } pushArguments(t, this_, methodSpec, false, arguments); @@ -3213,13 +3196,9 @@ class MyProcessor: public Processor { object method = resolveMethod (t, loader, className, methodName, methodSpec); - if (LIKELY(t->exception == 0)) { - assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); + assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0)); - return ::invoke(t, method); - } else { - return 0; - } + return ::invoke(t, method); } virtual object getStackTrace(vm::Thread*, vm::Thread*) { diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 43baf82d92..5a80e8d216 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -71,11 +71,9 @@ DetachCurrentThread(Machine* m) } } -jint JNICALL -DestroyJavaVM(Machine* m) +uint64_t +destroyJavaVM(Thread* t, uintptr_t*) { - Thread* t; AttachCurrentThread(m, &t, 0); - // wait for other non-daemon threads to exit { ACQUIRE(t, t->m->stateLock); while (t->m->liveCount - t->m->daemonCount > 1) { @@ -83,16 +81,22 @@ DestroyJavaVM(Machine* m) } } - { ENTER(t, Thread::ActiveState); + shutDown(t); - shutDown(t); + return 1; +} + +jint JNICALL +DestroyJavaVM(Machine* m) +{ + Thread* t; AttachCurrentThread(m, &t, 0); + + if (run(t, destroyJavaVM, 0)) { + t->exit(); + return 0; + } else { + return -1; } - - int exitCode = (t->exception ? -1 : 0); - - t->exit(); - - return exitCode; } jint JNICALL @@ -233,12 +237,11 @@ GetArrayLength(Thread* t, jarray array) return cast(*array, BytesPerWord); } -jstring JNICALL -NewString(Thread* t, const jchar* chars, jsize size) +uint64_t +newString(Thread* t, uintptr_t* arguments) { - if (chars == 0) return 0; - - ENTER(t, Thread::ActiveState); + const jchar* chars = reinterpret_cast(arguments[0]); + jsize size = arguments[1]; object a = 0; if (size) { @@ -246,7 +249,31 @@ NewString(Thread* t, const jchar* chars, jsize size) memcpy(&charArrayBody(t, a, 0), chars, size * sizeof(jchar)); } - return makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size)); + return reinterpret_cast + (makeLocalReference(t, t->m->classpath->makeString(t, a, 0, size))); +} + +jstring JNICALL +NewString(Thread* t, const jchar* chars, jsize size) +{ + if (chars == 0) return 0; + + uintptr_t arguments[] = { reinterpret_cast(chars), size }; + + return reinterpret_cast(run(t, newString, arguments)); +} + +uint64_t +newStringUTF(Thread* t, uintptr_t* arguments) +{ + const char* chars = reinterpret_cast(arguments[0]); + + object array = parseUtf8(t, chars, strlen(chars)); + + return reinterpret_cast + (makeLocalReference + (t, t->m->classpath->makeString + (t, array, 0, cast(array, BytesPerWord) - 1))); } jstring JNICALL @@ -254,13 +281,9 @@ NewStringUTF(Thread* t, const char* chars) { if (chars == 0) return 0; - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(chars) }; - object array = parseUtf8(t, chars, strlen(chars)); - - return makeLocalReference - (t, t->m->classpath->makeString - (t, array, 0, cast(array, BytesPerWord) - 1)); + return reinterpret_cast(run(t, newStringUTF, arguments)); } void @@ -274,45 +297,63 @@ replace(int a, int b, const char* in, int8_t* out) *out = 0; } +uint64_t +defineClass(Thread* t, uintptr_t* arguments) +{ + jobject loader = reinterpret_cast(arguments[0]); + const uint8_t* buffer = reinterpret_cast(arguments[1]); + jsize length = arguments[2]; + + return reinterpret_cast + (makeLocalReference + (t, getJClass + (t, defineClass + (t, loader ? *loader : root(t, Machine::BootLoader), buffer, length)))); +} + jclass JNICALL DefineClass(Thread* t, const char*, jobject loader, const jbyte* buffer, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(loader), + reinterpret_cast(buffer), + length }; - object c = defineClass - (t, loader ? *loader : root(t, Machine::BootLoader), - reinterpret_cast(buffer), length); - - return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); + return reinterpret_cast(run(t, defineClass, arguments)); } -jclass JNICALL -FindClass(Thread* t, const char* name) +uint64_t +findClass(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + const char* name = reinterpret_cast(arguments[0]); object n = makeByteArray(t, strlen(name) + 1); replace('.', '/', name, &byteArrayBody(t, n, 0)); object caller = getCaller(t, 0); - object c = resolveClass - (t, caller ? classLoader(t, methodClass(t, caller)) - : root(t, Machine::AppLoader), n); - - return makeLocalReference(t, c == 0 ? 0 : getJClass(t, c)); + return reinterpret_cast + (makeLocalReference + (t, getJClass + (t, resolveClass + (t, caller ? classLoader(t, methodClass(t, caller)) + : root(t, Machine::AppLoader), n)))); } -jint JNICALL -ThrowNew(Thread* t, jclass c, const char* message) +jclass JNICALL +FindClass(Thread* t, const char* name) { - if (t->exception) { - return -1; - } + uintptr_t arguments[] = { reinterpret_cast(name) }; + + return reinterpret_cast(run(t, findClass, arguments)); +} + +uint64_t +throwNew(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* message = reinterpret_cast(arguments[1]); - ENTER(t, Thread::ActiveState); - object m = 0; PROTECT(t, m); @@ -327,7 +368,20 @@ ThrowNew(Thread* t, jclass c, const char* message) set(t, t->exception, ThrowableMessage, m); set(t, t->exception, ThrowableTrace, trace); - return 0; + return 1; +} + +jint JNICALL +ThrowNew(Thread* t, jclass c, const char* message) +{ + if (t->exception) { + return -1; + } + + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(message) }; + + return run(t, throwNew, arguments) ? 0 : -1; } jint JNICALL @@ -429,15 +483,40 @@ methodID(Thread* t, object method) return methodNativeID(t, method); } +uint64_t +getMethodID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); + + object method = findMethod(t, c, name, spec); + + assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); + + return methodID(t, method); +} + jmethodID JNICALL GetMethodID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; + + return run(t, getMethodID, arguments); +} + +uint64_t +getStaticMethodID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; - assert(t, (methodFlags(t, method) & ACC_STATIC) == 0); + assert(t, methodFlags(t, method) & ACC_STATIC); return methodID(t, method); } @@ -445,14 +524,11 @@ GetMethodID(Thread* t, jclass c, const char* name, const char* spec) jmethodID JNICALL GetStaticMethodID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object method = findMethod(t, c, name, spec); - if (UNLIKELY(t->exception)) return 0; - - assert(t, methodFlags(t, method) & ACC_STATIC); - - return methodID(t, method); + return run(t, getStaticMethodID, arguments); } inline object @@ -465,17 +541,29 @@ getMethod(Thread* t, jmethodID m) return method; } -jobject JNICALL -NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) +uint64_t +newObjectV(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass c = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); object o = make(t, jclassVmClass(t, *c)); PROTECT(t, o); - t->m->processor->invokeList(t, getMethod(t, m), o, true, a); + t->m->processor->invokeList(t, getMethod(t, m), o, true, *a); - return makeLocalReference(t, o); + return reinterpret_cast(makeLocalReference(t, o)); +} + +jobject JNICALL +NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + m, + reinterpret_cast(a) }; + + return reinterpret_cast(run(t, newObjectV, arguments)); } jobject JNICALL @@ -491,14 +579,27 @@ NewObject(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callObjectMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return reinterpret_cast + (makeLocalReference + (t, t->m->processor->invokeList(t, method, *o, true, *a))); +} + jobject JNICALL CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - return makeLocalReference - (t, t->m->processor->invokeList(t, method, *o, true, a)); + return reinterpret_cast(run(t, callObjectMethodV, arguments)); } jobject JNICALL @@ -514,14 +615,25 @@ CallObjectMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callIntMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return intValue(t, t->m->processor->invokeList(t, method, *o, true, *a)); +} + jboolean JNICALL CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? (intValue(t, r) != 0) : false); + return run(t, callIntMethodV, arguments) != 0; } jboolean JNICALL @@ -540,11 +652,11 @@ CallBooleanMethod(Thread* t, jobject o, jmethodID m, ...) jbyte JNICALL CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jbyte JNICALL @@ -563,11 +675,11 @@ CallByteMethod(Thread* t, jobject o, jmethodID m, ...) jchar JNICALL CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jchar JNICALL @@ -586,11 +698,11 @@ CallCharMethod(Thread* t, jobject o, jmethodID m, ...) jshort JNICALL CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jshort JNICALL @@ -609,11 +721,11 @@ CallShortMethod(Thread* t, jobject o, jmethodID m, ...) jint JNICALL CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callIntMethodV, arguments); } jint JNICALL @@ -629,14 +741,25 @@ CallIntMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callLongMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + return longValue(t, t->m->processor->invokeList(t, method, *o, true, *a)); +} + jlong JNICALL CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? longValue(t, r) : 0); + return run(t, callLongMethodV, arguments); } jlong JNICALL @@ -655,11 +778,11 @@ CallLongMethod(Thread* t, jobject o, jmethodID m, ...) jfloat JNICALL CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? bitsToFloat(intValue(t, r)) : 0); + return bitsToFloat(run(t, callIntMethodV, arguments)); } jfloat JNICALL @@ -678,11 +801,11 @@ CallFloatMethod(Thread* t, jobject o, jmethodID m, ...) jdouble JNICALL CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - object r = t->m->processor->invokeList(t, method, *o, true, a); - return (r ? bitsToDouble(longValue(t, r)) : 0); + return bitsToDouble(run(t, callLongMethodV, arguments)); } jdouble JNICALL @@ -698,13 +821,27 @@ CallDoubleMethod(Thread* t, jobject o, jmethodID m, ...) return r; } +uint64_t +callVoidMethodV(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jmethodID m = arguments[1]; + va_list* a = reinterpret_cast(arguments[2]); + + object method = getMethod(t, m); + t->m->processor->invokeList(t, method, *o, true, *a); + + return 0; +} + void JNICALL CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o), + m, + reinterpret_cast(a) }; - object method = getMethod(t, m); - t->m->processor->invokeList(t, method, *o, true, a); + run(t, callVoidMethodV, arguments); } void JNICALL @@ -728,13 +865,23 @@ getStaticMethod(Thread* t, jmethodID m) return method; } +uint64_t +callStaticObjectMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return reinterpret_cast + (makeLocalReference + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a))); +} + jobject JNICALL CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - return makeLocalReference(t, t->m->processor->invokeList - (t, getStaticMethod(t, m), 0, true, a)); + return reinterpret_cast(run(t, callStaticObjectMethodV, arguments)); } jobject JNICALL @@ -750,13 +897,22 @@ CallStaticObjectMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticIntMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return intValue + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); +} + jboolean JNICALL CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? (intValue(t, r) != 0) : false); + return run(t, callStaticIntMethodV, arguments) != 0; } jboolean JNICALL @@ -775,10 +931,9 @@ CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...) jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jbyte JNICALL @@ -797,10 +952,9 @@ CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...) jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jchar JNICALL @@ -819,10 +973,9 @@ CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...) jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jshort JNICALL @@ -841,10 +994,9 @@ CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...) jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? intValue(t, r) : 0); + return run(t, callStaticIntMethodV, arguments); } jint JNICALL @@ -860,13 +1012,22 @@ CallStaticIntMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticLongMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + return longValue + (t, t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a)); +} + jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? longValue(t, r) : 0); + return run(t, callStaticLongMethodV, arguments); } jlong JNICALL @@ -885,10 +1046,9 @@ CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...) jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? bitsToFloat(intValue(t, r)) : 0); + return bitsToFloat(run(t, callStaticIntMethodV, arguments)); } jfloat JNICALL @@ -907,10 +1067,9 @@ CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...) jdouble JNICALL CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - object r = t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); - return (r ? bitsToDouble(longValue(t, r)) : 0); + return bitsToDouble(run(t, callStaticLongMethodV, arguments)); } jdouble JNICALL @@ -926,12 +1085,23 @@ CallStaticDoubleMethod(Thread* t, jclass c, jmethodID m, ...) return r; } +uint64_t +callStaticVoidMethodV(Thread* t, uintptr_t* arguments) +{ + jmethodID m = arguments[0]; + va_list* a = reinterpret_cast(arguments[1]); + + t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, *a); + + return 0; +} + void JNICALL CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { m, reinterpret_cast(a) }; - t->m->processor->invokeList(t, getStaticMethod(t, m), 0, true, a); + run(t, callStaticVoidMethodV, arguments); } void JNICALL @@ -945,26 +1115,34 @@ CallStaticVoidMethod(Thread* t, jclass c, jmethodID m, ...) va_end(a); } +uint64_t +getFieldID(Thread* t, uintptr_t* arguments) +{ + jclass c = reinterpret_cast(arguments[0]); + const char* name = reinterpret_cast(arguments[1]); + const char* spec = reinterpret_cast(arguments[2]); + + return fieldOffset(t, resolveField(t, jclassVmClass(t, *c), name, spec)); +} + jfieldID JNICALL GetFieldID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object field = resolveField(t, jclassVmClass(t, *c), name, spec); - if (UNLIKELY(t->exception)) return 0; - - return fieldOffset(t, field); + return run(t, getFieldID, arguments); } jfieldID JNICALL GetStaticFieldID(Thread* t, jclass c, const char* name, const char* spec) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(name), + reinterpret_cast(spec) }; - object field = resolveField(t, jclassVmClass(t, *c), name, spec); - if (UNLIKELY(t->exception)) return 0; - - return fieldOffset(t, field); + return run(t, getFieldID, arguments); } jobject JNICALL @@ -1325,17 +1503,29 @@ ExceptionClear(Thread* t) t->exception = 0; } -jobjectArray JNICALL -NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) +uint64_t +newObjectArray(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jsize length = arguments[0]; + jclass class_ = reinterpret_cast(arguments[1]); + jobject init = reinterpret_cast(arguments[2]); object a = makeObjectArray(t, jclassVmClass(t, *class_), length); object value = (init ? *init : 0); for (jsize i = 0; i < length; ++i) { set(t, a, ArrayBody + (i * BytesPerWord), value); } - return makeLocalReference(t, a); + return reinterpret_cast(makeLocalReference(t, a)); +} + +jobjectArray JNICALL +NewObjectArray(Thread* t, jsize length, jclass class_, jobject init) +{ + uintptr_t arguments[] = { length, + reinterpret_cast(class_), + reinterpret_cast(init) }; + + return reinterpret_cast(run(t, newObjectArray, arguments)); } jobject JNICALL @@ -1355,68 +1545,102 @@ SetObjectArrayElement(Thread* t, jobjectArray array, jsize index, set(t, *array, ArrayBody + (index * BytesPerWord), (value ? *value : 0)); } +uint64_t +newArray(Thread* t, uintptr_t* arguments) +{ + object (*constructor)(Thread*, unsigned) + = reinterpret_cast(arguments[0]); + + jsize length = arguments[1]; + + return reinterpret_cast + (makeLocalReference(t, constructor(t, length))); +} + jbooleanArray JNICALL NewBooleanArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeBooleanArray)), + length }; - return makeLocalReference(t, makeBooleanArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); +} + +object +makeByteArray0(Thread* t, unsigned length) +{ + return makeByteArray(t, length); } jbyteArray JNICALL NewByteArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeByteArray0)), + length }; - return makeLocalReference(t, makeByteArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jcharArray JNICALL NewCharArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeCharArray)), + length }; - return makeLocalReference(t, makeCharArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jshortArray JNICALL NewShortArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeShortArray)), + length }; - return makeLocalReference(t, makeShortArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jintArray JNICALL NewIntArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeIntArray)), + length }; - return makeLocalReference(t, makeIntArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jlongArray JNICALL NewLongArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeLongArray)), + length }; - return makeLocalReference(t, makeLongArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jfloatArray JNICALL NewFloatArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeFloatArray)), + length }; - return makeLocalReference(t, makeFloatArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jdoubleArray JNICALL NewDoubleArray(Thread* t, jsize length) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(makeDoubleArray)), + length }; - return makeLocalReference(t, makeDoubleArray(t, length)); + return reinterpret_cast(run(t, newArray, arguments)); } jboolean* JNICALL @@ -1909,11 +2133,13 @@ ReleasePrimitiveArrayCritical(Thread* t, jarray, void*, jint) } } -jint JNICALL -RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, - jint methodCount) +uint64_t +registerNatives(Thread* t, uintptr_t* arguments) { - ENTER(t, Thread::ActiveState); + jclass c = reinterpret_cast(arguments[0]); + const JNINativeMethod* methods + = reinterpret_cast(arguments[1]); + jint methodCount = arguments[2]; for (int i = 0; i < methodCount; ++i) { if (methods[i].function) { @@ -1930,7 +2156,18 @@ RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, } } - return 0; + return 1; +} + +jint JNICALL +RegisterNatives(Thread* t, jclass c, const JNINativeMethod* methods, + jint methodCount) +{ + uintptr_t arguments[] = { reinterpret_cast(c), + reinterpret_cast(methods), + methodCount }; + + return run(t, registerNatives, arguments) ? 0 : -1; } jint JNICALL @@ -1943,24 +2180,49 @@ UnregisterNatives(Thread* t, jclass c) return 0; } +uint64_t +monitorOp(Thread* t, uintptr_t* arguments) +{ + void (*op)(Thread*, object) + = reinterpret_cast(arguments[0]); + + jobject o = reinterpret_cast(arguments[1]); + + op(t, *o); + + return 1; +} + +void +acquire0(Thread* t, object o) +{ + return acquire(t, o); +} + jint JNICALL MonitorEnter(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(acquire0)), + reinterpret_cast(o) }; - acquire(t, *o); + return run(t, monitorOp, arguments) ? 0 : -1; +} - return 0; +void +release0(Thread* t, object o) +{ + return acquire(t, o); } jint JNICALL MonitorExit(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] + = { reinterpret_cast(voidPointer(release0)), + reinterpret_cast(o) }; - release(t, *o); - - return 0; + return run(t, monitorOp, arguments) ? 0 : -1; } jint JNICALL @@ -2030,20 +2292,23 @@ boot(Thread* t) { enter(t, Thread::ActiveState); - if (t->exception == 0) { - setRoot(t, Machine::NullPointerException, makeThrowable - (t, Machine::NullPointerExceptionType)); - - if (t->exception == 0) { - setRoot(t, Machine::ArithmeticException, - makeThrowable(t, Machine::ArithmeticExceptionType)); + t->javaThread = t->m->classpath->makeThread(t, 0); - if (t->exception == 0) { - setRoot(t, Machine::ArrayIndexOutOfBoundsException, - makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); - } - } - } + setRoot(t, Machine::NullPointerException, makeThrowable + (t, Machine::NullPointerExceptionType)); + + setRoot(t, Machine::ArithmeticException, + makeThrowable(t, Machine::ArithmeticExceptionType)); + + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + + setRoot(t, Machine::OutOfMemoryError, + makeThrowable(t, Machine::OutOfMemoryErrorType)); + + setRoot(t, Machine::FinalizerThread, t->m->classpath->makeThread(t, t)); + + threadDaemon(t, root(t, Machine::FinalizerThread)) = true; t->m->classpath->boot(t); diff --git a/src/machine.cpp b/src/machine.cpp index 1fade5edbe..6a93f39fb2 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -83,7 +83,7 @@ dispose(Thread* t, Thread* o, bool remove) expect(t, find(t->m->rootThread, o)); unsigned c = count(t->m->rootThread, o); - RUNTIME_ARRAY(Thread*, threads, c); + THREAD_RUNTIME_ARRAY(t, Thread*, threads, c); fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads)); #endif @@ -578,7 +578,14 @@ postCollect(Thread* t) } t->heapOffset = 0; - t->heapIndex = 0; + + if (t->m->heap->limitExceeded()) { + // if we're out of memory, pretend the thread-local heap is + // already full so we don't make things worse: + t->heapIndex = ThreadHeapSizeInWords; + } else { + t->heapIndex = 0; + } if (t->flags & Thread::UseBackupHeapFlag) { memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); @@ -592,6 +599,17 @@ postCollect(Thread* t) } } +uint64_t +invoke(Thread* t, uintptr_t* arguments) +{ + object m = reinterpret_cast(arguments[0]); + object o = reinterpret_cast(arguments[1]); + + t->m->processor->invoke(t, m, o); + + return 1; +} + void finalizeObject(Thread* t, object o) { @@ -604,7 +622,11 @@ finalizeObject(Thread* t, object o) and vm::strcmp(reinterpret_cast("()V"), &byteArrayBody(t, methodSpec(t, m), 0)) == 0) { - t->m->processor->invoke(t, m, o); + uintptr_t arguments[] = { reinterpret_cast(m), + reinterpret_cast(o) }; + + run(t, invoke, arguments); + t->exception = 0; return; } @@ -613,21 +635,6 @@ finalizeObject(Thread* t, object o) abort(t); } -object -makeByteArray(Thread* t, const char* format, va_list a) -{ - const int Size = 256; - char buffer[Size]; - - int r = vm::vsnprintf(buffer, Size - 1, format, a); - expect(t, r >= 0 and r < Size - 1); - - object s = makeByteArray(t, strlen(buffer) + 1); - memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s)); - - return s; -} - unsigned readByte(Stream& s, unsigned* value) { @@ -858,6 +865,9 @@ parsePool(Thread* t, Stream& s) if (count) { uint32_t* index = static_cast(t->m->heap->allocate(count * 4)); + THREAD_RESOURCE2(t, uint32_t*, index, unsigned, count, + t->m->heap->free(index, count * 4)); + for (unsigned i = 0; i < count; ++i) { index[i] = s.position(); @@ -889,6 +899,7 @@ parsePool(Thread* t, Stream& s) s.skip(8); ++ i; break; + case CONSTANT_Double: singletonSetBit(t, pool, count, i); singletonSetBit(t, pool, count, i + 1); @@ -911,8 +922,6 @@ parsePool(Thread* t, Stream& s) i += parsePoolEntry(t, s, index, pool, i); } - t->m->heap->free(index, count * 4); - s.setPosition(end); } @@ -960,7 +969,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) PROTECT(t, name); object interface = resolveClass(t, classLoader(t, class_), name); - if (UNLIKELY(t->exception)) return; PROTECT(t, interface); @@ -981,7 +989,6 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool) unsigned i = 0; for (HashMapIterator it(t, map); it.hasMore();) { object interface = tripleSecond(t, it.next()); - if (UNLIKELY(t->exception)) return; set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface); ++ i; @@ -1028,7 +1035,7 @@ parseFieldTable(Thread* t, Stream& s, object class_, object pool) object addendum = 0; PROTECT(t, addendum); - RUNTIME_ARRAY(uint8_t, staticTypes, count); + THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count); for (unsigned i = 0; i < count; ++i) { unsigned flags = s.read2(); @@ -2046,6 +2053,7 @@ boot(Thread* t) setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0)); setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0)); + m->processor->boot(t, 0); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); @@ -2162,6 +2170,67 @@ class HeapClient: public Heap::Client { Machine* m; }; +void +doCollect(Thread* t, Heap::CollectionType type) +{ +#ifdef VM_STRESS + bool stress = (t->flags |= Thread::StressFlag); + if (not stress) atomicOr(&(t->flags), Thread::StressFlag); +#endif + + Machine* m = t->m; + + m->unsafe = true; + m->heap->collect(type, footprint(m->rootThread)); + m->unsafe = false; + + postCollect(m->rootThread); + + killZombies(t, m->rootThread); + + for (unsigned i = 0; i < m->heapPoolIndex; ++i) { + m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes); + } + m->heapPoolIndex = 0; + + if (m->heap->limitExceeded()) { + // if we're out of memory, disallow further allocations of fixed + // objects: + m->fixedFootprint = FixedFootprintThresholdInBytes; + } else { + m->fixedFootprint = 0; + } + +#ifdef VM_STRESS + if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); +#endif + + object f = t->m->finalizeQueue; + t->m->finalizeQueue = 0; + for (; f; f = finalizerNext(t, f)) { + void (*function)(Thread*, object); + memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); + if (function) { + function(t, finalizerTarget(t, f)); + } else { + setRoot(t, Machine::ObjectsToFinalize, makePair + (t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize))); + } + } + + if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { + m->finalizeThread = m->processor->makeThread + (m, root(t, Machine::FinalizerThread), m->rootThread); + + addThread(t, m->finalizeThread); + + if (not startThread(t, m->finalizeThread)) { + removeThread(t, m->finalizeThread); + m->finalizeThread = 0; + } + } +} + } // namespace namespace vm { @@ -2663,7 +2732,9 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, > ThreadHeapSizeInWords) { t->heap = 0; - if (t->m->heapPoolIndex < ThreadHeapPoolSize) { + if ((not t->m->heap->limitExceeded()) + and t->m->heapPoolIndex < ThreadHeapPoolSize) + { t->heap = static_cast (t->m->heap->tryAllocate(ThreadHeapSizeInBytes)); @@ -2694,6 +2765,10 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, // vmPrintTrace(t); collect(t, Heap::MinorCollection); } + + if (t->m->heap->limitExceeded()) { + throw_(t, root(t, Machine::OutOfMemoryError)); + } } while (type == Machine::MovableAllocation and t->heapIndex + ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords); @@ -2759,12 +2834,51 @@ makeNewGeneral(Thread* t, object class_) return instance; } +void NO_RETURN +throw_(Thread* t, object e) +{ + assert(t, t->exception == 0); + + Thread::Checkpoint* checkpoint = t->checkpoint; + + expect(t, not checkpoint->noThrow); + + t->exception = e; + + while (t->resource != checkpoint->resource) { + Thread::Resource* r = t->resource; + t->resource = r->next; + r->release(); + } + + t->protector = checkpoint->protector; + + checkpoint->unwind(); + + abort(t); +} + +object +makeByteArray(Thread* t, const char* format, va_list a) +{ + const int Size = 256; + char buffer[Size]; + + int r = vm::vsnprintf(buffer, Size - 1, format, a); + expect(t, r >= 0 and r < Size - 1); + + object s = makeByteArray(t, strlen(buffer) + 1); + memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s)); + + return s; +} + object makeByteArray(Thread* t, const char* format, ...) { va_list a; va_start(a, format); - object s = ::makeByteArray(t, format, a); + object s = makeByteArray(t, format, a); va_end(a); return s; @@ -2775,7 +2889,7 @@ makeString(Thread* t, const char* format, ...) { va_list a; va_start(a, format); - object s = ::makeByteArray(t, format, a); + object s = makeByteArray(t, format, a); va_end(a); return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1); @@ -2880,6 +2994,16 @@ stringUTFChars(Thread* t, object string, unsigned start, unsigned length, } } +uint64_t +resolveBootstrap(Thread* t, uintptr_t* arguments) +{ + object name = reinterpret_cast(arguments[0]); + + resolveSystemClass(t, root(t, Machine::BootLoader), name); + + return 1; +} + bool isAssignableFrom(Thread* t, object a, object b) { @@ -2890,8 +3014,9 @@ isAssignableFrom(Thread* t, object a, object b) if (classFlags(t, a) & ACC_INTERFACE) { if (classVmFlags(t, b) & BootstrapFlag) { - resolveSystemClass(t, root(t, Machine::BootLoader), className(t, b)); - if (UNLIKELY(t->exception)) { + uintptr_t arguments[] = { reinterpret_cast(className(t, b)) }; + + if (run(t, resolveBootstrap, arguments) == 0) { t->exception = 0; return false; } @@ -3084,7 +3209,6 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) if (super) { object sc = resolveClass (t, loader, referenceName(t, singletonObject(t, pool, super - 1))); - if (UNLIKELY(t->exception)) return 0; set(t, class_, ClassSuper, sc); @@ -3094,16 +3218,12 @@ parseClass(Thread* t, object loader, const uint8_t* data, unsigned size) } parseInterfaceTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseFieldTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseMethodTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; parseAttributeTable(t, s, class_, pool); - if (UNLIKELY(t->exception)) return 0; object vtable = classVirtualTable(t, class_); unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0); @@ -3160,7 +3280,7 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) if (byteArrayBody(t, spec, 0) == '[') { class_ = resolveArrayClass(t, loader, spec, throw_); } else { - RUNTIME_ARRAY(char, file, byteArrayLength(t, spec) + 6); + THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6); memcpy(RUNTIME_ARRAY_BODY(file), &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1); @@ -3177,27 +3297,27 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0)); } - // parse class file - class_ = parseClass(t, loader, region->start(), region->length()); - region->dispose(); + { THREAD_RESOURCE(t, System::Region*, region, region->dispose()); - if (LIKELY(t->exception == 0)) { - if (Verbose) { - fprintf(stderr, "done parsing %s: %p\n", - &byteArrayBody(t, spec, 0), - class_); - } + // parse class file + class_ = parseClass(t, loader, region->start(), region->length()); + } - object bootstrapClass = hashMapFind - (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, - byteArrayEqual); + if (Verbose) { + fprintf(stderr, "done parsing %s: %p\n", + &byteArrayBody(t, spec, 0), + class_); + } - if (bootstrapClass) { - PROTECT(t, bootstrapClass); - - updateBootstrapClass(t, bootstrapClass, class_); - class_ = bootstrapClass; - } + object bootstrapClass = hashMapFind + (t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash, + byteArrayEqual); + + if (bootstrapClass) { + PROTECT(t, bootstrapClass); + + updateBootstrapClass(t, bootstrapClass, class_); + class_ = bootstrapClass; } } } @@ -3206,10 +3326,9 @@ resolveSystemClass(Thread* t, object loader, object spec, bool throw_) PROTECT(t, class_); hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash); - } else if (throw_ and t->exception == 0) { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeThrowable - (t, Machine::ClassNotFoundExceptionType, message); + } else if (throw_) { + throwNew(t, Machine::ClassNotFoundExceptionType, "%s", + &byteArrayBody(t, spec, 0)); } } @@ -3265,28 +3384,24 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) } } - if (LIKELY(t->exception == 0)) { - object method = findVirtualMethod - (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); + object method = findVirtualMethod + (t, root(t, Machine::LoadClassMethod), objectClass(t, loader)); - if (LIKELY(t->exception == 0)) { - PROTECT(t, method); + PROTECT(t, method); + + THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec)); + replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast + (&byteArrayBody(t, spec, 0))); - RUNTIME_ARRAY(char, s, byteArrayLength(t, spec)); - replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast - (&byteArrayBody(t, spec, 0))); + object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s)); - - object jc = t->m->processor->invoke(t, method, loader, specString); - if (LIKELY(jc and t->exception == 0)) { - c = jclassVmClass(t, jc); - } - } + object jc = t->m->processor->invoke(t, method, loader, specString); + if (LIKELY(jc)) { + c = jclassVmClass(t, jc); } } - if (LIKELY(c and t->exception == 0)) { + if (LIKELY(c)) { PROTECT(t, c); ACQUIRE(t, t->m->classLock); @@ -3301,13 +3416,8 @@ resolveClass(Thread* t, object loader, object spec, bool throw_) return c; } else { - if (t->exception == 0) { - object message = makeString(t, "%s", &byteArrayBody(t, spec, 0)); - t->exception = makeThrowable - (t, Machine::ClassNotFoundExceptionType, message); - } - - return 0; + throwNew(t, Machine::ClassNotFoundExceptionType, "%s", + &byteArrayBody(t, spec, 0)); } } } @@ -3325,13 +3435,10 @@ resolveMethod(Thread* t, object class_, const char* methodName, object method = findMethodInClass(t, class_, name, spec); - if (t->exception == 0 and method == 0) { - object message = makeString - (t, "%s %s not found in %s", methodName, methodSpec, - &byteArrayBody(t, className(t, class_), 0)); - - t->exception = makeThrowable(t, Machine::NoSuchMethodErrorType, message); - return 0; + if (method == 0) { + throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s", + methodName, methodSpec, &byteArrayBody + (t, className(t, class_), 0)); } else { return method; } @@ -3358,13 +3465,9 @@ resolveField(Thread* t, object class_, const char* fieldName, field = findFieldInClass(t, c, name, spec); } - if (t->exception == 0 and field == 0) { - object message = makeString - (t, "%s %s not found in %s", fieldName, fieldSpec, - &byteArrayBody(t, className(t, class_), 0)); - - t->exception = makeThrowable(t, Machine::NoSuchFieldErrorType, message); - return 0; + if (field == 0) { + throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s", + fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0)); } else { return field; } @@ -3413,11 +3516,8 @@ preInitClass(Thread* t, object c) t->m->classLock->wait(t->systemThread, 0); } } else if (classVmFlags(t, c) & InitErrorFlag) { - object message = makeString - (t, "%s", &byteArrayBody(t, className(t, c), 0)); - - t->exception = makeThrowable - (t, Machine::NoClassDefFoundErrorType, message); + throwNew(t, Machine::NoClassDefFoundErrorType, "%s", + &byteArrayBody(t, className(t, c), 0)); } else { classVmFlags(t, c) |= InitFlag; return true; @@ -3434,13 +3534,13 @@ postInitClass(Thread* t, object c) ACQUIRE(t, t->m->classLock); if (t->exception) { - object exception = t->exception; - t->exception = 0; - t->exception = makeThrowable - (t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); - classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag; classVmFlags(t, c) &= ~InitFlag; + + object exception = t->exception; + t->exception = 0; + + throwNew(t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); } else { classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag); } @@ -3453,11 +3553,11 @@ initClass(Thread* t, object c) PROTECT(t, c); if (preInitClass(t, c)) { + OBJECT_RESOURCE(t, c, postInitClass(t, c)); + Thread::ClassInitStack stack(t, c); t->m->processor->invoke(t, classInitializer(t, c), 0); - - postInitClass(t, c); } } @@ -3496,7 +3596,6 @@ resolveObjectArrayClass(Thread* t, object loader, object elementClass) } object arrayClass = resolveClass(t, loader, spec); - if (UNLIKELY(t->exception)) return 0; set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass, arrayClass); @@ -3509,7 +3608,6 @@ makeObjectArray(Thread* t, object elementClass, unsigned count) { object arrayClass = resolveObjectArrayClass (t, classLoader(t, elementClass), elementClass); - if (UNLIKELY(t->exception)) return 0; PROTECT(t, arrayClass); @@ -3692,57 +3790,16 @@ collect(Thread* t, Heap::CollectionType type) { ENTER(t, Thread::ExclusiveState); -#ifdef VM_STRESS - bool stress = (t->flags |= Thread::StressFlag); - if (not stress) atomicOr(&(t->flags), Thread::StressFlag); -#endif - - Machine* m = t->m; - - m->unsafe = true; - m->heap->collect(type, footprint(m->rootThread)); - m->unsafe = false; - - postCollect(m->rootThread); - - killZombies(t, m->rootThread); - - for (unsigned i = 0; i < m->heapPoolIndex; ++i) { - m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes); - } - m->heapPoolIndex = 0; - - m->fixedFootprint = 0; - -#ifdef VM_STRESS - if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag); -#endif - - object f = t->m->finalizeQueue; - t->m->finalizeQueue = 0; - for (; f; f = finalizerNext(t, f)) { - void (*function)(Thread*, object); - memcpy(&function, &finalizerFinalize(t, f), BytesPerWord); - if (function) { - function(t, finalizerTarget(t, f)); - } else { - setRoot(t, Machine::ObjectsToFinalize, makePair - (t, finalizerTarget(t, f), root(t, Machine::ObjectsToFinalize))); - } + if (t->m->heap->limitExceeded()) { + type = Heap::MajorCollection; } - if (root(t, Machine::ObjectsToFinalize) and m->finalizeThread == 0) { - object javaThread = t->m->classpath->makeThread(t, m->rootThread); - threadDaemon(t, javaThread) = true; + doCollect(t, type); - m->finalizeThread = m->processor->makeThread(m, javaThread, m->rootThread); - - addThread(t, m->finalizeThread); - - if (not startThread(t, m->finalizeThread)) { - removeThread(t, m->finalizeThread); - m->finalizeThread = 0; - } + if (t->m->heap->limitExceeded()) { + // try once more, giving the heap a chance to squeeze everything + // into the smallest possible space: + doCollect(t, Heap::MajorCollection); } } @@ -3762,7 +3819,7 @@ walk(Thread* t, Heap::Walker* w, object o, unsigned start) = (arrayElementSize ? cast(o, fixedSize - BytesPerWord) : 0); - RUNTIME_ARRAY(uint32_t, mask, intArrayLength(t, objectMask)); + THREAD_RUNTIME_ARRAY(t, uint32_t, mask, intArrayLength(t, objectMask)); memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0), intArrayLength(t, objectMask) * 4); @@ -3836,7 +3893,7 @@ printTrace(Thread* t, object exception) if (throwableMessage(t, e)) { object m = throwableMessage(t, e); - RUNTIME_ARRAY(char, message, stringLength(t, m) + 1); + THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1); stringChars(t, m, RUNTIME_ARRAY_BODY(message)); fprintf(stderr, ": %s\n", RUNTIME_ARRAY_BODY(message)); } else { diff --git a/src/machine.h b/src/machine.h index 789d3214ef..187dc46e21 100644 --- a/src/machine.h +++ b/src/machine.h @@ -37,6 +37,56 @@ #define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state) +#define THREAD_RESOURCE0(t, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t): Resource(t) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + } MAKE_NAME(resource_)(t); + +#define OBJECT_RESOURCE(t, name, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, object name): \ + Resource(t), name(name), protector(t, &(this->name)) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + object name; \ + Thread::SingleProtector protector; \ + } MAKE_NAME(resource_)(t, name); + +#define THREAD_RESOURCE(t, type, name, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, type name): \ + Resource(t), name(name) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + type name; \ + } MAKE_NAME(resource_)(t, name); + +#define THREAD_RESOURCE2(t, type1, name1, type2, name2, releaseBody) \ + class MAKE_NAME(Resource_): public Thread::Resource { \ + public: \ + MAKE_NAME(Resource_)(Thread* t, type1 name1, type2 name2): \ + Resource(t), name1(name1), name2(name2) { } \ + ~MAKE_NAME(Resource_)() { releaseBody; } \ + virtual void release() \ + { this->MAKE_NAME(Resource_)::~MAKE_NAME(Resource_)(); } \ + \ + private: \ + type1 name1; \ + type2 name2; \ + } MAKE_NAME(resource_)(t, name1, name2); + namespace vm { const bool Verbose = false; @@ -1201,10 +1251,12 @@ class Machine { MethodRuntimeDataTable, JNIMethodTable, ShutdownHooks, + FinalizerThread, ObjectsToFinalize, NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, + OutOfMemoryError, VirtualFileFinders, VirtualFiles }; @@ -1280,15 +1332,23 @@ inline void stress(Thread* t); #endif // not VM_STRESS -void -runJavaThread(Thread* t); +uint64_t +runThread(Thread*, uintptr_t*); -void -runFinalizeThread(Thread* t); +uint64_t +run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), + uintptr_t* arguments); void checkDaemon(Thread* t); +extern "C" uint64_t +vmRun(uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments, + void* checkpoint); + +extern "C" void +vmRun_returnAddress(); + class Thread { public: enum State { @@ -1336,9 +1396,26 @@ class Thread { object* p; }; - class ClassInitStack { + class Resource { + public: + Resource(Thread* t): t(t), next(t->resource) { + t->resource = this; + } + + ~Resource() { + t->resource = next; + } + + virtual void release() = 0; + + Thread* t; + Resource* next; + }; + + class ClassInitStack: public Resource { public: ClassInitStack(Thread* t, object class_): + Resource(t), next(t->classInitStack), class_(class_), protector(t, &(this->class_)) @@ -1347,7 +1424,11 @@ class Thread { } ~ClassInitStack() { - protector.t->classInitStack = next; + t->classInitStack = next; + } + + virtual void release() { + this->ClassInitStack::~ClassInitStack(); } ClassInitStack* next; @@ -1355,6 +1436,50 @@ class Thread { SingleProtector protector; }; + class Checkpoint { + public: + Checkpoint(Thread* t): + t(t), + next(t->checkpoint), + resource(t->resource), + protector(t->protector), + noThrow(false) + { + t->checkpoint = this; + } + + ~Checkpoint() { + t->checkpoint = next; + } + + virtual void NO_RETURN unwind() = 0; + + Thread* t; + Checkpoint* next; + Resource* resource; + Protector* protector; + bool noThrow; + }; + + class RunCheckpoint: public Checkpoint { + public: + RunCheckpoint(Thread* t): + Checkpoint(t), + stack(0), + base(0) + { } + + virtual void unwind() { + void* stack = this->stack; + this->stack = 0; + expect(t->m->system, stack); + vmJump(voidPointer(vmRun_returnAddress), base, stack, t, 0, 0); + } + + void* stack; + void* base; + }; + class Runnable: public System::Runnable { public: Runnable(Thread* t): t(t) { } @@ -1366,18 +1491,10 @@ class Thread { virtual void run() { enterActiveState(t); - t->m->localThread->set(t); + vm::run(t, runThread, 0); - checkDaemon(t); - - if (t == t->m->finalizeThread) { - runFinalizeThread(t); - } else if (t->javaThread) { - runJavaThread(t); - - if (t->exception) { - printTrace(t, t->exception); - } + if (t->exception) { + printTrace(t, t->exception); } t->exit(); @@ -1416,6 +1533,8 @@ class Thread { unsigned heapOffset; Protector* protector; ClassInitStack* classInitStack; + Resource* resource; + Checkpoint* checkpoint; Runnable runnable; uintptr_t* defaultHeap; uintptr_t* heap; @@ -1448,6 +1567,38 @@ class Classpath { dispose() = 0; }; +#ifdef _MSC_VER + +template +class RuntimeArray: public Thread::Resource { + public: + RuntimeArray(Thread* t, unsigned size): + Resource(t), + body(static_cast(t->m->heap->allocate(size * sizeof(T)))), + size(size) + { } + + ~RuntimeArray() { + t->m->heap->free(body, size * sizeof(T)); + } + + virtual void release() { + RuntimeArray::~RuntimeArray(); + } + + T* body; + unsigned size; +}; + +# define THREAD_RUNTIME_ARRAY(thread, type, name, size) \ + RuntimeArray name(thread, size); + +#else // not _MSC_VER + +# define THREAD_RUNTIME_ARRAY(thread, type, name, size) type name[size]; + +#endif // not _MSC_VER + Classpath* makeClasspath(System* system, Allocator* allocator, const char* javaHome, const char* embedPrefix); @@ -1469,16 +1620,21 @@ enterActiveState(Thread* t) enter(t, Thread::ActiveState); } -class StateResource { +class StateResource: public Thread::Resource { public: - StateResource(Thread* t, Thread::State state): t(t), oldState(t->state) { + StateResource(Thread* t, Thread::State state): + Resource(t), oldState(t->state) + { enter(t, state); } ~StateResource() { enter(t, oldState); } + virtual void release() { + this->StateResource::~StateResource(); + } + private: - Thread* t; Thread::State oldState; }; @@ -1553,33 +1709,43 @@ release(Thread* t, System::Monitor* m) m->release(t->systemThread); } -class MonitorResource { +class MonitorResource: public Thread::Resource { public: - MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) { + MonitorResource(Thread* t, System::Monitor* m): + Resource(t), m(m) + { acquire(t, m); } ~MonitorResource() { - release(t, m); + vm::release(t, m); + } + + virtual void release() { + this->MonitorResource::~MonitorResource(); } private: - Thread* t; System::Monitor* m; }; -class RawMonitorResource { +class RawMonitorResource: public Thread::Resource { public: - RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) { + RawMonitorResource(Thread* t, System::Monitor* m): + Resource(t), m(m) + { m->acquire(t->systemThread); } ~RawMonitorResource() { - release(t, m); + vm::release(t, m); + } + + virtual void release() { + this->RawMonitorResource::~RawMonitorResource(); } private: - Thread* t; System::Monitor* m; }; @@ -1622,8 +1788,12 @@ class FixedAllocator: public Allocator { return p; } - virtual void free(const void*, unsigned) { - abort(s); + virtual void free(const void* p, unsigned size) { + if (p >= base and static_cast(p) + size == base + offset) { + offset -= size; + } else { + abort(s); + } } System* s; @@ -1667,7 +1837,6 @@ allocateSmall(Thread* t, unsigned sizeInBytes) object o = reinterpret_cast(t->heap + t->heapIndex); t->heapIndex += ceiling(sizeInBytes, BytesPerWord); - cast(o, 0) = 0; return o; } @@ -1745,12 +1914,39 @@ instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" +inline uint64_t +run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) +{ + ENTER(t, Thread::ActiveState); + Thread::RunCheckpoint checkpoint(t); + return vmRun(function, arguments, &checkpoint); +} + inline void runJavaThread(Thread* t) { t->m->classpath->runThread(t); } +void +runFinalizeThread(Thread* t); + +inline uint64_t +runThread(Thread* t, uintptr_t*) +{ + t->m->localThread->set(t); + + checkDaemon(t); + + if (t == t->m->finalizeThread) { + runFinalizeThread(t); + } else if (t->javaThread) { + runJavaThread(t); + } + + return 1; +} + inline bool startThread(Thread* t, Thread* p) { @@ -1820,17 +2016,12 @@ checkDaemon(Thread* t) } } -inline Thread* -attachThread(Machine* m, bool daemon) +inline uint64_t +initAttachedThread(Thread* t, uintptr_t* arguments) { - Thread* t = m->processor->makeThread(m, 0, m->rootThread); - m->system->attach(&(t->runnable)); + bool daemon = arguments[0]; - addThread(t, t); - - enter(t, Thread::ActiveState); - - t->javaThread = m->classpath->makeThread(t, m->rootThread); + t->javaThread = t->m->classpath->makeThread(t, t->m->rootThread); threadPeer(t, t->javaThread) = reinterpret_cast(t); @@ -1840,11 +2031,30 @@ attachThread(Machine* m, bool daemon) registerDaemon(t); } - enter(t, Thread::IdleState); + t->m->localThread->set(t); - m->localThread->set(t); + return 1; +} - return t; +inline Thread* +attachThread(Machine* m, bool daemon) +{ + Thread* t = m->processor->makeThread(m, 0, m->rootThread); + m->system->attach(&(t->runnable)); + + addThread(t, t); + + uintptr_t arguments[] = { daemon }; + + enter(t, Thread::ActiveState); + + if (run(t, initAttachedThread, arguments)) { + enter(t, Thread::IdleState); + return t; + } else { + t->exit(); + return 0; + } } inline object& @@ -1939,6 +2149,9 @@ make(Thread* t, object class_) } } +object +makeByteArray(Thread* t, const char* format, va_list a); + object makeByteArray(Thread* t, const char* format, ...); @@ -2248,12 +2461,8 @@ inline object resolveMethod(Thread* t, object loader, const char* className, const char* methodName, const char* methodSpec) { - object class_ = resolveClass(t, loader, className); - if (LIKELY(t->exception == 0)) { - return resolveMethod(t, class_, methodName, methodSpec); - } else { - return 0; - } + return resolveMethod + (t, resolveClass(t, loader, className), methodName, methodSpec); } object @@ -2264,12 +2473,8 @@ inline object resolveField(Thread* t, object loader, const char* className, const char* fieldName, const char* fieldSpec) { - object class_ = resolveClass(t, loader, className); - if (LIKELY(t->exception == 0)) { - return resolveField(t, class_, fieldName, fieldSpec); - } else { - return 0; - } + return resolveField + (t, resolveClass(t, loader, className), fieldName, fieldSpec); } bool @@ -2347,6 +2552,48 @@ makeThrowable return result; } +inline object +makeThrowable(Thread* t, Machine::Type type, const char* format, va_list a) +{ + object s = makeByteArray(t, format, a); + + object message = t->m->classpath->makeString + (t, s, 0, byteArrayLength(t, s) - 1); + + return makeThrowable(t, type, message); +} + +inline object +makeThrowable(Thread* t, Machine::Type type, const char* format, ...) +{ + va_list a; + va_start(a, format); + object r = makeThrowable(t, type, format, a); + va_end(a); + + return r; +} + +void NO_RETURN +throw_(Thread* t, object e); + +inline void NO_RETURN +throwNew(Thread* t, Machine::Type type) +{ + throw_(t, makeThrowable(t, type)); +} + +inline void NO_RETURN +throwNew(Thread* t, Machine::Type type, const char* format, ...) +{ + va_list a; + va_start(a, format); + object r = makeThrowable(t, type, format, a); + va_end(a); + + throw_(t, r); +} + object findInHierarchyOrNull(Thread* t, object class_, object name, object spec, object (*find)(Thread*, object, object, object)); @@ -2359,12 +2606,10 @@ findInHierarchy(Thread* t, object class_, object name, object spec, object o = findInHierarchyOrNull(t, class_, name, spec, find); if (o == 0) { - object message = makeString - (t, "%s %s not found in %s", - &byteArrayBody(t, name, 0), - &byteArrayBody(t, spec, 0), - &byteArrayBody(t, className(t, class_), 0)); - t->exception = makeThrowable(t, errorType, message); + throwNew(t, errorType, "%s %s not found in %s", + &byteArrayBody(t, name, 0), + &byteArrayBody(t, spec, 0), + &byteArrayBody(t, className(t, class_), 0)); } return o; @@ -2390,8 +2635,7 @@ findMethodOrNull(Thread* t, object class_, const char* name, const char* spec) inline object findVirtualMethod(Thread* t, object method, object class_) { - return arrayBody(t, classVirtualTable(t, class_), - methodOffset(t, method)); + return arrayBody(t, classVirtualTable(t, class_), methodOffset(t, method)); } inline object @@ -2403,8 +2647,8 @@ findInterfaceMethod(Thread* t, object method, object class_) object itable = classInterfaceTable(t, class_); for (unsigned i = 0; i < arrayLength(t, itable); i += 2) { if (arrayBody(t, itable, i) == interface) { - return arrayBody(t, arrayBody(t, itable, i + 1), - methodOffset(t, method)); + return arrayBody + (t, arrayBody(t, itable, i + 1), methodOffset(t, method)); } } abort(t); @@ -2849,10 +3093,10 @@ wait(Thread* t, object o, int64_t milliseconds) bool interrupted = monitorWait(t, m, milliseconds); if (interrupted) { - t->exception = makeThrowable(t, Machine::InterruptedExceptionType); + throwNew(t, Machine::InterruptedExceptionType); } } else { - t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } if (DebugMonitors) { @@ -2881,7 +3125,7 @@ notify(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotify(t, m); } else { - t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } } @@ -2898,7 +3142,7 @@ notifyAll(Thread* t, object o) if (m and monitorOwner(t, m) == t) { monitorNotifyAll(t, m); } else { - t->exception = makeThrowable(t, Machine::IllegalMonitorStateExceptionType); + throwNew(t, Machine::IllegalMonitorStateExceptionType); } } @@ -3057,7 +3301,6 @@ resolveClassInObject(Thread* t, object loader, object container, PROTECT(t, container); o = resolveClass(t, loader, o); - if (UNLIKELY(t->exception)) return 0; set(t, container, classOffset, o); } @@ -3072,7 +3315,6 @@ resolveClassInPool(Thread* t, object loader, object method, unsigned index) PROTECT(t, method); o = resolveClass(t, loader, referenceName(t, o)); - if (UNLIKELY(t->exception)) return 0; set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); @@ -3101,12 +3343,10 @@ resolve(Thread* t, object loader, object method, unsigned index, PROTECT(t, reference); object class_ = resolveClassInObject(t, loader, o, ReferenceClass); - if (UNLIKELY(t->exception)) return 0; o = findInHierarchy (t, class_, referenceName(t, reference), referenceSpec(t, reference), find, errorType); - if (UNLIKELY(t->exception)) return 0; set(t, codePool(t, methodCode(t, method)), SingletonBody + (index * BytesPerWord), o); @@ -3236,9 +3476,7 @@ primitiveClass(Thread* t, char name) case 'S': return type(t, Machine::JshortType); case 'V': return type(t, Machine::JvoidType); case 'Z': return type(t, Machine::JbooleanType); - default: - t->exception = makeThrowable(t, Machine::IllegalArgumentExceptionType); - return 0; + default: throwNew(t, Machine::IllegalArgumentExceptionType); } } diff --git a/src/process.cpp b/src/process.cpp index 00edbe66b7..b364598eb5 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -153,13 +153,13 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, { unsigned undecoratedSize = prefixLength + jniNameLength(t, method, false); // extra 6 is for code below: - RUNTIME_ARRAY(char, undecorated, undecoratedSize + 1 + 6); + THREAD_RUNTIME_ARRAY(t, char, undecorated, undecoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(undecorated) + 1, method, false); unsigned decoratedSize = prefixLength + jniNameLength(t, method, true); // extra 6 is for code below: - RUNTIME_ARRAY(char, decorated, decoratedSize + 1 + 6); + THREAD_RUNTIME_ARRAY(t, char, decorated, decoratedSize + 1 + 6); makeJNIName(t, prefix, prefixLength, RUNTIME_ARRAY_BODY(decorated) + 1, method, true); @@ -232,20 +232,13 @@ resolveNative(Thread* t, object method) initClass(t, methodClass(t, method)); - if (LIKELY(t->exception == 0) - and methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) - { + if (methodRuntimeDataNative(t, getMethodRuntimeData(t, method)) == 0) { object native = resolveNativeMethod(t, method); if (UNLIKELY(native == 0)) { - object message = makeString - (t, "%s.%s%s", - &byteArrayBody(t, className(t, methodClass(t, method)), 0), - &byteArrayBody(t, methodName(t, method), 0), - &byteArrayBody(t, methodSpec(t, method), 0)); - - t->exception = makeThrowable - (t, Machine::UnsatisfiedLinkErrorType, message); - return; + throwNew(t, Machine::UnsatisfiedLinkErrorType, "%s.%s%s", + &byteArrayBody(t, className(t, methodClass(t, method)), 0), + &byteArrayBody(t, methodName(t, method), 0), + &byteArrayBody(t, methodSpec(t, method), 0)); } PROTECT(t, native); diff --git a/src/x86.S b/src/x86.S index 552e093bdc..c7c6e5c504 100644 --- a/src/x86.S +++ b/src/x86.S @@ -23,6 +23,10 @@ #ifdef __x86_64__ +#define CHECKPOINT_THREAD 8 +#define CHECKPOINT_STACK 48 +#define CHECKPOINT_BASE 56 + #ifdef __MINGW32__ .globl GLOBAL(detectFeature) GLOBAL(detectFeature): @@ -173,6 +177,48 @@ GLOBAL(vmJump): movq %r8,%rsp movq %r9,%rbx jmp *%rcx + +#define VMRUN_FRAME_SIZE 80 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // %rcx: function + // %rdx: arguments + // %r8 : checkpoint + pushq %rbp + movq %rsp,%rbp + subq $VMRUN_FRAME_SIZE,%rsp + + movq %rbx,16(%rsp) + movq %r12,24(%rsp) + movq %r13,32(%rsp) + movq %r14,40(%rsp) + movq %r15,48(%rsp) + movq %rsi,56(%rsp) + movq %rdi,64(%rsp) + + movq %rsp,CHECKPOINT_STACK(%rcx) + movq %rbp,CHECKPOINT_BASE(%rcx) + + movq %rcx,%r11 + movq CHECKPOINT_THREAD(%rdx),%rcx + + call *%r11 + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movq 16(%rsp),%rbx + movq 24(%rsp),%r12 + movq 32(%rsp),%r13 + movq 40(%rsp),%r14 + movq 48(%rsp),%r15 + movq 56(%rsp),%rsi + movq 64(%rsp),%rdi + + addq $VMRUN_FRAME_SIZE,%rsp + popq %rbp + ret #else // not __MINGW32__ .globl GLOBAL(detectFeature) @@ -314,10 +360,52 @@ GLOBAL(vmJump): movq %r9,%rdx jmp *%rdi +#define VMRUN_FRAME_SIZE 64 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // %rdi: function + // %rsi: arguments + // %rdx: checkpoint + pushq %rbp + movq %rsp,%rbp + subq $VMRUN_FRAME_SIZE,%rsp + + movq %rbx,16(%rsp) + movq %r12,24(%rsp) + movq %r13,32(%rsp) + movq %r14,40(%rsp) + movq %r15,48(%rsp) + + movq %rsp,CHECKPOINT_STACK(%rdx) + movq %rbp,CHECKPOINT_BASE(%rdx) + + movq %rdi,%r11 + movq CHECKPOINT_THREAD(%rdx),%rdi + + call *%r11 + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movq 16(%rsp),%rbx + movq 24(%rsp),%r12 + movq 32(%rsp),%r13 + movq 40(%rsp),%r14 + movq 48(%rsp),%r15 + + addq $VMRUN_FRAME_SIZE,%rsp + popq %rbp + ret + #endif // not __MINGW32__ #elif defined __i386__ +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 +#define CHECKPOINT_BASE 28 + .globl GLOBAL(detectFeature) GLOBAL(detectFeature): pushl %ebp @@ -432,4 +520,42 @@ GLOBAL(vmJump): movl 12(%esp),%esp jmp *%esi -#endif //def __x86_64__ +#define VMRUN_FRAME_SIZE 32 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // 8(%ebp): function + // 12(%ebp): arguments + // 16(%ebp): checkpoint + pushl %ebp + movl %esp,%ebp + subl $VMRUN_FRAME_SIZE,%esp + + movl %ebx,8(%esp) + movl %esi,12(%esp) + movl %edi,16(%esp) + + movl 12(%ebp),%eax + movl %eax,4(%esp) + + movl 16(%ebp),%ecx + movl CHECKPOINT_THREAD(%ecx),%eax + movl %eax,0(%esp) + + movl %esp,CHECKPOINT_STACK(%ecx) + movl %ebp,CHECKPOINT_BASE(%ecx) + + call *8(%ebp) + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + + movl 8(%esp),%ebx + movl 12(%esp),%esi + movl 16(%esp),%edi + + addl $VMRUN_FRAME_SIZE,%esp + popl %ebp + ret + +#endif // __i386__ diff --git a/test/OutOfMemory.java b/test/OutOfMemory.java new file mode 100644 index 0000000000..fbcb614fdf --- /dev/null +++ b/test/OutOfMemory.java @@ -0,0 +1,62 @@ +public class OutOfMemory { + // assume a 128MB heap size: + private static final int Padding = 120 * 1024 * 1024; + + private static class Node { + Object value; + Node next; + } + + private static void bigObjects() { + Object[] root = null; + while (true) { + Object[] x = new Object[1024 * 1024]; + x[0] = root; + root = x; + } + } + + private static void littleObjects() { + byte[] padding = new byte[Padding]; + Node root = null; + while (true) { + Node x = new Node(); + x.next = root; + root = x; + } + } + + private static void bigAndLittleObjects() { + byte[] padding = new byte[Padding]; + Node root = null; + while (true) { + Node x = new Node(); + x.value = new Object[1024 * 1024]; + x.next = root; + root = x; + } + } + + public static void main(String[] args) { + try { + bigObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + + try { + littleObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + + try { + bigAndLittleObjects(); + throw new RuntimeException(); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + } + } +} From dd52908f894eecdc9018b9c5f913b6b4b76b07e5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 11 Jan 2011 18:25:34 -0700 Subject: [PATCH 182/274] add URLConnection methods --- classpath/java/net/URLConnection.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/classpath/java/net/URLConnection.java b/classpath/java/net/URLConnection.java index ab8f5619e4..0219fbe688 100644 --- a/classpath/java/net/URLConnection.java +++ b/classpath/java/net/URLConnection.java @@ -16,6 +16,9 @@ import java.io.OutputStream; public abstract class URLConnection { protected final URL url; + protected boolean doInput = true; + protected boolean doOutput = false; + protected boolean useCaches = true; protected URLConnection(URL url) { this.url = url; @@ -29,6 +32,8 @@ public abstract class URLConnection { return -1; } + public abstract void connect() throws IOException; + public InputStream getInputStream() throws IOException { throw new UnknownServiceException(); } @@ -36,4 +41,24 @@ public abstract class URLConnection { public OutputStream getOutputStream() throws IOException { throw new UnknownServiceException(); } + + public boolean getDoInput() { + return doInput; + } + + public boolean getDoOutput() { + return doOutput; + } + + public void setDoInput(boolean v) { + doInput = v; + } + + public void setDoOutput(boolean v) { + doInput = v; + } + + public void setUseCaches(boolean v) { + useCaches = v; + } } From 4f0dccb53c3946ef19c45607ff048d0a9c43a1ef Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 11 Jan 2011 18:26:37 -0700 Subject: [PATCH 183/274] add Channels.newChannel methods --- classpath/java/nio/channels/Channels.java | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/classpath/java/nio/channels/Channels.java b/classpath/java/nio/channels/Channels.java index 3f7fe63eaa..849a16dffc 100644 --- a/classpath/java/nio/channels/Channels.java +++ b/classpath/java/nio/channels/Channels.java @@ -24,6 +24,14 @@ public class Channels { return new MyOutputStream(channel); } + public static ReadableByteChannel newChannel(InputStream stream) { + return new InputStreamChannel(stream); + } + + public static WritableByteChannel newChannel(OutputStream stream) { + return new OutputStreamChannel(stream); + } + private static class MyInputStream extends InputStream { private final ReadableByteChannel channel; @@ -72,4 +80,63 @@ public class Channels { channel.close(); } } + + private static class InputStreamChannel implements ReadableByteChannel { + private InputStream stream; + + public InputStreamChannel(InputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int read(ByteBuffer b) throws IOException { + int c = stream.read + (b.array(), b.arrayOffset() + b.position(), b.remaining()); + + if (c > 0) { + b.position(b.position() + c); + } + + return c; + } + } + + private static class OutputStreamChannel implements WritableByteChannel { + private OutputStream stream; + + public OutputStreamChannel(OutputStream stream) { + this.stream = stream; + } + + public void close() throws IOException { + if (stream != null) { + stream.close(); + stream = null; + } + } + + public boolean isOpen() { + return stream != null; + } + + public int write(ByteBuffer b) throws IOException { + stream.write(b.array(), b.arrayOffset() + b.position(), b.remaining()); + + int c = b.remaining(); + + b.position(b.limit()); + + return c; + } + } } From eb3a9f010b0518abe0786e65058bcc137f592302 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 11 Jan 2011 18:29:48 -0700 Subject: [PATCH 184/274] fix false positive return from SocketChannel.finishConnect This fixes a bug in finishConnect such that it would return true even if the socket had not yet connected successfully. --- classpath/java-nio.cpp | 11 ++--- .../nio/channels/GatheringByteChannel.java | 20 ++++++++++ .../java/nio/channels/SelectableChannel.java | 2 + .../java/nio/channels/SocketChannel.java | 40 +++++++++++++++++-- .../java/nio/channels/SocketSelector.java | 1 + 5 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 classpath/java/nio/channels/GatheringByteChannel.java diff --git a/classpath/java-nio.cpp b/classpath/java-nio.cpp index 2e5d37bb1a..9a7656db91 100644 --- a/classpath/java-nio.cpp +++ b/classpath/java-nio.cpp @@ -279,7 +279,7 @@ doListen(JNIEnv* e, int s, sockaddr_in* address) } } -bool +void doFinishConnect(JNIEnv* e, int socket) { int error; @@ -289,12 +289,9 @@ doFinishConnect(JNIEnv* e, int socket) if (r != 0 or size != sizeof(int)) { throwIOException(e); - } else if (einProgress(error)) { - return false; - } else if (error != 0) { + } else if (error and not einProgress(error)) { throwIOException(e, socketErrorString(e, error)); } - return true; } bool @@ -426,12 +423,12 @@ Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv *e, return s; } -extern "C" JNIEXPORT jboolean JNICALL +extern "C" JNIEXPORT void JNICALL Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e, jclass, jint socket) { - return doFinishConnect(e, socket); + doFinishConnect(e, socket); } extern "C" JNIEXPORT jint JNICALL diff --git a/classpath/java/nio/channels/GatheringByteChannel.java b/classpath/java/nio/channels/GatheringByteChannel.java new file mode 100644 index 0000000000..5696f5e980 --- /dev/null +++ b/classpath/java/nio/channels/GatheringByteChannel.java @@ -0,0 +1,20 @@ +/* Copyright (c) 2011, 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.nio.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface GatheringByteChannel extends WritableByteChannel { + public long write(ByteBuffer[] srcs) throws IOException; + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException; +} diff --git a/classpath/java/nio/channels/SelectableChannel.java b/classpath/java/nio/channels/SelectableChannel.java index a8dc302dc7..734bce9fc8 100644 --- a/classpath/java/nio/channels/SelectableChannel.java +++ b/classpath/java/nio/channels/SelectableChannel.java @@ -19,6 +19,8 @@ public abstract class SelectableChannel implements Channel { abstract int socketFD(); + abstract void handleReadyOps(int ops); + public abstract SelectableChannel configureBlocking(boolean v) throws IOException; diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index 4dbc352558..d0296f4833 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -18,12 +18,13 @@ import java.net.Socket; import java.nio.ByteBuffer; public class SocketChannel extends SelectableChannel - implements ReadableByteChannel, WritableByteChannel + implements ReadableByteChannel, GatheringByteChannel { public static final int InvalidSocket = -1; int socket = InvalidSocket; boolean connected = false; + boolean readyToConnect = false; boolean blocking = true; public static SocketChannel open() throws IOException { @@ -66,8 +67,18 @@ public class SocketChannel extends SelectableChannel public boolean finishConnect() throws IOException { if (! connected) { - connected = natFinishConnect(socket); + while (blocking && ! readyToConnect) { + Selector selector = Selector.open(); + SelectionKey key = register(selector, SelectionKey.OP_CONNECT, null); + + selector.select(); + } + + natFinishConnect(socket); + + connected = readyToConnect; } + return connected; } @@ -117,6 +128,23 @@ public class SocketChannel extends SelectableChannel return w; } + public long write(ByteBuffer[] srcs) throws IOException { + return write(srcs, 0, srcs.length); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + long total = 0; + for (int i = offset; i < offset + length; ++i) { + total += write(srcs[i]); + if (srcs[i].hasRemaining()) { + return total; + } + } + return total; + } + private void closeSocket() { natCloseSocket(socket); } @@ -125,6 +153,12 @@ public class SocketChannel extends SelectableChannel return socket; } + void handleReadyOps(int ops) { + if ((ops & SelectionKey.OP_CONNECT) != 0) { + readyToConnect = true; + } + } + public class Handle extends Socket { public void setTcpNoDelay(boolean on) throws SocketException { natSetTcpNoDelay(socket, on); @@ -139,7 +173,7 @@ public class SocketChannel extends SelectableChannel private static native int natDoConnect(String host, int port, boolean blocking, boolean[] connected) throws IOException; - private static native boolean natFinishConnect(int socket) + private static native void natFinishConnect(int socket) throws IOException; private static native int natRead(int socket, byte[] buffer, int offset, int length, boolean blocking) throws IOException; diff --git a/classpath/java/nio/channels/SocketSelector.java b/classpath/java/nio/channels/SocketSelector.java index 27daf2670b..2482d0f180 100644 --- a/classpath/java/nio/channels/SocketSelector.java +++ b/classpath/java/nio/channels/SocketSelector.java @@ -96,6 +96,7 @@ class SocketSelector extends Selector { int ready = natUpdateReadySet(socket, key.interestOps(), state); key.readyOps(ready); if (ready != 0) { + c.handleReadyOps(ready); selectedKeys.add(key); } } From 39018c20e012fafceab6439fcbc8782ef642e81f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 11 Jan 2011 18:39:48 -0700 Subject: [PATCH 185/274] check connection readyness in SocketChannel.finishConnect if necessary --- classpath/java/nio/channels/SocketChannel.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/classpath/java/nio/channels/SocketChannel.java b/classpath/java/nio/channels/SocketChannel.java index d0296f4833..65c9768d88 100644 --- a/classpath/java/nio/channels/SocketChannel.java +++ b/classpath/java/nio/channels/SocketChannel.java @@ -67,11 +67,16 @@ public class SocketChannel extends SelectableChannel public boolean finishConnect() throws IOException { if (! connected) { - while (blocking && ! readyToConnect) { + while (! readyToConnect) { Selector selector = Selector.open(); SelectionKey key = register(selector, SelectionKey.OP_CONNECT, null); - selector.select(); + if (blocking) { + selector.select(); + } else { + selector.selectNow(); + break; + } } natFinishConnect(socket); From 0c253c40a29a017ee0fe1b922ba4989022804ab9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 13 Jan 2011 07:03:28 -0700 Subject: [PATCH 186/274] add ServerSocketChannel.handleReadyOps to fix build --- classpath/java/nio/channels/ServerSocketChannel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index 7aa806886c..53e6eec36d 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -32,6 +32,10 @@ public class ServerSocketChannel extends SelectableChannel { return channel.socketFD(); } + public void handleReadyOps(int ops) { + channel.handleReadyOps(ops); + } + public SelectableChannel configureBlocking(boolean v) throws IOException { return channel.configureBlocking(v); } From 69dc2026a1f9edd469c51102ff1d44604ba31333 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 13 Jan 2011 08:57:39 -0700 Subject: [PATCH 187/274] provide default implementation for ClassLoader.reallyFindLoadedClass This is a non-standard method, so we shouldn't expect subclasses to implement it. --- classpath/java/lang/ClassLoader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/classpath/java/lang/ClassLoader.java b/classpath/java/lang/ClassLoader.java index 5dc6505877..b2ee0b7f75 100644 --- a/classpath/java/lang/ClassLoader.java +++ b/classpath/java/lang/ClassLoader.java @@ -54,7 +54,9 @@ public abstract class ClassLoader { throw new ClassNotFoundException(); } - protected abstract Class reallyFindLoadedClass(String name); + protected Class reallyFindLoadedClass(String name) { + return null; + } protected final Class findLoadedClass(String name) { return reallyFindLoadedClass(name); From ff18524906fc7bcca35b8b092256b7a46bbffc74 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 13 Jan 2011 08:59:55 -0700 Subject: [PATCH 188/274] add DefineClass to test suite As reported on the discussion group, there is a problem with the ClassLoader.defineClass implementation sunch that this test is not currently passing, at least for the mode=debug and bootimage=true builds. I plan to address these failures soon, but I wanted to add a test first to make sure I could reproduce them. --- test/DefineClass.java | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 test/DefineClass.java diff --git a/test/DefineClass.java b/test/DefineClass.java new file mode 100644 index 0000000000..bfbf67b0cd --- /dev/null +++ b/test/DefineClass.java @@ -0,0 +1,52 @@ +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; + +public class DefineClass { + private static File findHello(File directory) { + File[] files = directory.listFiles(); + for (File file: directory.listFiles()) { + if (file.isFile()) { + if (file.getName().equals("Hello.class")) { + return file; + } + } else if (file.isDirectory()) { + File result = findHello(file); + if (result != null) { + return result; + } + } + } + return null; + } + + private static byte[] read(File file) throws IOException { + byte[] bytes = new byte[(int) file.length()]; + FileInputStream in = new FileInputStream(file); + try { + if (in.read(bytes) != (int) file.length()) { + throw new RuntimeException(); + } + return bytes; + } finally { + in.close(); + } + } + + public static void main(String[] args) throws Exception { + byte[] bytes = read(findHello(new File(System.getProperty("user.dir")))); + Class c = new MyClassLoader(DefineClass.class.getClassLoader()).defineClass + ("Hello", bytes); + c.getMethod("main", String[].class).invoke(null, (Object) new String[0]); + } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] bytes) { + return super.defineClass(name, bytes, 0, bytes.length); + } + } +} From d12d33d71608ac5ce0ff43952f5239bfaad3fb3d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 14 Jan 2011 08:13:49 -0700 Subject: [PATCH 189/274] fix memory leak in Java_java_io_File_length --- classpath/java-io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 06dd0cc375..f3463e25b8 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -325,10 +325,10 @@ Java_java_io_File_length(JNIEnv* e, jclass, jstring path) if (chars) { STRUCT_STAT s; int r = STAT(chars, &s); + releaseChars(e, path, chars); if (r == 0) { return s.st_size; } - releaseChars(e, path, chars); } return -1; From b6978c6c68ed72670cc6ee3d6f2e699c393bf48d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 14 Jan 2011 11:26:00 -0700 Subject: [PATCH 190/274] always create file if necessary in Java_java_io_FileOutputStream_open Previously, we would only create the file if it did not already exist *and* we weren't appending. Now we do so whether appending or not. --- classpath/java-io.cpp | 4 +++- test/FileOutput.java | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index f3463e25b8..740d5199c6 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -624,7 +624,9 @@ Java_java_io_FileOutputStream_open(JNIEnv* e, jclass, jstring path, jboolean app { string_t chars = getChars(e, path); if (chars) { - int fd = doOpen(e, chars, append ? (O_WRONLY | O_APPEND) : (O_WRONLY | O_CREAT | O_TRUNC)); + int fd = doOpen(e, chars, append + ? (O_WRONLY | O_CREAT | O_APPEND) + : (O_WRONLY | O_CREAT | O_TRUNC)); releaseChars(e, path, chars); return fd; } else { diff --git a/test/FileOutput.java b/test/FileOutput.java index db4273f650..fa2cc0965e 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -4,14 +4,9 @@ import java.io.File; import java.io.IOException; public class FileOutput { - - /** - * @param args - * @throws IOException - */ - public static void main(String[] args) throws IOException { + private static void test(boolean appendFirst) throws IOException { try { - FileOutputStream f = new FileOutputStream("test.txt"); + FileOutputStream f = new FileOutputStream("test.txt", appendFirst); f.write("Hello world!\n".getBytes()); f.close(); @@ -37,4 +32,9 @@ public class FileOutput { } } + public static void main(String[] args) throws IOException { + test(false); + test(true); + } + } From d5ba7412cd10324d65af93c98830d34e0a202bb8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 15 Jan 2011 10:33:56 -0700 Subject: [PATCH 191/274] update DefineClass to exercise Class.newInstance This is an attempt to reproduce an issue reported on the discussion group. However, the current form of the test is passing, so further work will be necessary to trigger the bug. --- test/DefineClass.java | 48 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/test/DefineClass.java b/test/DefineClass.java index bfbf67b0cd..0b72cd5b95 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -3,15 +3,15 @@ import java.io.File; import java.io.FileInputStream; public class DefineClass { - private static File findHello(File directory) { + private static File findClass(String name, File directory) { File[] files = directory.listFiles(); for (File file: directory.listFiles()) { if (file.isFile()) { - if (file.getName().equals("Hello.class")) { + if (file.getName().equals(name + ".class")) { return file; } } else if (file.isDirectory()) { - File result = findHello(file); + File result = findClass(name, file); if (result != null) { return result; } @@ -33,11 +33,25 @@ public class DefineClass { } } + private static Class loadClass(String name) throws Exception { + return new MyClassLoader(DefineClass.class.getClassLoader()).defineClass + (name, read(findClass(name, new File(System.getProperty("user.dir"))))); + } + + private static void testStatic() throws Exception { + loadClass("DefineClass$Hello") + .getMethod("main", String[].class).invoke(null, (Object) new String[0]); + } + + private static void testDerived() throws Exception { + System.out.println + (String.valueOf + (((Base) loadClass("DefineClass$Derived").newInstance()).zip())); + } + public static void main(String[] args) throws Exception { - byte[] bytes = read(findHello(new File(System.getProperty("user.dir")))); - Class c = new MyClassLoader(DefineClass.class.getClassLoader()).defineClass - ("Hello", bytes); - c.getMethod("main", String[].class).invoke(null, (Object) new String[0]); + testStatic(); + testDerived(); } private static class MyClassLoader extends ClassLoader { @@ -49,4 +63,24 @@ public class DefineClass { return super.defineClass(name, bytes, 0, bytes.length); } } + + public static class Hello { + public static void main(String[] args) { + System.out.println("hello, world!"); + } + } + + public abstract static class Base { + public int foo; + + public void bar() { } + + public abstract int zip(); + } + + public static class Derived extends Base { + public int zip() { + return 42; + } + } } From 43cbfd3f3aba6c59c7f6a20ff79060c7572806a0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 16 Jan 2011 19:05:05 -0700 Subject: [PATCH 192/274] support stack unwinding without using a frame pointer Previously, we unwound the stack by following the chain of frame pointers for normal returns, stack trace creation, and exception unwinding. On x86, this required reserving EBP/RBP for frame pointer duties, making it unavailable for general computation and requiring that it be explicitly saved and restored on entry and exit, respectively. On PowerPC, we use an ABI that makes the stack pointer double as a frame pointer, so it doesn't cost us anything. We've been using the same convention on ARM, but it doesn't match the native calling convention, which makes it unusable when we want to call native code from Java and pass arguments on the stack. So far, the ARM calling convention mismatch hasn't been an issue because we've never passed more arguments from Java to native code than would fit in registers. However, we must now pass an extra argument (the thread pointer) to e.g. divideLong so it can throw an exception on divide by zero, which means the last argument must be passed on the stack. This will clobber the linkage area we've been using to hold the frame pointer, so we need to stop using it. One solution would be to use the same convention on ARM as we do on x86, but this would introduce the same overhead of making a register unavailable for general use and extra code at method entry and exit. Instead, this commit removes the need for a frame pointer. Unwinding involves consulting a map of instruction offsets to frame sizes which is generated at compile time. This is necessary because stack trace creation can happen at any time due to Thread.getStackTrace being called by another thread, and the frame size varies during the execution of a method. So far, only x86(_64) is working, and continuations and tail call optimization are probably broken. More to come. --- src/arch.h | 4 +- src/arm.S | 22 +++ src/arm.cpp | 4 + src/arm.h | 2 + src/assembler.h | 31 ++++- src/common.h | 63 ++++++--- src/compile-arm.S | 12 +- src/compile-x86.S | 225 ++++++++++++++---------------- src/compile.cpp | 346 +++++++++++++++++++++++++++++----------------- src/compiler.cpp | 40 +++++- src/jnienv.cpp | 42 +++--- src/machine.cpp | 4 +- src/machine.h | 6 +- src/posix.cpp | 14 +- src/system.h | 5 +- src/types.def | 1 + src/x86.S | 31 ++--- src/x86.cpp | 230 +++++++++++++++++++++--------- src/x86.h | 2 + 19 files changed, 675 insertions(+), 409 deletions(-) diff --git a/src/arch.h b/src/arch.h index f06dcef0f9..56afe1d5c3 100644 --- a/src/arch.h +++ b/src/arch.h @@ -22,8 +22,8 @@ #include "common.h" extern "C" void NO_RETURN -vmJump(void* address, void* base, void* stack, void* thread, - uintptr_t returnLow, uintptr_t returnHigh); +vmJump(void* address, void* stack, void* thread, uintptr_t returnLow, + uintptr_t returnHigh); namespace vm { diff --git a/src/arm.S b/src/arm.S index 6536017d60..458ece75cb 100644 --- a/src/arm.S +++ b/src/arm.S @@ -56,3 +56,25 @@ vmJump: mov sp, r2 mov r8, r3 bx lr + +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 + +.globl vmRun +vmRun: + // r0: function + // r1: arguments + // r2: checkpoint + stmfd sp!, {r4-r11, lr} + + str sp, [r2, #CHECKPOINT_STACK] + + mov r12, r0 + ldr r0, [r2, #CHECKPOINT_THREAD] + + blx r12 + +.globl vmRun_returnAddress +vmRun_returnAddress: + ldmfd sp!, {r4-r11, lr} + bx lr diff --git a/src/arm.cpp b/src/arm.cpp index bac3bc10a0..14528b5c59 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1720,6 +1720,10 @@ class MyArchitecture: public Assembler::Architecture { return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } + virtual bool argumentAlignment() { + return true; + } + virtual unsigned argumentRegisterCount() { return 4; } diff --git a/src/arm.h b/src/arm.h index e66377e7f6..198a76945f 100644 --- a/src/arm.h +++ b/src/arm.h @@ -14,6 +14,8 @@ #include "types.h" #include "common.h" +#define VA_LIST(x) (&(x)) + #define IP_REGISTER(context) (context->uc_mcontext.arm_pc) #define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) #define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) diff --git a/src/assembler.h b/src/assembler.h index 4c5f67b1a9..0cdc788ad1 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -22,6 +22,12 @@ const bool TailCalls = true; const bool TailCalls = false; #endif +#ifdef AVIAN_USE_FRAME_POINTER +const bool UseFramePointer = true; +#else +const bool UseFramePointer = false; +#endif + enum Operation { Return, LoadBarrier, @@ -298,6 +304,13 @@ class Assembler { virtual unsigned resolve(unsigned start, Block* next) = 0; }; + class FrameSizeEvent { + public: + virtual unsigned offset() = 0; + virtual int change() = 0; + virtual FrameSizeEvent* next() = 0; + }; + class Architecture { public: virtual unsigned floatRegisterSize() = 0; @@ -323,6 +336,7 @@ class Assembler { virtual unsigned frameFootprint(unsigned footprint) = 0; virtual unsigned argumentFootprint(unsigned footprint) = 0; + virtual bool argumentAlignment() = 0; virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; @@ -343,7 +357,6 @@ class Assembler { virtual unsigned frameFooterSize() = 0; virtual int returnAddressOffset() = 0; virtual int framePointerOffset() = 0; - virtual void nextFrame(void** stack, void** base) = 0; virtual void plan (UnaryOperation op, @@ -385,17 +398,19 @@ class Assembler { virtual Architecture* arch() = 0; - virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) = 0; + virtual void saveFrame(unsigned stackOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; - virtual void adjustFrame(unsigned footprint) = 0; - virtual void popFrame() = 0; + virtual void adjustFrame(unsigned difference) = 0; + virtual void popFrame(unsigned footprint) = 0; virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) = 0; - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) = 0; - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) = 0; virtual void apply(Operation op) = 0; @@ -422,6 +437,10 @@ class Assembler { virtual unsigned length() = 0; + virtual unsigned frameSizeEventCount() = 0; + + virtual FrameSizeEvent* firstFrameSizeEvent() = 0; + virtual void dispose() = 0; }; diff --git a/src/common.h b/src/common.h index 57dea834ef..1514369d15 100644 --- a/src/common.h +++ b/src/common.h @@ -311,67 +311,98 @@ log(unsigned n) return r; } +template inline unsigned wordOf(unsigned i) { - return i / BitsPerWord; + return i / (sizeof(T) * 8); +} + +inline unsigned +wordOf(unsigned i) +{ + return wordOf(i); +} + +template +inline unsigned +bitOf(unsigned i) +{ + return i % (sizeof(T) * 8); } inline unsigned bitOf(unsigned i) { - return i % BitsPerWord; + return bitOf(i); +} + +template +inline unsigned +indexOf(unsigned word, unsigned bit) +{ + return (word * (sizeof(T) * 8)) + bit; } inline unsigned indexOf(unsigned word, unsigned bit) { - return (word * BitsPerWord) + bit; + return indexOf(word, bit); } +template inline void -markBit(uintptr_t* map, unsigned i) +markBit(T* map, unsigned i) { - map[wordOf(i)] |= static_cast(1) << bitOf(i); + map[wordOf(i)] |= static_cast(1) << bitOf(i); } +template inline void -clearBit(uintptr_t* map, unsigned i) +clearBit(T* map, unsigned i) { - map[wordOf(i)] &= ~(static_cast(1) << bitOf(i)); + map[wordOf(i)] &= ~(static_cast(1) << bitOf(i)); } +template inline unsigned -getBit(uintptr_t* map, unsigned i) +getBit(T* map, unsigned i) { - return (map[wordOf(i)] & (static_cast(1) << bitOf(i))) - >> bitOf(i); + return (map[wordOf(i)] & (static_cast(1) << bitOf(i))) + >> bitOf(i); } +// todo: the following (clearBits, setBits, and getBits) could be made +// more efficient by operating on a word at a time instead of a bit at +// a time: + +template inline void -clearBits(uintptr_t* map, unsigned bitsPerRecord, unsigned index) +clearBits(T* map, unsigned bitsPerRecord, unsigned index) { for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { - clearBit(map, i); + clearBit(map, i); } } +template inline void -setBits(uintptr_t* map, unsigned bitsPerRecord, int index, unsigned v) +setBits(T* map, unsigned bitsPerRecord, int index, unsigned v) { for (int i = index + bitsPerRecord - 1; i >= index; --i) { - if (v & 1) markBit(map, i); else clearBit(map, i); + if (v & 1) markBit(map, i); else clearBit(map, i); v >>= 1; } } +template inline unsigned -getBits(uintptr_t* map, unsigned bitsPerRecord, unsigned index) +getBits(T* map, unsigned bitsPerRecord, unsigned index) { unsigned v = 0; for (unsigned i = index, limit = index + bitsPerRecord; i < limit; ++i) { v <<= 1; - v |= getBit(map, i); + v |= getBit(map, i); } return v; } diff --git a/src/compile-arm.S b/src/compile-arm.S index c61ebaff37..ed66b222a1 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -22,12 +22,12 @@ # define GLOBAL(x) x #endif -#define THREAD_STACK 2144 -#define THREAD_CONTINUATION 2148 +#define THREAD_STACK 2152 +#define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 -#define THREAD_EXCEPTION_OFFSET 2156 -#define THREAD_EXCEPTION_HANDLER 2160 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 @@ -121,7 +121,7 @@ GLOBAL(vmInvoke_safeStack): mov r4,sp str r4,[sp,r7]! - add r7,r5,#CONTINUATION_BODY + add r7,r5,#CONTINUATION_BODY mov r11,#0 add r10,sp,#ARGUMENT_BASE diff --git a/src/compile-x86.S b/src/compile-x86.S index 4b79aa4e38..080b3ba5da 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -23,7 +23,8 @@ #ifdef __x86_64__ -#define THREAD_STACK 2232 +#define THREAD_STACK 2224 +#define THREAD_SCRATCH 2232 #if defined __MINGW32__ || defined __CYGWIN32__ @@ -41,22 +42,25 @@ GLOBAL(vmInvoke): // 48(%rbp) : frameSize // 56(%rbp) : returnType (ignored) - // allocate stack space, adding room for callee-saved registers - movl 48(%rbp),%eax - subq %rax,%rsp + // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movq %rsp,THREAD_SCRATCH(%rcx) // save callee-saved registers - movq %rsp,%r11 - addq %rax,%r11 - - movq %rbx,0(%r11) - movq %r12,8(%r11) - movq %r13,16(%r11) - movq %r14,24(%r11) - movq %r15,32(%r11) - movq %rsi,40(%r11) - movq %rdi,48(%r11) + movq %rbx,0(%rsp) + movq %r12,8(%rsp) + movq %r13,16(%rsp) + movq %r14,24(%rsp) + movq %r15,32(%rsp) + movq %rsi,40(%rsp) + movq %rdi,48(%rsp) + + // allocate stack space for arguments + movl 48(%rbp),%eax + subq %rax,%rsp // we use rbx to hold the thread pointer, by convention mov %rcx,%rbx @@ -80,7 +84,7 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer - movq %rbp,%rsp + movq THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -96,19 +100,17 @@ GLOBAL(vmInvoke_safeStack): # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS - // restore callee-saved registers (below the stack pointer, but in - // the red zone) - movq %rsp,%r11 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r11 - - movq 0(%r11),%rbx - movq 8(%r11),%r12 - movq 16(%r11),%r13 - movq 24(%r11),%r14 - movq 32(%r11),%r15 - movq 40(%r11),%rsi - movq 48(%r11),%rdi + // restore callee-saved registers + movq 0(%rsp),%rbx + movq 8(%rsp),%r12 + movq 16(%rsp),%r13 + movq 24(%rsp),%r14 + movq 32(%rsp),%r15 + movq 40(%rsp),%rsi + movq 48(%rsp),%rdi + addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + // return popq %rbp ret @@ -118,47 +120,39 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rcx: thread // %rdx: address - // %r8 : base - // %r9 : (unused) - // 40(%rsp): argumentFootprint - // 48(%rsp): arguments - // 56(%rsp): frameSize - - movq %r8,%rbp + // %r8 : stack + // %r9 : argumentFootprint + // 40(%rsp): arguments + // 48(%rsp): frameSize - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movq %rbp,%r9 - // allocate new frame, adding room for callee-saved registers - movl 56(%rsp),%eax - subq %rax,%r9 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9 + movl 48(%rsp),%eax + subq %rax,%r8 + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r8 movq %rcx,%rbx // set return address leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10 - movq %r10,(%r9) + movq %r10,(%r8) // copy arguments into place movq $0,%r11 - movl 48(%rsp),%r8d movl 40(%rsp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movq (%r8,%r11,1),%r10 - movq %r10,8(%r9,%r11,1) + movq (%rax,%r11,1),%r10 + movq %r10,8(%r8,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): - cmpq %rax,%r11 + cmpq %9,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - movq %r9,%rsp + movq %r8,%rsp jmp *%rdx #else // not AVIAN_CONTINUATIONS @@ -183,20 +177,23 @@ GLOBAL(vmInvoke): // %r8 : frameSize // %r9 : returnType (ignored) - // allocate stack space, adding room for callee-saved registers - subq %r8,%rsp + // allocate stack space for callee-saved registers subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movq %rsp,THREAD_SCRATCH(%rdi) + // save callee-saved registers - movq %rsp,%r9 - addq %r8,%r9 - - movq %rbx,0(%r9) - movq %r12,8(%r9) - movq %r13,16(%r9) - movq %r14,24(%r9) - movq %r15,32(%r9) - + movq %rbx,0(%rsp) + movq %r12,8(%rsp) + movq %r13,16(%rsp) + movq %r14,24(%rsp) + movq %r15,32(%rsp) + + // allocate stack space for arguments + subq %r8,%rsp + // we use rbx to hold the thread pointer, by convention mov %rdi,%rbx @@ -219,7 +216,7 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): // restore stack pointer - movq %rbp,%rsp + movq THREAD_SCRATCH(%rbx),%rsp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -234,18 +231,16 @@ GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS + + // restore callee-saved registers + movq 0(%rsp),%rbx + movq 8(%rsp),%r12 + movq 16(%rsp),%r13 + movq 24(%rsp),%r14 + movq 32(%rsp),%r15 + + addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp - // restore callee-saved registers (below the stack pointer, but in - // the red zone) - movq %rsp,%r9 - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9 - - movq 0(%r9),%rbx - movq 8(%r9),%r12 - movq 16(%r9),%r13 - movq 24(%r9),%r14 - movq 32(%r9),%r15 - // return popq %rbp ret @@ -255,45 +250,37 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // %rdi: thread // %rsi: address - // %rdx: base - // %rcx: (unused) - // %r8 : argumentFootprint - // %r9 : arguments - // 8(%rsp): frameSize - - movq %rdx,%rbp - - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movq %rbp,%rcx + // %rdx: stack + // %rcx: argumentFootprint + // %r8 : arguments + // %r9 : frameSize // allocate new frame, adding room for callee-saved registers - movl 8(%rsp),%eax - subq %rax,%rcx - subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rcx + subq %r9,%rdx + subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rdx movq %rdi,%rbx // set return address movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10 - movq %r10,(%rcx) + movq %r10,(%rdx) // copy arguments into place movq $0,%r11 jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - movq (%r9,%r11,1),%r10 - movq %r10,8(%rcx,%r11,1) + movq (%r8,%r11,1),%r10 + movq %r10,8(%rdx,%r11,1) addq $8,%r11 LOCAL(vmJumpAndInvoke_argumentTest): - cmpq %r8,%r11 + cmpq %rcx,%r11 jb LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - movq %rcx,%rsp + movq %rdx,%rsp jmp *%rsi #else // not AVIAN_CONTINUATIONS @@ -306,7 +293,8 @@ LOCAL(vmJumpAndInvoke_argumentTest): #elif defined __i386__ -#define THREAD_STACK 2152 +#define THREAD_STACK 2148 +#define THREAD_SCRATCH 2152 #define CALLEE_SAVED_REGISTER_FOOTPRINT 16 @@ -321,21 +309,24 @@ GLOBAL(vmInvoke): // 20(%ebp): argumentFootprint // 24(%ebp): frameSize // 28(%ebp): returnType - - // allocate stack space, adding room for callee-saved registers - subl 24(%ebp),%esp + + // allocate stack space for callee-saved registers subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp - // save callee-saved registers - movl %esp,%ecx - addl 24(%ebp),%ecx + // remember this stack position, since we won't be able to rely on + // %rbp being restored when the call returns + movl 8(%ebp),%eax + movl %esp,THREAD_SCRATCH(%eax) - movl %ebx,0(%ecx) - movl %esi,4(%ecx) - movl %edi,8(%ecx) + movl %ebx,0(%esp) + movl %esi,4(%esp) + movl %edi,8(%esp) + + // allocate stack space for arguments + subl 24(%ebp),%esp // we use ebx to hold the thread pointer, by convention - mov 8(%ebp),%ebx + mov %eax,%ebx // copy arguments into place movl $0,%ecx @@ -356,11 +347,8 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): - // restore stack pointer, preserving the area containing saved - // registers - movl %ebp,%ecx - subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx - movl %ecx,%esp + // restore stack pointer + movl THREAD_SCRATCH(%ebx),%esp // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See @@ -380,11 +368,11 @@ GLOBAL(vmInvoke_safeStack): movl 0(%esp),%ebx movl 4(%esp),%esi movl 8(%esp),%edi - - // handle return value based on expected type - movl 28(%ebp),%ecx addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp + + // handle return value based on expected type + movl 28(%esp),%ecx LOCAL(vmInvoke_void): cmpl $VOID_TYPE,%ecx @@ -412,20 +400,15 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // 4(%esp): thread // 8(%esp): address - // 12(%esp): base - // 16(%esp): (unused) - // 20(%esp): argumentFootprint - // 24(%esp): arguments - // 28(%esp): frameSize + // 12(%esp): stack + // 16(%esp): argumentFootprint + // 20(%esp): arguments + // 24(%esp): frameSize - movl 12(%esp),%ebp - - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - movl %ebp,%ecx + movl 12(%esp),%ecx // allocate new frame, adding room for callee-saved registers - subl 28(%esp),%ecx + subl 24(%esp),%ecx subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx movl 4(%esp),%ebx @@ -447,8 +430,8 @@ LOCAL(vmJumpAndInvoke_offset): // copy arguments into place movl $0,%esi - movl 20(%esp),%edx - movl 24(%esp),%eax + movl 16(%esp),%edx + movl 20(%esp),%eax jmp LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): diff --git a/src/compile.cpp b/src/compile.cpp index 6069a0dc13..42791ca8b4 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -29,18 +29,15 @@ extern "C" void vmInvoke_safeStack(); extern "C" void -vmJumpAndInvoke(void* thread, void* function, void* base, void* stack, +vmJumpAndInvoke(void* thread, void* function, void* stack, unsigned argumentFootprint, uintptr_t* arguments, unsigned frameSize); -extern "C" void -vmCall(); - namespace { namespace local { -const bool DebugCompile = false; +const bool DebugCompile = true; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; @@ -90,26 +87,28 @@ class MyThread: public Thread { public: CallTrace(MyThread* t, object method): t(t), - base(t->base), stack(t->stack), + scratch(t->scratch), continuation(t->continuation), nativeMethod((methodFlags(t, method) & ACC_NATIVE) ? method : 0), targetMethod(0), originalMethod(method), next(t->trace) { - doTransition(t, 0, 0, 0, 0, this); + doTransition(t, 0, 0, 0, this); } ~CallTrace() { assert(t, t->stack == 0); - doTransition(t, 0, stack, base, continuation, next); + t->scratch = scratch; + + doTransition(t, 0, stack, continuation, next); } MyThread* t; - void* base; void* stack; + void* scratch; object continuation; object nativeMethod; object targetMethod; @@ -132,11 +131,10 @@ class MyThread: public Thread { Context* context; }; - Context(MyThread* t, void* ip, void* stack, void* base, - object continuation, CallTrace* trace): + Context(MyThread* t, void* ip, void* stack, object continuation, + CallTrace* trace): ip(ip), stack(stack), - base(base), continuation(continuation), trace(trace), protector(t, this) @@ -144,7 +142,6 @@ class MyThread: public Thread { void* ip; void* stack; - void* base; object continuation; CallTrace* trace; MyProtector protector; @@ -152,9 +149,9 @@ class MyThread: public Thread { class TraceContext: public Context { public: - TraceContext(MyThread* t, void* ip, void* stack, void* base, - object continuation, CallTrace* trace): - Context(t, ip, stack, base, continuation, trace), + TraceContext(MyThread* t, void* ip, void* stack, object continuation, + CallTrace* trace): + Context(t, ip, stack, continuation, trace), t(t), next(t->traceContext) { @@ -162,7 +159,7 @@ class MyThread: public Thread { } TraceContext(MyThread* t): - Context(t, t->ip, t->stack, t->base, t->continuation, t->trace), + Context(t, t->ip, t->stack, t->continuation, t->trace), t(t), next(t->traceContext) { @@ -177,7 +174,7 @@ class MyThread: public Thread { TraceContext* next; }; - static void doTransition(MyThread* t, void* ip, void* stack, void* base, + static void doTransition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { // in this function, we "atomically" update the thread context @@ -187,7 +184,7 @@ class MyThread: public Thread { assert(t, t->transition == 0); - Context c(t, ip, stack, base, continuation, trace); + Context c(t, ip, stack, continuation, trace); compileTimeMemoryBarrier(); @@ -196,7 +193,6 @@ class MyThread: public Thread { compileTimeMemoryBarrier(); t->ip = ip; - t->base = base; t->stack = stack; t->continuation = continuation; t->trace = trace; @@ -210,8 +206,8 @@ class MyThread: public Thread { bool useNativeFeatures): Thread(m, javaThread, parent), ip(0), - base(0), stack(0), + scratch(0), continuation(0), exceptionStackAdjustment(0), exceptionOffset(0), @@ -232,8 +228,8 @@ class MyThread: public Thread { } void* ip; - void* base; void* stack; + void* scratch; object continuation; uintptr_t exceptionStackAdjustment; uintptr_t exceptionOffset; @@ -250,10 +246,10 @@ class MyThread: public Thread { }; void -transition(MyThread* t, void* ip, void* stack, void* base, object continuation, +transition(MyThread* t, void* ip, void* stack, object continuation, MyThread::CallTrace* trace) { - MyThread::doTransition(t, ip, stack, base, continuation, trace); + MyThread::doTransition(t, ip, stack, continuation, trace); } unsigned @@ -372,6 +368,104 @@ methodForIp(MyThread* t, void* ip) root(t, MethodTreeSentinal), compareIpToMethodBounds); } +unsigned +localSize(MyThread* t, object method) +{ + unsigned size = codeMaxLocals(t, methodCode(t, method)); + if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) + == ACC_SYNCHRONIZED) + { + ++ size; + } + return size; +} + +unsigned +alignedFrameSize(MyThread* t, object method) +{ + return t->arch->alignFrameSize + (localSize(t, method) + - methodParameterFootprint(t, method) + + codeMaxStack(t, methodCode(t, method)) + + t->arch->frameFootprint(MaxNativeCallFootprint)); +} + +unsigned +bitsNeeded(unsigned v) +{ + return log(v + 1); +} + +void +setTableValue(Thread* t, object table, unsigned base, unsigned max, + unsigned index, unsigned value) +{ + unsigned bits = bitsNeeded(max); + setBits + (&intArrayBody(t, table, base), bits, index * bits, value); +} + +unsigned +getTableValue(Thread* t, object table, unsigned base, unsigned max, + unsigned index) +{ + unsigned bits = bitsNeeded(max); + return getBits + (&intArrayBody(t, table, base), bits, index * bits); +} + +unsigned +frameSize(MyThread* t, intptr_t ip, object method) +{ + object code = methodCode(t, method); + object table = codeFrameSizeTable(t, code); + unsigned count = intArrayBody(t, table, 0); + unsigned max = alignedFrameSize(t, method); + intptr_t start = codeCompiled(t, code); + int codeSize = compiledSize(start); + unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32); + + assert(t, ip >= start); + assert(t, ip <= start + codeSize); + + unsigned offset = ip - start; + unsigned bottom = 0; + unsigned top = count; + for (unsigned span = top - bottom; span; span = top - bottom) { + unsigned middle = bottom + (span / 2); + unsigned candidate = getTableValue(t, table, 1, codeSize, middle); + + if (offset >= candidate + and (middle + 1 == count + or offset < getTableValue(t, table, 1, codeSize, middle + 1))) + { + return getTableValue(t, table, 1 + indexSize, max, middle); + } else if (offset < candidate) { + top = middle; + } else if (offset > candidate) { + bottom = middle + 1; + } + } + + if (top == 0) { + return 0; + } else if (top < count) { + return getTableValue(t, table, 1 + indexSize, max, top); + } else if (top == count && count > 0) { + return getTableValue(t, table, 1 + indexSize, max, top - 1); + } else { + abort(t); + } +} + +void* +nextFrame(MyThread* t, void* ip, void* sp, object method) +{ + return reinterpret_cast(sp) + local::frameSize + (t, reinterpret_cast(ip), method) + + t->arch->frameReturnAddressSize(); +} + class MyStackWalker: public Processor::StackWalker { public: enum State { @@ -406,13 +500,11 @@ class MyStackWalker: public Processor::StackWalker { { if (t->traceContext) { ip_ = t->traceContext->ip; - base = t->traceContext->base; stack = t->traceContext->stack; trace = t->traceContext->trace; continuation = t->traceContext->continuation; } else { ip_ = 0; - base = t->base; stack = t->stack; trace = t->trace; continuation = t->continuation; @@ -423,7 +515,6 @@ class MyStackWalker: public Processor::StackWalker { t(w->t), state(w->state), ip_(w->ip_), - base(w->base), stack(w->stack), trace(w->trace), method_(w->method_), @@ -478,7 +569,6 @@ class MyStackWalker: public Processor::StackWalker { if (trace) { continuation = trace->continuation; stack = trace->stack; - base = trace->base; ip_ = t->arch->frameIp(stack); trace = trace->next; @@ -509,7 +599,7 @@ class MyStackWalker: public Processor::StackWalker { break; case Method: - t->arch->nextFrame(&stack, &base); + stack = nextFrame(t, ip_, stack, method_); ip_ = t->arch->frameIp(stack); break; @@ -561,7 +651,6 @@ class MyStackWalker: public Processor::StackWalker { MyThread* t; State state; void* ip_; - void* base; void* stack; MyThread::CallTrace* trace; object method_; @@ -569,28 +658,6 @@ class MyStackWalker: public Processor::StackWalker { MyProtector protector; }; -unsigned -localSize(MyThread* t, object method) -{ - unsigned size = codeMaxLocals(t, methodCode(t, method)); - if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC)) - == ACC_SYNCHRONIZED) - { - ++ size; - } - return size; -} - -unsigned -alignedFrameSize(MyThread* t, object method) -{ - return t->arch->alignFrameSize - (localSize(t, method) - - methodParameterFootprint(t, method) - + codeMaxStack(t, methodCode(t, method)) - + t->arch->frameFootprint(MaxNativeCallFootprint)); -} - int localOffset(MyThread* t, int v, object method) { @@ -1929,22 +1996,19 @@ releaseLock(MyThread* t, object method, void* stack) } void -findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - void** targetStack, object* targetContinuation) +findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, + object* targetContinuation) { void* ip; - void* base; void* stack; object continuation; if (t->traceContext) { ip = t->traceContext->ip; - base = t->traceContext->base; stack = t->traceContext->stack; continuation = t->traceContext->continuation; } else { ip = 0; - base = t->base; stack = t->stack; continuation = t->continuation; } @@ -1963,9 +2027,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, if (handler) { *targetIp = handler; - *targetBase = base; - t->arch->nextFrame(&stack, &base); + stack = nextFrame(t, ip, stack, method); void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); @@ -1977,7 +2040,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->exception = 0; } else { - t->arch->nextFrame(&stack, &base); + stack = nextFrame(t, ip, stack, method); ip = t->arch->frameIp(stack); if (t->exception) { @@ -1988,7 +2051,6 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } } else { *targetIp = ip; - *targetBase = base; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); *targetContinuation = continuation; @@ -2029,11 +2091,9 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, } object -makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) +makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) { void* ip = t->arch->frameIp(t->stack); - void* base = t->base; void* stack = t->stack; object context = t->continuation @@ -2066,7 +2126,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, top += argumentFootprint - alignment; } - t->arch->nextFrame(&stack, &base); + stack = nextFrame(t, ip, stack, method); void** bottom = static_cast(stack) + t->arch->frameReturnAddressSize(); @@ -2101,7 +2161,6 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, target = method; } else { *targetIp = ip; - *targetBase = base; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); } @@ -2117,14 +2176,13 @@ void NO_RETURN unwind(MyThread* t) { void* ip; - void* base; void* stack; object continuation; - findUnwindTarget(t, &ip, &base, &stack, &continuation); + findUnwindTarget(t, &ip, &stack, &continuation); - transition(t, ip, stack, base, continuation, t->trace); + transition(t, ip, stack, continuation, t->trace); - vmJump(ip, base, stack, t, 0, 0); + vmJump(ip, stack, t, 0, 0); } class MyCheckpoint: public Thread::Checkpoint { @@ -5165,6 +5223,45 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) } } +object +makeFrameSizeTable(MyThread* t, Context* c, unsigned codeSize) +{ + Assembler* a = c->assembler; + unsigned count = a->frameSizeEventCount(); + int max = alignedFrameSize(t, c->method); + unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32); + unsigned tableSize = ceiling(count * bitsNeeded(max), 32); + object table = makeIntArray(t, 1 + indexSize + tableSize); + + intArrayBody(t, table, 0) = count; + + unsigned index = 0; + int value = 0; + for (Assembler::FrameSizeEvent* e = a->firstFrameSizeEvent(); + e; e = e->next()) + { + assert(t, index < count); + + unsigned offset = e->offset(); + assert(t, offset <= codeSize); + + value += e->change(); + + fprintf(stderr, "offset %d change %d value %d\n", + offset, e->change(), value); + + assert(t, value >= 0); + assert(t, value <= max); + + setTableValue(t, table, 1, codeSize, index, offset); + setTableValue(t, table, 1 + indexSize, max, index, value); + + ++ index; + } + + return table; +} + void printSet(uintptr_t m, unsigned limit) { @@ -5842,18 +5939,23 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - object newExceptionHandlerTable = translateExceptionHandlerTable - (t, c, context->method, reinterpret_cast(start)); + { object newExceptionHandlerTable = translateExceptionHandlerTable + (t, c, context->method, reinterpret_cast(start)); - PROTECT(t, newExceptionHandlerTable); + PROTECT(t, newExceptionHandlerTable); - object newLineNumberTable = translateLineNumberTable - (t, c, methodCode(t, context->method), reinterpret_cast(start)); + object newLineNumberTable = translateLineNumberTable + (t, c, methodCode(t, context->method), + reinterpret_cast(start)); - { object code = methodCode(t, context->method); + PROTECT(t, newLineNumberTable); + + object frameSizeTable = makeFrameSizeTable(t, context, codeSize); + + object code = methodCode(t, context->method); code = makeCode - (t, 0, newExceptionHandlerTable, newLineNumberTable, + (t, 0, newExceptionHandlerTable, newLineNumberTable, frameSizeTable, reinterpret_cast(start), codeMaxStack(t, code), codeMaxLocals(t, code), 0); @@ -6423,8 +6525,7 @@ invokeNative(MyThread* t) stack += t->arch->frameReturnAddressSize(); - transition(t, t->arch->frameIp(t->stack), stack, t->base, t->continuation, - t->trace); + transition(t, t->arch->frameIp(t->stack), stack, t->continuation, t->trace); return result; } @@ -6595,7 +6696,6 @@ void visitStack(MyThread* t, Heap::Visitor* v) { void* ip = t->arch->frameIp(t->stack); - void* base = t->base; void* stack = t->stack; MyThread::CallTrace* trace = t->trace; @@ -6611,14 +6711,13 @@ visitStack(MyThread* t, Heap::Visitor* v) if (method) { PROTECT(t, method); - t->arch->nextFrame(&stack, &base); + stack = nextFrame(t, ip, stack, method); visitStackAndLocals(t, v, stack, method, ip); ip = t->arch->frameIp(stack); } else if (trace) { stack = trace->stack; - base = trace->base; ip = t->arch->frameIp(stack); trace = trace->next; @@ -6671,24 +6770,24 @@ walkContinuationBody(MyThread* t, Heap::Walker* w, object c, int start) void callContinuation(MyThread* t, object continuation, object result, - object exception, void* ip, void* base, void* stack) + object exception, void* ip, void* stack) { assert(t, t->exception == 0); if (exception) { t->exception = exception; - MyThread::TraceContext c(t, ip, stack, base, continuation, t->trace); + MyThread::TraceContext c(t, ip, stack, continuation, t->trace); - findUnwindTarget(t, &ip, &base, &stack, &continuation); + findUnwindTarget(t, &ip, &stack, &continuation); } t->trace->nativeMethod = 0; t->trace->targetMethod = 0; - transition(t, ip, stack, base, continuation, t->trace); + transition(t, ip, stack, continuation, t->trace); - vmJump(ip, base, stack, t, reinterpret_cast(result), 0); + vmJump(ip, stack, t, reinterpret_cast(result), 0); } int8_t* @@ -6746,7 +6845,7 @@ compatibleReturnType(MyThread* t, object oldMethod, object newMethod) } void -jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) +jumpAndInvoke(MyThread* t, object method, void* stack, ...) { t->trace->targetMethod = 0; @@ -6766,7 +6865,6 @@ jumpAndInvoke(MyThread* t, object method, void* base, void* stack, ...) vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), - base, stack, argumentCount * BytesPerWord, RUNTIME_ARRAY_BODY(arguments), @@ -6858,25 +6956,24 @@ callContinuation(MyThread* t, object continuation, object result, } void* ip; - void* base; void* stack; object threadContinuation; - findUnwindTarget(t, &ip, &base, &stack, &threadContinuation); + findUnwindTarget(t, &ip, &stack, &threadContinuation); switch (action) { case Call: { - callContinuation(t, continuation, result, exception, ip, base, stack); + callContinuation(t, continuation, result, exception, ip, stack); } break; case Unwind: { - callContinuation(t, nextContinuation, result, 0, ip, base, stack); + callContinuation(t, nextContinuation, result, 0, ip, stack); } break; case Rewind: { - transition(t, 0, 0, 0, nextContinuation, t->trace); + transition(t, 0, 0, nextContinuation, t->trace); jumpAndInvoke - (t, root(t, RewindMethod), base, stack, + (t, root(t, RewindMethod), stack, continuationContextBefore(t, continuationContext(t, nextContinuation)), continuation, result, exception); } break; @@ -6891,7 +6988,6 @@ callWithCurrentContinuation(MyThread* t, object receiver) { object method = 0; void* ip = 0; - void* base = 0; void* stack = 0; { PROTECT(t, receiver); @@ -6920,17 +7016,16 @@ callWithCurrentContinuation(MyThread* t, object receiver) compile(t, local::codeAllocator(t), 0, method); - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); + t->continuation = makeCurrentContinuation(t, &ip, &stack); } - jumpAndInvoke(t, method, base, stack, receiver, t->continuation); + jumpAndInvoke(t, method, stack, receiver, t->continuation); } void dynamicWind(MyThread* t, object before, object thunk, object after) { void* ip = 0; - void* base = 0; void* stack = 0; { PROTECT(t, before); @@ -6949,7 +7044,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) } } - t->continuation = makeCurrentContinuation(t, &ip, &base, &stack); + t->continuation = makeCurrentContinuation(t, &ip, &stack); object newContext = makeContinuationContext (t, continuationContext(t, t->continuation), before, after, @@ -6958,7 +7053,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) set(t, t->continuation, ContinuationContext, newContext); } - jumpAndInvoke(t, root(t, WindMethod), base, stack, before, thunk, after); + jumpAndInvoke(t, root(t, WindMethod), stack, before, thunk, after); } class ArgumentList { @@ -7168,9 +7263,7 @@ class SignalHandler: public System::SignalHandler { SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): m(0), type(type), root(root), fixedSize(fixedSize) { } - virtual bool handleSignal(void** ip, void** base, void** stack, - void** thread) - { + virtual bool handleSignal(void** ip, void** stack, void** thread) { MyThread* t = static_cast(m->localThread->get()); if (t and t->state == Thread::ActiveState) { object node = methodForIp(t, *ip); @@ -7180,7 +7273,7 @@ class SignalHandler: public System::SignalHandler { MyThread::TraceContext context (t, static_cast(*ip) + 1, static_cast(*stack) - t->arch->frameReturnAddressSize(), - *base, t->continuation, t->trace); + t->continuation, t->trace); if (ensure(t, fixedSize + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); @@ -7195,9 +7288,9 @@ class SignalHandler: public System::SignalHandler { // printTrace(t, t->exception); object continuation; - findUnwindTarget(t, ip, base, stack, &continuation); + findUnwindTarget(t, ip, stack, &continuation); - transition(t, ip, stack, base, continuation, t->trace); + transition(t, ip, stack, continuation, t->trace); *thread = t; @@ -7291,6 +7384,7 @@ class MyProcessor: public Processor { if (false) { fprintf(stderr, "%d\n", difference(&(t->stack), t)); + fprintf(stderr, "%d\n", difference(&(t->scratch), t)); fprintf(stderr, "%d\n", difference(&(t->continuation), t)); fprintf(stderr, "%d\n", difference(&(t->exception), t)); fprintf(stderr, "%d\n", difference(&(t->exceptionStackAdjustment), t)); @@ -7571,18 +7665,16 @@ class MyProcessor: public Processor { t(t), p(p), target(target), trace(0) { } - virtual void visit(void* ip, void* base, void* stack) { + virtual void visit(void* ip, void* stack) { MyThread::TraceContext c(target); if (methodForIp(t, ip)) { // we caught the thread in Java code - use the register values c.ip = ip; - c.base = base; c.stack = stack; } else if (target->transition) { // we caught the thread in native code while in the middle - // of updating the context fields (MyThread::stack, - // MyThread::base, etc.) + // of updating the context fields (MyThread::stack, etc.) static_cast(c) = *(target->transition); } else if (isVmInvokeUnsafeStack(ip)) { // we caught the thread in native code just after returning @@ -7591,31 +7683,26 @@ class MyProcessor: public Processor { // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; - c.base = 0; c.stack = 0; } else if (target->stack and (not isThunkUnsafeStack(t, ip)) and (not isVirtualThunk(t, ip))) { // we caught the thread in a thunk or native code, and the - // saved stack and base pointers indicate the most recent - // Java frame on the stack + // saved stack pointer indicates the most recent Java frame + // on the stack c.ip = t->arch->frameIp(target->stack); - c.base = target->base; c.stack = target->stack; } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { - // we caught the thread in a thunk where the stack and base - // registers indicate the most recent Java frame on the - // stack + // we caught the thread in a thunk where the stack register + // indicates the most recent Java frame on the stack c.ip = t->arch->frameIp(stack); - c.base = base; c.stack = stack; } else { // we caught the thread in native code, and the most recent // Java frame, if any, can be found in // MyThread::continuation or MyThread::trace c.ip = 0; - c.base = 0; c.stack = 0; } @@ -8316,7 +8403,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = defaultContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.default_.frameSavedOffset = a->length(); @@ -8326,7 +8413,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(defaultContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrame(); + a->popFrame(t->arch->alignFrameSize(1)); Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); @@ -8360,7 +8447,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(Move, BytesPerWord, RegisterOperand, &index, BytesPerWord, MemoryOperand, &virtualCallIndex); - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.defaultVirtual.frameSavedOffset = a->length(); @@ -8370,7 +8457,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(defaultVirtualContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrame(); + a->popFrame(t->arch->alignFrameSize(1)); Assembler::Register result(t->arch->returnLow()); a->apply(Jump, BytesPerWord, RegisterOperand, &result); @@ -8382,7 +8469,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = nativeContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.native.frameSavedOffset = a->length(); @@ -8392,7 +8479,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) Assembler::Constant proc(&(nativeContext.promise)); a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); - a->popFrameAndUpdateStackAndReturn(difference(&(t->stack), t)); + a->popFrameAndUpdateStackAndReturn + (t->arch->alignFrameSize(1), difference(&(t->stack), t)); p->thunks.native.length = a->endBlock(false)->resolve(0, 0); } @@ -8401,7 +8489,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = aioobContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.aioob.frameSavedOffset = a->length(); @@ -8418,7 +8506,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = stackOverflowContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.stackOverflow.frameSavedOffset = a->length(); @@ -8435,7 +8523,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = tableContext.context.assembler; - a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + a->saveFrame(difference(&(t->stack), t)); p->thunks.table.frameSavedOffset = a->length(); diff --git a/src/compiler.cpp b/src/compiler.cpp index e25dfafb50..65b5437cad 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -3147,12 +3147,25 @@ class CallEvent: public Event { assert(c, stackArgumentFootprint == 0); Stack* s = argumentStack; - unsigned frameIndex = 0; unsigned index = 0; + unsigned argumentIndex = 0; while (true) { + unsigned footprint; + if (argumentIndex + 1 < argumentCount + and s->value->nextWord == s->next->value) + { + footprint = 2; + } else { + footprint = 1; + } + + if (footprint > 1 and index & 1 and c->arch->argumentAlignment()) { + ++ index; + } + SiteMask targetMask; - if (index < c->arch->argumentRegisterCount()) { + if (index + footprint <= c->arch->argumentRegisterCount()) { int number = c->arch->argumentRegister(index); if (DebugReads) { @@ -3162,17 +3175,24 @@ class CallEvent: public Event { targetMask = fixedRegisterMask(number); registerMask &= ~(1 << number); } else { + if (index < c->arch->argumentRegisterCount()) { + index = c->arch->argumentRegisterCount(); + } + + unsigned frameIndex = index - c->arch->argumentRegisterCount(); + if (DebugReads) { fprintf(stderr, "stack %d arg read %p\n", frameIndex, s->value); } targetMask = SiteMask(1 << MemoryOperand, 0, frameIndex); - ++ frameIndex; } addRead(c, this, s->value, targetMask); - if ((++ index) < argumentCount) { + ++ index; + + if ((++ argumentIndex) < argumentCount) { s = s->next; } else { break; @@ -3225,7 +3245,11 @@ class CallEvent: public Event { int base = frameBase(c); returnAddressIndex = base + c->arch->returnAddressOffset(); - framePointerIndex = base + c->arch->framePointerOffset(); + if (UseFramePointer) { + framePointerIndex = base + c->arch->framePointerOffset(); + } else { + framePointerIndex = -1; + } frameOffset = totalFrameSize(c) - c->arch->argumentFootprint(stackArgumentFootprint); @@ -3451,7 +3475,8 @@ class ReturnEvent: public Event { if (not unreachable(this)) { c->assembler->popFrameAndPopArgumentsAndReturn - (c->arch->argumentFootprint(c->parameterFootprint)); + (c->alignedFrameSize, + c->arch->argumentFootprint(c->parameterFootprint)); } } @@ -6042,7 +6067,8 @@ class MyCompiler: public Compiler { unsigned base = frameBase(&c); c.frameResources[base + c.arch->returnAddressOffset()].reserved = true; - c.frameResources[base + c.arch->framePointerOffset()].reserved = true; + c.frameResources[base + c.arch->framePointerOffset()].reserved + = UseFramePointer; // leave room for logical instruction -1 unsigned codeSize = sizeof(LogicalInstruction*) * (logicalCodeLength + 1); diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 5a80e8d216..027025b1e3 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -561,7 +561,7 @@ NewObjectV(Thread* t, jclass c, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(c), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, newObjectV, arguments)); } @@ -597,7 +597,7 @@ CallObjectMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, callObjectMethodV, arguments)); } @@ -631,7 +631,7 @@ CallBooleanMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments) != 0; } @@ -654,7 +654,7 @@ CallByteMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } @@ -677,7 +677,7 @@ CallCharMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } @@ -700,7 +700,7 @@ CallShortMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } @@ -723,7 +723,7 @@ CallIntMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callIntMethodV, arguments); } @@ -757,7 +757,7 @@ CallLongMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return run(t, callLongMethodV, arguments); } @@ -780,7 +780,7 @@ CallFloatMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return bitsToFloat(run(t, callIntMethodV, arguments)); } @@ -803,7 +803,7 @@ CallDoubleMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; return bitsToDouble(run(t, callLongMethodV, arguments)); } @@ -839,7 +839,7 @@ CallVoidMethodV(Thread* t, jobject o, jmethodID m, va_list a) { uintptr_t arguments[] = { reinterpret_cast(o), m, - reinterpret_cast(a) }; + reinterpret_cast(VA_LIST(a)) }; run(t, callVoidMethodV, arguments); } @@ -879,7 +879,7 @@ callStaticObjectMethodV(Thread* t, uintptr_t* arguments) jobject JNICALL CallStaticObjectMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return reinterpret_cast(run(t, callStaticObjectMethodV, arguments)); } @@ -910,7 +910,7 @@ callStaticIntMethodV(Thread* t, uintptr_t* arguments) jboolean JNICALL CallStaticBooleanMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments) != 0; } @@ -931,7 +931,7 @@ CallStaticBooleanMethod(Thread* t, jclass c, jmethodID m, ...) jbyte JNICALL CallStaticByteMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } @@ -952,7 +952,7 @@ CallStaticByteMethod(Thread* t, jclass c, jmethodID m, ...) jchar JNICALL CallStaticCharMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } @@ -973,7 +973,7 @@ CallStaticCharMethod(Thread* t, jclass c, jmethodID m, ...) jshort JNICALL CallStaticShortMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } @@ -994,7 +994,7 @@ CallStaticShortMethod(Thread* t, jclass c, jmethodID m, ...) jint JNICALL CallStaticIntMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticIntMethodV, arguments); } @@ -1025,7 +1025,7 @@ callStaticLongMethodV(Thread* t, uintptr_t* arguments) jlong JNICALL CallStaticLongMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return run(t, callStaticLongMethodV, arguments); } @@ -1046,7 +1046,7 @@ CallStaticLongMethod(Thread* t, jclass c, jmethodID m, ...) jfloat JNICALL CallStaticFloatMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return bitsToFloat(run(t, callStaticIntMethodV, arguments)); } @@ -1067,7 +1067,7 @@ CallStaticFloatMethod(Thread* t, jclass c, jmethodID m, ...) jdouble JNICALL CallStaticDoubleMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; return bitsToDouble(run(t, callStaticLongMethodV, arguments)); } @@ -1099,7 +1099,7 @@ callStaticVoidMethodV(Thread* t, uintptr_t* arguments) void JNICALL CallStaticVoidMethodV(Thread* t, jclass, jmethodID m, va_list a) { - uintptr_t arguments[] = { m, reinterpret_cast(a) }; + uintptr_t arguments[] = { m, reinterpret_cast(VA_LIST(a)) }; run(t, callStaticVoidMethodV, arguments); } diff --git a/src/machine.cpp b/src/machine.cpp index 6a93f39fb2..9a8116d165 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1227,7 +1227,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -2056,7 +2056,7 @@ boot(Thread* t) m->processor->boot(t, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); diff --git a/src/machine.h b/src/machine.h index 187dc46e21..f721277b44 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1465,19 +1465,17 @@ class Thread { public: RunCheckpoint(Thread* t): Checkpoint(t), - stack(0), - base(0) + stack(0) { } virtual void unwind() { void* stack = this->stack; this->stack = 0; expect(t->m->system, stack); - vmJump(voidPointer(vmRun_returnAddress), base, stack, t, 0, 0); + vmJump(voidPointer(vmRun_returnAddress), stack, t, 0, 0); } void* stack; - void* base; }; class Runnable: public System::Runnable { diff --git a/src/posix.cpp b/src/posix.cpp index 4439feea01..590d8e65ca 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -815,7 +815,7 @@ class MySystem: public System { } class NullSignalHandler: public SignalHandler { - virtual bool handleSignal(void**, void**, void**, void**) { return false; } + virtual bool handleSignal(void**, void**, void**) { return false; } } nullHandler; SignalHandler* handlers[SignalCount]; @@ -831,12 +831,7 @@ handleSignal(int signal, siginfo_t* info, void* context) { ucontext_t* c = static_cast(context); -#ifndef BASE_REGISTER -# define BASE_REGISTER(x) 0 -#endif - void* ip = reinterpret_cast(IP_REGISTER(c)); - void* base = reinterpret_cast(BASE_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); void* thread = reinterpret_cast(THREAD_REGISTER(c)); @@ -846,7 +841,7 @@ handleSignal(int signal, siginfo_t* info, void* context) case VisitSignal: { index = VisitSignalIndex; - system->threadVisitor->visit(ip, base, stack); + system->threadVisitor->visit(ip, stack); System::Thread* t = system->visitTarget; system->visitTarget = 0; @@ -875,8 +870,7 @@ handleSignal(int signal, siginfo_t* info, void* context) abort(); } - bool jump = system->handlers[index]->handleSignal - (&ip, &base, &stack, &thread); + bool jump = system->handlers[index]->handleSignal(&ip, &stack, &thread); if (jump) { // I'd like to use setcontext here (and get rid of the @@ -890,7 +884,7 @@ handleSignal(int signal, siginfo_t* info, void* context) sigaddset(&set, signal); sigprocmask(SIG_UNBLOCK, &set, 0); - vmJump(ip, base, stack, thread, 0, 0); + vmJump(ip, stack, thread, 0, 0); } } break; diff --git a/src/system.h b/src/system.h index 315f7151d2..8cf08ea88a 100644 --- a/src/system.h +++ b/src/system.h @@ -35,7 +35,7 @@ class System { class ThreadVisitor { public: - virtual void visit(void* ip, void* base, void* stack) = 0; + virtual void visit(void* ip, void* stack) = 0; }; class Runnable { @@ -96,8 +96,7 @@ class System { class SignalHandler { public: - virtual bool handleSignal(void** ip, void** base, void** stack, - void** thread) = 0; + virtual bool handleSignal(void** ip, void** stack, void** thread) = 0; }; class MonitorResource { diff --git a/src/types.def b/src/types.def index 8b8d980ffc..7509c431a9 100644 --- a/src/types.def +++ b/src/types.def @@ -86,6 +86,7 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) + (object frameSizeTable) (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) diff --git a/src/x86.S b/src/x86.S index c7c6e5c504..08e05e4aaf 100644 --- a/src/x86.S +++ b/src/x86.S @@ -25,7 +25,6 @@ #define CHECKPOINT_THREAD 8 #define CHECKPOINT_STACK 48 -#define CHECKPOINT_BASE 56 #ifdef __MINGW32__ .globl GLOBAL(detectFeature) @@ -171,11 +170,10 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): - movq %rdx,%rbp - movq 40(%rsp),%rax - movq 48(%rsp),%rdx - movq %r8,%rsp - movq %r9,%rbx + movq %r9,%rax + movq 40(%rsp),%rdx + movq %rdx,%rsp + movq %r8,%rbx jmp *%rcx #define VMRUN_FRAME_SIZE 80 @@ -198,7 +196,6 @@ GLOBAL(vmRun): movq %rdi,64(%rsp) movq %rsp,CHECKPOINT_STACK(%rcx) - movq %rbp,CHECKPOINT_BASE(%rcx) movq %rcx,%r11 movq CHECKPOINT_THREAD(%rdx),%rcx @@ -353,11 +350,10 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): - movq %rsi,%rbp - movq %rdx,%rsp - movq %rcx,%rbx - movq %r8,%rax - movq %r9,%rdx + movq %rsi,%rsp + movq %rdx,%rbx + movq %rcx,%rax + movq %r8,%rdx jmp *%rdi #define VMRUN_FRAME_SIZE 64 @@ -378,7 +374,6 @@ GLOBAL(vmRun): movq %r15,48(%rsp) movq %rsp,CHECKPOINT_STACK(%rdx) - movq %rbp,CHECKPOINT_BASE(%rdx) movq %rdi,%r11 movq CHECKPOINT_THREAD(%rdx),%rdi @@ -513,11 +508,10 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): movl 4(%esp),%esi - movl 8(%esp),%ebp - movl 16(%esp),%ebx - movl 20(%esp),%eax - movl 24(%esp),%edx - movl 12(%esp),%esp + movl 12(%esp),%ebx + movl 16(%esp),%eax + movl 20(%esp),%edx + movl 8(%esp),%esp jmp *%esi #define VMRUN_FRAME_SIZE 32 @@ -543,7 +537,6 @@ GLOBAL(vmRun): movl %eax,0(%esp) movl %esp,CHECKPOINT_STACK(%ecx) - movl %ebp,CHECKPOINT_BASE(%ecx) call *8(%ebp) diff --git a/src/x86.cpp b/src/x86.cpp index 4c11e8adfe..676c011da8 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -65,13 +65,15 @@ const unsigned GeneralRegisterMask const unsigned FloatRegisterMask = BytesPerWord == 4 ? 0x00ff0000 : 0xffff0000; -const unsigned FrameHeaderSize = 2; +const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1); const int LongJumpRegister = r10; const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; +const int FrameSizePoison = -2147483647; + bool isInt8(intptr_t v) { @@ -86,16 +88,26 @@ isInt32(intptr_t v) class Task; class AlignmentPadding; +class MyFrameSizeEvent; unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, AlignmentPadding* limit); +class Context; +class MyBlock; + +void +appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change); + +ResolvedPromise* + resolved(Context* c, int64_t value); + class MyBlock: public Assembler::Block { public: MyBlock(unsigned offset): - next(0), firstPadding(0), lastPadding(0), offset(offset), start(~0), - size(0) + next(0), firstPadding(0), lastPadding(0), firstFrameSizeEvent(0), + lastFrameSizeEvent(0), offset(offset), start(~0), size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { @@ -108,13 +120,13 @@ class MyBlock: public Assembler::Block { MyBlock* next; AlignmentPadding* firstPadding; AlignmentPadding* lastPadding; + MyFrameSizeEvent* firstFrameSizeEvent; + MyFrameSizeEvent* lastFrameSizeEvent; unsigned offset; unsigned start; unsigned size; }; -class Context; - typedef void (*OperationType)(Context*); typedef void (*UnaryOperationType)(Context*, unsigned, Assembler::Operand*); @@ -152,7 +164,8 @@ class Context { Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), ac(ac) + lastBlock(firstBlock), firstFrameSizeEvent(0), lastFrameSizeEvent(0), + ac(ac), frameSizeEventCount(0) { } System* s; @@ -163,7 +176,10 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; + MyFrameSizeEvent* firstFrameSizeEvent; + MyFrameSizeEvent* lastFrameSizeEvent; ArchitectureContext* ac; + unsigned frameSizeEventCount; }; void NO_RETURN @@ -450,6 +466,54 @@ padding(AlignmentPadding* p, unsigned start, unsigned offset, return padding; } +class MyFrameSizeEvent: public Assembler::FrameSizeEvent { + public: + MyFrameSizeEvent(Context* c, Promise* offset, int change): + c(c), next_(0), offset_(offset), change_(change) + { } + + virtual unsigned offset() { + return offset_->value(); + } + + virtual int change() { + expect(c, change_ != FrameSizePoison); + + return change_; + } + + virtual Assembler::FrameSizeEvent* next() { + return next_; + } + + Context* c; + MyFrameSizeEvent* next_; + Promise* offset_; + int change_; +}; + +void +appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change) +{ + MyFrameSizeEvent* e = new (c->zone->allocate(sizeof(MyFrameSizeEvent))) + MyFrameSizeEvent(c, offset, change); + + if (b->firstFrameSizeEvent) { + b->lastFrameSizeEvent->next_ = e; + } else { + b->firstFrameSizeEvent = e; + } + b->lastFrameSizeEvent = e; + + ++ c->frameSizeEventCount; +} + +void +appendFrameSizeEvent(Context* c, int change) +{ + appendFrameSizeEvent(c, c->lastBlock, offset(c), change); +} + extern "C" bool detectFeature(unsigned ecx, unsigned edx); @@ -881,22 +945,6 @@ popR(Context* c, unsigned size, Assembler::Register* a) } } -void -popM(Context* c, unsigned size, Assembler::Memory* a) -{ - if (BytesPerWord == 4 and size == 8) { - Assembler::Memory ah(a->base, a->offset + 4, a->index, a->scale); - - popM(c, 4, a); - popM(c, 4, &ah); - } else { - assert(c, BytesPerWord == 4 or size == 8); - - opcode(c, 0x8f); - modrmSibImm(c, 0, a->scale, a->index, a->base, a->offset); - } -} - void addCarryCR(Context* c, unsigned size, Assembler::Constant* a, Assembler::Register* b); @@ -2701,6 +2749,8 @@ class MyArchitecture: public Assembler::Architecture { virtual bool reserved(int register_) { switch (register_) { case rbp: + return UseFramePointer; + case rsp: case rbx: return true; @@ -2724,6 +2774,10 @@ class MyArchitecture: public Assembler::Architecture { return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); } + virtual bool argumentAlignment() { + return false; + } + virtual unsigned argumentRegisterCount() { #ifdef PLATFORM_WINDOWS if (BytesPerWord == 8) return 4; else @@ -2893,13 +2947,6 @@ class MyArchitecture: public Assembler::Architecture { return -1; } - virtual void nextFrame(void** stack, void** base) { - assert(&c, *static_cast(*base) != *base); - - *stack = static_cast(*base) + 1; - *base = *static_cast(*base); - } - virtual void plan (UnaryOperation, unsigned, uint8_t* aTypeMask, uint64_t* aRegisterMask, @@ -3288,16 +3335,11 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned baseOffset) { + virtual void saveFrame(unsigned stackOffset) { Register stack(rsp); Memory stackDst(rbx, stackOffset); apply(Move, BytesPerWord, RegisterOperand, &stack, BytesPerWord, MemoryOperand, &stackDst); - - Register base(rbp); - Memory baseDst(rbx, baseOffset); - apply(Move, BytesPerWord, RegisterOperand, &base, - BytesPerWord, MemoryOperand, &baseDst); } virtual void pushFrame(unsigned argumentCount, ...) { @@ -3347,37 +3389,62 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register base(rbp); - pushR(&c, BytesPerWord, &base); - Register stack(rsp); - apply(Move, BytesPerWord, RegisterOperand, &stack, - BytesPerWord, RegisterOperand, &base); + + if (UseFramePointer) { + Register base(rbp); + pushR(&c, BytesPerWord, &base); + + apply(Move, BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &base); + + appendFrameSizeEvent(&c, 1); + } Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); + + appendFrameSizeEvent(&c, footprint); } - virtual void adjustFrame(unsigned footprint) { + virtual void adjustFrame(unsigned difference) { + appendFrameSizeEvent(&c, - difference); + Register stack(rsp); - Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); - apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, + Constant differenceConstant(resolved(&c, difference * BytesPerWord)); + apply(Subtract, BytesPerWord, ConstantOperand, &differenceConstant, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); + + appendFrameSizeEvent(&c, difference); } - virtual void popFrame() { - Register base(rbp); - Register stack(rsp); - apply(Move, BytesPerWord, RegisterOperand, &base, - BytesPerWord, RegisterOperand, &stack); + virtual void popFrame(unsigned frameFootprint) { + if (UseFramePointer) { + Register base(rbp); + Register stack(rsp); + apply(Move, BytesPerWord, RegisterOperand, &base, + BytesPerWord, RegisterOperand, &stack); - popR(&c, BytesPerWord, &base); + appendFrameSizeEvent(&c, - frameFootprint); + + popR(&c, BytesPerWord, &base); + + appendFrameSizeEvent(&c, - 1); + } else { + Register stack(rsp); + Constant footprint(resolved(&c, frameFootprint * BytesPerWord)); + apply(Add, BytesPerWord, ConstantOperand, &footprint, + BytesPerWord, RegisterOperand, &stack, + BytesPerWord, RegisterOperand, &stack); + + appendFrameSizeEvent(&c, - frameFootprint); + } } - virtual void popFrameForTailCall(unsigned footprint, + virtual void popFrameForTailCall(unsigned frameFootprint, int offset, int returnAddressSurrogate, int framePointerSurrogate) @@ -3386,22 +3453,27 @@ class MyAssembler: public Assembler { if (offset) { Register tmp(c.client->acquireTemporary()); - Memory returnAddressSrc(rsp, (footprint + 1) * BytesPerWord); + Memory returnAddressSrc(rsp, (frameFootprint + 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); - Memory returnAddressDst(rsp, (footprint - offset + 1) * BytesPerWord); + Memory returnAddressDst + (rsp, (frameFootprint - offset + 1) * BytesPerWord); moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); c.client->releaseTemporary(tmp.low); - Memory baseSrc(rsp, footprint * BytesPerWord); - Register base(rbp); - moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + if (UseFramePointer) { + Memory baseSrc(rsp, frameFootprint * BytesPerWord); + Register base(rbp); + moveMR(&c, BytesPerWord, &baseSrc, BytesPerWord, &base); + } Register stack(rsp); - Constant footprintConstant - (resolved(&c, (footprint - offset + 1) * BytesPerWord)); - addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); + Constant footprint + (resolved(&c, (frameFootprint - offset + 1) * BytesPerWord)); + addCR(&c, BytesPerWord, &footprint, BytesPerWord, &stack); + + appendFrameSizeEvent(&c, - (frameFootprint - offset + 1)); if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); @@ -3419,15 +3491,17 @@ class MyAssembler: public Assembler { moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); } } else { - popFrame(); + popFrame(frameFootprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); @@ -3442,23 +3516,36 @@ class MyAssembler: public Assembler { * BytesPerWord)); addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack); + appendFrameSizeEvent(&c, - (argumentFootprint - StackAlignmentInWords)); + jumpR(&c, BytesPerWord, &returnAddress); } else { return_(&c); } + + // todo: this is not necessary if there are no instructions to + // follow: + appendFrameSizeEvent(&c, frameFootprint); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); + popFrame(frameFootprint); Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); + appendFrameSizeEvent(&c, -1); + Register stack(rsp); Memory stackSrc(rbx, stackOffsetFromThread); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); + // we can't statically determine the frame size at this point, so + // we poison any attempt to query for it: + appendFrameSizeEvent(&c, FrameSizePoison); + jumpR(&c, BytesPerWord, &returnAddress); } @@ -3507,6 +3594,15 @@ class MyAssembler: public Assembler { c.result = dst; for (MyBlock* b = c.firstBlock; b; b = b->next) { + if (b->firstFrameSizeEvent) { + if (c.firstFrameSizeEvent) { + c.lastFrameSizeEvent->next_ = b->firstFrameSizeEvent; + } else { + c.firstFrameSizeEvent = b->firstFrameSizeEvent; + } + c.lastFrameSizeEvent = b->lastFrameSizeEvent; + } + unsigned index = 0; unsigned padding = 0; for (AlignmentPadding* p = b->firstPadding; p; p = p->next) { @@ -3560,6 +3656,14 @@ class MyAssembler: public Assembler { return c.code.length(); } + virtual unsigned frameSizeEventCount() { + return c.frameSizeEventCount; + } + + virtual FrameSizeEvent* firstFrameSizeEvent() { + return c.firstFrameSizeEvent; + } + virtual void dispose() { c.code.dispose(); } diff --git a/src/x86.h b/src/x86.h index a125e4425c..3073d1f46c 100644 --- a/src/x86.h +++ b/src/x86.h @@ -22,6 +22,8 @@ # undef interface #endif +#define VA_LIST(x) x + #ifdef ARCH_x86_32 # ifdef __APPLE__ From c855224d141799959540a8d9e3f36d9269ddff1a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 17 Jan 2011 09:36:03 -0700 Subject: [PATCH 193/274] fix VM abort when ClassLoader.defineClass is used in bootimage build When loading a class which extends another class that contained a field of primitive array type using defineClass in a bootimage=true build, the VM was unable to find the primitive array class, and makeArrayClass refused to create one since it should already have existed. The problem was that the bootimage=true build uses an empty Machine::BootstrapClassMap, and resolveArrayClass expected to find the primitive array classes there. The fix is to check the Machine::BootLoader map if we can't find it in Machine::BootstrapClassMap. --- src/machine.cpp | 11 ++++++++++- test/DefineClass.java | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/machine.cpp b/src/machine.cpp index 1fade5edbe..14ad1632c7 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1835,7 +1835,16 @@ resolveArrayClass(Thread* t, object loader, object spec, bool throw_) return c; } else { - return makeArrayClass(t, loader, spec, throw_); + PROTECT(t, loader); + PROTECT(t, spec); + + c = findLoadedClass(t, root(t, Machine::BootLoader), spec); + + if (c) { + return c; + } else { + return makeArrayClass(t, loader, spec, throw_); + } } } diff --git a/test/DefineClass.java b/test/DefineClass.java index 0b72cd5b95..ad98028b91 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -72,6 +72,7 @@ public class DefineClass { public abstract static class Base { public int foo; + public int[] array; public void bar() { } From 4a9ff5506017e99029f25c114f30b22b07a19737 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 17 Jan 2011 09:48:34 -0700 Subject: [PATCH 194/274] File.length should return 0 for non-existent files --- classpath/java-io.cpp | 2 +- test/FileOutput.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 740d5199c6..3c4ec00544 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -331,7 +331,7 @@ Java_java_io_File_length(JNIEnv* e, jclass, jstring path) } } - return -1; + return 0; } extern "C" JNIEXPORT void JNICALL diff --git a/test/FileOutput.java b/test/FileOutput.java index fa2cc0965e..6fffc0f8a7 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -4,6 +4,10 @@ import java.io.File; import java.io.IOException; public class FileOutput { + private static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + private static void test(boolean appendFirst) throws IOException { try { FileOutputStream f = new FileOutputStream("test.txt", appendFirst); @@ -33,6 +37,8 @@ public class FileOutput { } public static void main(String[] args) throws IOException { + expect(new File("nonexistent-file").length() == 0); + test(false); test(true); } From b4941cddbea9cca8e7763d04ec06fb7a46456834 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 17 Jan 2011 10:33:43 -0700 Subject: [PATCH 195/274] close FileInputStream before deleting file in FileOutput test Otherwise, Windows won't let us delete it. --- test/FileOutput.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/FileOutput.java b/test/FileOutput.java index 6fffc0f8a7..539b73fc59 100644 --- a/test/FileOutput.java +++ b/test/FileOutput.java @@ -25,6 +25,7 @@ public class FileOutput { while ((c = in.read(buffer, offset, buffer.length - offset)) != -1) { offset += c; } + in.close(); if (! "Hello world!\nHello world again!".equals (new String(buffer, 0, offset))) @@ -32,7 +33,7 @@ public class FileOutput { throw new RuntimeException(); } } finally { - new File("test.txt").delete(); + expect(new File("test.txt").delete()); } } From 475b286c7f6c80078b48a403036e35f4669b8fa7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 17 Jan 2011 20:23:01 -0700 Subject: [PATCH 196/274] preserve ClassLoader.loadClass from obfuscation/shrinking This method is called by name in the VM. --- vm.pro | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vm.pro b/vm.pro index edfd2e1679..1dccb36b6a 100644 --- a/vm.pro +++ b/vm.pro @@ -116,3 +116,9 @@ -keepclassmembers class java.lang.Object { protected java.lang.Object clone(); } + +# called by name in the VM: + +-keepclassmembers class java.lang.ClassLoader { + public java.lang.Class loadClass(java.lang.String); + } From c02bfc57a5c853af88a71eb6e4ac691f824092cc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 18 Jan 2011 08:35:52 -0700 Subject: [PATCH 197/274] resolve primitive array classes when generating boot image This is necessary to accomodate classes loaded at runtime which refer to primitive array types. Otherwise, they won't be included unless classes in the bootimage refer to them. --- src/bootimage.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 252028dd79..13907b6b01 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -411,6 +411,41 @@ writeBootImage(Thread* t, FILE* out, BootImage* image, uint8_t* code, set(t, type(t, Machine::JdoubleType), ClassName, name); } + // resolve primitive array classes in case they are needed at + // runtime: + { resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[B"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[Z"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[S"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[C"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[I"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[J"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[F"), true); + if (t->exception) return; + + resolveSystemClass + (t, root(t, Machine::BootLoader), makeByteArray(t, "[D"), true); + if (t->exception) return; + } + collect(t, Heap::MajorCollection); uintptr_t* heap = static_cast From 9c36105b8fa06543897acd8d86de0737149d519a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 19 Jan 2011 16:00:18 -0700 Subject: [PATCH 198/274] fix misleading pathnames in bootimage build instructions --- readme.txt | 6 +++--- test/DefineClass.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.txt b/readme.txt index f8b7a51e06..32209046f7 100644 --- a/readme.txt +++ b/readme.txt @@ -462,7 +462,7 @@ Step 2: Create a stage1 directory and extract the contents of the class library jar into it. $ mkdir stage1 - $ (cd stage1 && jar xf ../../build/${platform}-${arch}/classpath.jar) + $ (cd stage1 && jar xf ../../build/linux-i386-bootimage/classpath.jar) Step 3: Build the Java code and add it to stage1. @@ -498,10 +498,10 @@ Step 6: Build the boot image. Step 7: Make an object file out of the boot image. - $ ../build/${platform}-${arch}/binaryToObject \ + $ ../build/linux-i386-bootimage/binaryToObject \ bootimage.bin bootimage-bin.o \ _binary_bootimage_bin_start _binary_bootimage_bin_end \ - ${platform} ${arch} 8 writable executable + linux i386 8 writable executable Step 8: Write a driver which starts the VM and runs the desired main method. Note the bootimageBin function, which will be called by the diff --git a/test/DefineClass.java b/test/DefineClass.java index ad98028b91..4e0d8faef7 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -50,7 +50,7 @@ public class DefineClass { } public static void main(String[] args) throws Exception { - testStatic(); + //testStatic(); testDerived(); } From 51c56c1b3c901354a1ae8fad290b00a7436f41c5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 08:26:56 -0700 Subject: [PATCH 199/274] add PrintStream.print[ln] overloads for primitives and char arrays --- classpath/java/io/PrintStream.java | 48 ++++++++++++++++++++++++++++++ test/Misc.java | 8 +++++ 2 files changed, 56 insertions(+) diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index 520b676a29..a720fac6a0 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -39,10 +39,34 @@ public class PrintStream extends OutputStream { print(String.valueOf(o)); } + public void print(boolean v) { + print(String.valueOf(v)); + } + public void print(char c) { print(String.valueOf(c)); } + public void print(int v) { + print(String.valueOf(v)); + } + + public void print(long v) { + print(String.valueOf(v)); + } + + public void print(float v) { + print(String.valueOf(v)); + } + + public void print(double v) { + print(String.valueOf(v)); + } + + public void print(char[] s) { + print(String.valueOf(s)); + } + public synchronized void println(String s) { try { out.write(s.getBytes()); @@ -62,9 +86,33 @@ public class PrintStream extends OutputStream { println(String.valueOf(o)); } + public void println(boolean v) { + println(String.valueOf(v)); + } + public void println(char c) { println(String.valueOf(c)); } + + public void println(int v) { + println(String.valueOf(v)); + } + + public void println(long v) { + println(String.valueOf(v)); + } + + public void println(float v) { + println(String.valueOf(v)); + } + + public void println(double v) { + println(String.valueOf(v)); + } + + public void println(char[] s) { + println(String.valueOf(s)); + } public void write(int c) throws IOException { out.write(c); diff --git a/test/Misc.java b/test/Misc.java index 8a501392c7..7ff2f25378 100644 --- a/test/Misc.java +++ b/test/Misc.java @@ -227,5 +227,13 @@ public class Misc { } System.out.println(new java.util.Date().toString()); + + System.out.println('x'); + System.out.println(true); + System.out.println(42); + System.out.println(123456789012345L); + System.out.println(75.62); + System.out.println(75.62d); + System.out.println(new char[] { 'h', 'i' }); } } From 2dcc1d525aa1d7dbce05d1322cfc2736bda1198f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 08:50:53 -0700 Subject: [PATCH 200/274] add note about slower floating point code for 32-bit x86 bootimage build --- readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 32209046f7..6bfc750124 100644 --- a/readme.txt +++ b/readme.txt @@ -442,7 +442,10 @@ For boot image builds: space in the executable than the equivalent class files. In practice, this can make the executable 30-50% larger. Also, AOT compilation does not yet yield significantly faster or smaller code - than JIT compilation. + than JIT compilation. Finally, floating point code may be slower + on 32-bit x86 since the compiler cannot assume SSE2 support will be + available at runtime, and the x87 FPU is not supported except via + out-of-line helper functions. Note you can use ProGuard without using a boot image and vice-versa, as desired. From b57e734ceb051e45c373f7681c437f796d777a41 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 09:33:50 -0700 Subject: [PATCH 201/274] implement Character.forDigit --- classpath/java/lang/Character.java | 9 +++++++++ test/Strings.java | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/classpath/java/lang/Character.java b/classpath/java/lang/Character.java index f696037561..88025280e8 100644 --- a/classpath/java/lang/Character.java +++ b/classpath/java/lang/Character.java @@ -109,6 +109,15 @@ public final class Character implements Comparable { } } + public static char forDigit(int digit, int radix) { + if (MIN_RADIX <= radix && radix <= MAX_RADIX) { + if (0 <= digit && digit < radix) { + return (char) (digit < 10 ? digit + '0' : digit + 'a' - 10); + } + } + return 0; + } + public static boolean isLetter(int c) { return canCastToChar(c) && isLetter((char) c); } diff --git a/test/Strings.java b/test/Strings.java index 6b993bcb4f..d98c1f13f9 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -71,5 +71,11 @@ public class Strings { sb.append('$'); sb.append('2'); expect(sb.substring(1).equals("2")); + + expect(Character.forDigit(Character.digit('0', 10), 10) == '0'); + expect(Character.forDigit(Character.digit('9', 10), 10) == '9'); + expect(Character.forDigit(Character.digit('b', 16), 16) == 'b'); + expect(Character.forDigit(Character.digit('f', 16), 16) == 'f'); + expect(Character.forDigit(Character.digit('z', 36), 36) == 'z'); } } From 3a2a46499eb4af32052d75a6b33e3ef9660ae3a9 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 09:34:46 -0700 Subject: [PATCH 202/274] add Reader.mark/markSupported/reset --- classpath/java/io/Reader.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/classpath/java/io/Reader.java b/classpath/java/io/Reader.java index acbf42ffd2..a09c8a24e9 100644 --- a/classpath/java/io/Reader.java +++ b/classpath/java/io/Reader.java @@ -28,5 +28,17 @@ public abstract class Reader { public abstract int read(char[] buffer, int offset, int length) throws IOException; + public boolean markSupported() { + return false; + } + + public void mark(int readAheadLimit) throws IOException { + throw new IOException("mark not supported"); + } + + public void reset() throws IOException { + throw new IOException("reset not supported"); + } + public abstract void close() throws IOException; } From 0ca7ed8c67421fb8b45ed86ae6c2d47f3a8b498a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 09:35:34 -0700 Subject: [PATCH 203/274] add Package.getName --- classpath/java/lang/Package.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/classpath/java/lang/Package.java b/classpath/java/lang/Package.java index 507a240a3e..5cd9b9547e 100644 --- a/classpath/java/lang/Package.java +++ b/classpath/java/lang/Package.java @@ -43,4 +43,8 @@ public class Package { this.sealed = sealed; this.loader = loader; } + + public String getName() { + return name; + } } From 3aff7dc861de624dde48bbec953f79b64b5039f0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 20 Jan 2011 09:39:16 -0700 Subject: [PATCH 204/274] add TreeSet(Collection) constructor --- classpath/java/util/TreeSet.java | 8 ++++++++ test/Tree.java | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 5a1d4a8c47..16f291a134 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -33,6 +33,14 @@ public class TreeSet extends AbstractSet implements Collection { } }); } + + public TreeSet(Collection collection) { + this(); + + for (T item: collection) { + add(item); + } + } public Iterator iterator() { return new MyIterator(set.first()); diff --git a/test/Tree.java b/test/Tree.java index ded42a27ea..12f1e8fa08 100644 --- a/test/Tree.java +++ b/test/Tree.java @@ -1,6 +1,8 @@ import java.util.Comparator; import java.util.TreeSet; import java.util.TreeMap; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Iterator; @@ -87,5 +89,13 @@ public class Tree { map.put("y", "Y"); isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); + + Collection list = new ArrayList(); + list.add(7); + list.add(2); + list.add(9); + list.add(2); + + isEqual(printList(new TreeSet(list)), "2, 7, 9"); } } From 0cc615693258dd688abd5110512de2d551c66373 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 21 Jan 2011 16:11:36 -0700 Subject: [PATCH 205/274] remove redundant code from DefineClass and Zip tests --- test/DefineClass.java | 1 - test/Zip.java | 1 - 2 files changed, 2 deletions(-) diff --git a/test/DefineClass.java b/test/DefineClass.java index 4e0d8faef7..ea3b6362ae 100644 --- a/test/DefineClass.java +++ b/test/DefineClass.java @@ -4,7 +4,6 @@ import java.io.FileInputStream; public class DefineClass { private static File findClass(String name, File directory) { - File[] files = directory.listFiles(); for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().equals(name + ".class")) { diff --git a/test/Zip.java b/test/Zip.java index 8862e767c7..9b34444023 100644 --- a/test/Zip.java +++ b/test/Zip.java @@ -7,7 +7,6 @@ import java.util.zip.ZipEntry; public class Zip { private static String findJar(File directory) { - File[] files = directory.listFiles(); for (File file: directory.listFiles()) { if (file.isFile()) { if (file.getName().endsWith(".jar")) { From 220f7760b7c41ed88c7960fc70eedd777fb3501e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 21 Jan 2011 16:14:21 -0700 Subject: [PATCH 206/274] fix MSVC build regressions --- classpath/java-io.cpp | 6 ++++-- makefile | 3 ++- readme.txt | 2 +- src/finder.cpp | 2 +- src/main.cpp | 8 +++++++- src/process.cpp | 4 ++-- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 3c4ec00544..abc7684634 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -37,10 +37,12 @@ # define OPEN_MASK O_BINARY # ifdef _MSC_VER -# define S_ISREG(x) ((x) | _S_IFREG) -# define S_ISDIR(x) ((x) | _S_IFDIR) +# define S_ISREG(x) ((x) & _S_IFREG) +# define S_ISDIR(x) ((x) & _S_IFDIR) # define S_IRUSR _S_IREAD # define S_IWUSR _S_IWRITE +# define W_OK 2 +# define R_OK 4 # else # define OPEN _wopen # define CREAT _wcreat diff --git a/makefile b/makefile index ef5fb8b04e..5b34b5051b 100644 --- a/makefile +++ b/makefile @@ -353,7 +353,8 @@ ifdef msvc ld = "$(msvc)/BIN/link.exe" mt = "mt.exe" cflags = -nologo -DAVIAN_VERSION=\"$(version)\" -D_JNI_IMPLEMENTATION_ \ - -DUSE_ATOMIC_OPERATIONS \ + -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ + -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" \ -Fd$(build)/$(name).pdb -I"$(zlib)/include" -I$(src) -I"$(build)" \ -I"$(windows-java-home)/include" -I"$(windows-java-home)/include/win32" shared = -dll diff --git a/readme.txt b/readme.txt index 6bfc750124..0f0ad44bb7 100644 --- a/readme.txt +++ b/readme.txt @@ -187,7 +187,7 @@ C++ portions of the VM, while the assembly code and helper tools are built using GCC. The MSVC build has been tested with Visual Studio Express Edition -versions 8 and 9. Other versions may also work. +versions 8, 9, and 10. Other versions may also work. To build with MSVC, install Cygwin as described above and set the following environment variables: diff --git a/src/finder.cpp b/src/finder.cpp index 543c45e312..b0e25ef82a 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -458,7 +458,7 @@ class JarIndex { RUNTIME_ARRAY_BODY(n)[length] = '/'; RUNTIME_ARRAY_BODY(n)[length + 1] = 0; - node = findNode(n); + node = findNode(RUNTIME_ARRAY_BODY(n)); if (node) { return System::TypeDirectory; } else { diff --git a/src/main.cpp b/src/main.cpp index 8cdb435dd0..9996e6078d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,13 @@ extern "C" void __cxa_pure_virtual(void) { abort(); } // we link against a System implmentation, which requires this at link // time, but it should not be used at runtime: extern "C" uint64_t -vmNativeCall(void*, void*, unsigned, unsigned) { abort(); } +vmNativeCall(void*, void*, unsigned, unsigned) +{ + abort(); + // abort is not declared __declspec(noreturn) on MSVC, so we have to + // pretend it might return to make the compiler happy: + return 0; +} #endif // BOOT_LIBRARY diff --git a/src/process.cpp b/src/process.cpp index 00edbe66b7..4c06794461 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -206,12 +206,12 @@ resolveNativeMethod(Thread* t, object method, const char* prefix, object resolveNativeMethod(Thread* t, object method) { - void* p = ::resolveNativeMethod(t, method, "Avian_", 6, 3); + void* p = resolveNativeMethod(t, method, "Avian_", 6, 3); if (p) { return makeNative(t, p, true); } - p = ::resolveNativeMethod(t, method, "Java_", 5, -1); + p = resolveNativeMethod(t, method, "Java_", 5, -1); if (p) { return makeNative(t, p, false); } From 966650f105c64b93a7fcdda2c6392beefcbef2f0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 25 Jan 2011 17:13:59 -0700 Subject: [PATCH 207/274] make StackOverflow test useful in tails=true build --- test/StackOverflow.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/StackOverflow.java b/test/StackOverflow.java index 0a26217e65..c613fe5616 100644 --- a/test/StackOverflow.java +++ b/test/StackOverflow.java @@ -1,14 +1,14 @@ public class StackOverflow { - private static void test1() { - test1(); + private static int test1() { + return test1() + 1; } - private static void test2() { - test3(); + private static int test2() { + return test3() + 1; } - private static void test3() { - test2(); + private static int test3() { + return test2() + 1; } public static void main(String[] args) { From c1a0d8b6fcceebf6193546db288ecb704d875aaa Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 25 Jan 2011 17:22:43 -0700 Subject: [PATCH 208/274] more work on frame-pointer-less unwinding This fixes the tails=true build (at least for x86_64) and eliminates the need for a frame table in the tails=false build. In the tails=true build, we still need a frame table on x86(_64) to help determine whether we've caught a thread executing code to do a tail call or pop arguments off the stack. However, I've not yet written the code to actually use this table, and it is only needed to handle asynchronous unwinds via Thread.getStackTrace. --- src/arm.cpp | 155 +++++++++++++++++++------------- src/assembler.h | 13 +-- src/compile-x86.S | 4 +- src/compile.cpp | 146 +++++++++++++++--------------- src/posix.cpp | 3 +- src/system.h | 2 +- src/types.def | 2 +- src/x86.cpp | 222 +++++++++++++++++++++++++++++----------------- src/x86.h | 12 +-- 9 files changed, 327 insertions(+), 232 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 14528b5c59..768e1af9a7 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -164,13 +164,13 @@ inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } inline bool isOfWidth(long long i, int size) { return static_cast(i) >> size == 0; } inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } -const unsigned FrameFooterSize = 2; -const unsigned FrameHeaderSize = 0; +const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1); const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int ThreadRegister = 8; +const int FrameRegister = 12; const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; @@ -1701,6 +1701,9 @@ class MyArchitecture: public Assembler::Architecture { virtual bool reserved(int register_) { switch (register_) { + case FrameRegister: + return UseFramePointer; + case LinkRegister: case StackRegister: case ThreadRegister: @@ -1781,8 +1784,8 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned alignFrameSize(unsigned sizeInWords) { - const unsigned alignment = StackAlignmentInBytes / BytesPerWord; - return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); + return pad(sizeInWords + FrameHeaderSize, StackAlignmentInWords) + - FrameHeaderSize; } virtual void* frameIp(void* stack) { @@ -1798,15 +1801,15 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned frameFooterSize() { - return FrameFooterSize; + return 0; } virtual int returnAddressOffset() { - return 1; + return -1; } virtual int framePointerOffset() { - return 0; + return -2; } virtual void nextFrame(void** stack, void**) { @@ -2006,11 +2009,14 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned) { + virtual void saveFrame(unsigned stackOffset) { + appendFrameSizeEvent(&c, FrameSizePoison); + + // ??? Register returnAddress(LinkRegister); - Memory returnAddressDst - (StackRegister, arch_->returnAddressOffset() * BytesPerWord); - moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); + Memory returnAddressDst(StackRegister, - BytesPerWord); + moveAndUpdateRM(&c, BytesPerWord, &returnAddress, BytesPerWord, + &returnAddressDst); Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); @@ -2059,33 +2065,53 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register returnAddress(LinkRegister); + Register stack(StackRegister); + Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); + subCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack, + BytesPerWord, &stack); - Memory returnAddressDst(StackRegister, arch_->returnAddressOffset() * BytesPerWord); + appendFrameSizeEvent(&c, footprint); + + Register returnAddress(LinkRegister); + Memory returnAddressDst(StackRegister, (footprint - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); - Register stack(StackRegister); - Memory stackDst(StackRegister, -footprint * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); + if (UseFramePointer) { + Register frame(FrameRegister); + Memory frameDst(StackRegister, (footprint - 2) * BytesPerWord); + moveRM(&c, BytesPerWord, &frame, BytesPerWord, &frameDst); + } } - virtual void adjustFrame(unsigned footprint) { - Register nextStack(5); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); + virtual void adjustFrame(unsigned difference) { + appendFrameSizeEvent(&c, - difference); - Memory stackDst(StackRegister, -footprint * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst); + Register stack(StackRegister); + Constant differenceConstant(resolved(&c, difference * BytesPerWord)); + subCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack, + BytesPerWord, &stack); + + appendFrameSizeEvent(&c, difference); } - virtual void popFrame() { - Register stack(StackRegister); - Memory stackSrc(StackRegister, arch_->framePointerOffset() * BytesPerWord); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); + virtual void popFrame(unsigned frameFootprint) { + if (UseFramePointer) { + Register frame(FrameRegister); + Memory frameSrc(StackRegister, (frameFootprint - 1) * BytesPerWord); + moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame); + } Register returnAddress(LinkRegister); - Memory returnAddressSrc(StackRegister, arch_->returnAddressOffset() * BytesPerWord); + Memory returnAddressSrc + (StackRegister, (frameFootprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); + + Register stack(StackRegister); + Constant differenceConstant(resolved(&c, frameFootprint * BytesPerWord)); + addCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack, + BytesPerWord, &stack); + + appendFrameSizeEvent(&c, - frameFootprint); } virtual void popFrameForTailCall(unsigned footprint, @@ -2095,80 +2121,85 @@ class MyAssembler: public Assembler { { if (TailCalls) { if (offset) { + if (UseFramePointer) { + Register frame(FrameRegister); + Memory frameSrc(StackRegister, (footprint - 1) * BytesPerWord); + moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame); + } + Register link(LinkRegister); Memory returnAddressSrc - (StackRegister, BytesPerWord + (footprint * BytesPerWord)); + (StackRegister, (footprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link); - Register tmp(c.client->acquireTemporary()); - Memory stackSrc(StackRegister, footprint * BytesPerWord); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + Register stack(StackRegister); + Constant footprintConstant + (resolved(&c, (footprint - offset + 1) * BytesPerWord)); + addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); - Memory stackDst(StackRegister, (footprint - offset) * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); - - c.client->releaseTemporary(tmp.low); + appendFrameSizeEvent(&c, - (frameFootprint - offset + 1)); if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); Register ras(returnAddressSurrogate); - Memory dst(StackRegister, BytesPerWord + (offset * BytesPerWord)); + Memory dst(StackRegister, (offset - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } if (framePointerSurrogate != NoRegister) { assert(&c, offset > 0); - Register fps(framePointerSurrogate); - Memory dst(StackRegister, offset * BytesPerWord); - moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); + Register las(framePointerSurrogate); + Memory dst(StackRegister, (offset - 2) * BytesPerWord); + moveRM(&c, BytesPerWord, &las, BytesPerWord, &dst); } } else { - popFrame(); + popFrame(footprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); + unsigned offset; if (TailCalls and argumentFootprint > StackAlignmentInWords) { - Register tmp(5); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp); + offset = argumentFootprint - StackAlignmentInWords; - Memory stackDst(StackRegister, - (argumentFootprint - StackAlignmentInWords) - * BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &tmp, BytesPerWord, &stackDst); + Register stack(StackRegister); + Constant adjustment(resolved(&c, offset * BytesPerWord)); + addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack); + + appendFrameSizeEvent(&c, - offset); + } else { + offset = 0; } return_(&c); + + // todo: this is not necessary if there are no instructions to + // follow: + appendFrameSizeEvent(&c, frameFootprint + offset); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); + appendFrameSizeEvent(&c, FrameSizePoison); - Register tmp1(6); - Memory stackSrc(StackRegister, 0); - moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &tmp1); - - Register tmp2(5); - Memory newStackSrc(ThreadRegister, stackOffsetFromThread); - moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &tmp2); + popFrame(frameFootprint); Register stack(StackRegister); - subR(&c, BytesPerWord, &stack, &tmp2, &tmp2); - - Memory stackDst(StackRegister, 0, tmp2.low); - moveAndUpdateRM(&c, BytesPerWord, &tmp1, BytesPerWord, &stackDst); + Memory newStackSrc(ThreadRegister, stackOffsetFromThread); + moveMR(&c, BytesPerWord, &newStackSrc, BytesPerWord, &stack); return_(&c); } diff --git a/src/assembler.h b/src/assembler.h index 0cdc788ad1..7edc0b9001 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -304,11 +304,10 @@ class Assembler { virtual unsigned resolve(unsigned start, Block* next) = 0; }; - class FrameSizeEvent { + class FrameEvent { public: virtual unsigned offset() = 0; - virtual int change() = 0; - virtual FrameSizeEvent* next() = 0; + virtual FrameEvent* next() = 0; }; class Architecture { @@ -351,6 +350,10 @@ class Assembler { virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + int32_t* frameTable, void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) = 0; virtual void* frameIp(void* stack) = 0; virtual unsigned frameHeaderSize() = 0; virtual unsigned frameReturnAddressSize() = 0; @@ -437,9 +440,9 @@ class Assembler { virtual unsigned length() = 0; - virtual unsigned frameSizeEventCount() = 0; + virtual unsigned frameEventCount() = 0; - virtual FrameSizeEvent* firstFrameSizeEvent() = 0; + virtual FrameEvent* firstFrameEvent() = 0; virtual void dispose() = 0; }; diff --git a/src/compile-x86.S b/src/compile-x86.S index 080b3ba5da..6bf13a5bfb 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -295,9 +295,9 @@ LOCAL(vmJumpAndInvoke_argumentTest): #define THREAD_STACK 2148 #define THREAD_SCRATCH 2152 - + #define CALLEE_SAVED_REGISTER_FOOTPRINT 16 - + .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): pushl %ebp diff --git a/src/compile.cpp b/src/compile.cpp index 42791ca8b4..61112a5fc0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -153,14 +153,18 @@ class MyThread: public Thread { CallTrace* trace): Context(t, ip, stack, continuation, trace), t(t), + link(0), + javaStackLimit(0), next(t->traceContext) { t->traceContext = this; } - TraceContext(MyThread* t): + TraceContext(MyThread* t, void* link): Context(t, t->ip, t->stack, t->continuation, t->trace), t(t), + link(link), + javaStackLimit(0), next(t->traceContext) { t->traceContext = this; @@ -171,6 +175,8 @@ class MyThread: public Thread { } MyThread* t; + void* link; + void* javaStackLimit; TraceContext* next; }; @@ -414,56 +420,42 @@ getTableValue(Thread* t, object table, unsigned base, unsigned max, (&intArrayBody(t, table, base), bits, index * bits); } -unsigned -frameSize(MyThread* t, intptr_t ip, object method) +void +nextFrame(MyThread* t, void** ip, void** sp, object method, object target) { object code = methodCode(t, method); - object table = codeFrameSizeTable(t, code); - unsigned count = intArrayBody(t, table, 0); - unsigned max = alignedFrameSize(t, method); + object table = codeFrameTable(t, code); intptr_t start = codeCompiled(t, code); - int codeSize = compiledSize(start); - unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32); - - assert(t, ip >= start); - assert(t, ip <= start + codeSize); + void* link; + void* javaStackLimit; - unsigned offset = ip - start; - unsigned bottom = 0; - unsigned top = count; - for (unsigned span = top - bottom; span; span = top - bottom) { - unsigned middle = bottom + (span / 2); - unsigned candidate = getTableValue(t, table, 1, codeSize, middle); - - if (offset >= candidate - and (middle + 1 == count - or offset < getTableValue(t, table, 1, codeSize, middle + 1))) - { - return getTableValue(t, table, 1 + indexSize, max, middle); - } else if (offset < candidate) { - top = middle; - } else if (offset > candidate) { - bottom = middle + 1; - } - } - - if (top == 0) { - return 0; - } else if (top < count) { - return getTableValue(t, table, 1 + indexSize, max, top); - } else if (top == count && count > 0) { - return getTableValue(t, table, 1 + indexSize, max, top - 1); + if (t->traceContext) { + link = t->traceContext->link; + javaStackLimit = t->traceContext->javaStackLimit; } else { - abort(t); + link = 0; + javaStackLimit = 0; } -} -void* -nextFrame(MyThread* t, void* ip, void* sp, object method) -{ - return reinterpret_cast(sp) + local::frameSize - (t, reinterpret_cast(ip), method) - + t->arch->frameReturnAddressSize(); + // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s\n", + // &byteArrayBody(t, className(t, methodClass(t, method)), 0), + // &byteArrayBody(t, methodName(t, method), 0), + // &byteArrayBody(t, methodSpec(t, method), 0), + // target + // ? &byteArrayBody(t, className(t, methodClass(t, target)), 0) + // : 0, + // target + // ? &byteArrayBody(t, methodName(t, target), 0) + // : 0, + // target + // ? &byteArrayBody(t, methodSpec(t, target), 0) + // : 0); + + t->arch->nextFrame + (reinterpret_cast(start), compiledSize(start), + alignedFrameSize(t, method), table ? &intArrayBody(t, table, 0) : 0, + link, javaStackLimit, target ? methodParameterFootprint(t, target) : -1, + ip, sp); } class MyStackWalker: public Processor::StackWalker { @@ -486,6 +478,7 @@ class MyStackWalker: public Processor::StackWalker { virtual void visit(Heap::Visitor* v) { v->visit(&(walker->method_)); + v->visit(&(walker->target)); v->visit(&(walker->continuation)); } @@ -496,6 +489,7 @@ class MyStackWalker: public Processor::StackWalker { t(t), state(Start), method_(0), + target(0), protector(this) { if (t->traceContext) { @@ -518,6 +512,7 @@ class MyStackWalker: public Processor::StackWalker { stack(w->stack), trace(w->trace), method_(w->method_), + target(w->target), continuation(w->continuation), protector(this) { } @@ -551,6 +546,7 @@ class MyStackWalker: public Processor::StackWalker { case Next: if (stack) { + target = method_; method_ = methodForIp(t, ip_); if (method_) { state = Method; @@ -599,8 +595,7 @@ class MyStackWalker: public Processor::StackWalker { break; case Method: - stack = nextFrame(t, ip_, stack, method_); - ip_ = t->arch->frameIp(stack); + nextFrame(t, &ip_, &stack, method_, target); break; case NativeMethod: @@ -654,6 +649,7 @@ class MyStackWalker: public Processor::StackWalker { void* stack; MyThread::CallTrace* trace; object method_; + object target; object continuation; MyProtector protector; }; @@ -2028,7 +2024,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, if (handler) { *targetIp = handler; - stack = nextFrame(t, ip, stack, method); + nextFrame(t, &ip, &stack, method, target); void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); @@ -2040,8 +2036,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, t->exception = 0; } else { - stack = nextFrame(t, ip, stack, method); - ip = t->arch->frameIp(stack); + nextFrame(t, &ip, &stack, method, target); if (t->exception) { releaseLock(t, method, stack); @@ -2126,7 +2121,8 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) top += argumentFootprint - alignment; } - stack = nextFrame(t, ip, stack, method); + void* nextIp = ip; + nextFrame(t, &nextIp, &stack, method, target); void** bottom = static_cast(stack) + t->arch->frameReturnAddressSize(); @@ -2156,7 +2152,7 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) } last = c; - ip = t->arch->frameIp(stack); + ip = nextIp; target = method; } else { @@ -5224,20 +5220,21 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) } object -makeFrameSizeTable(MyThread* t, Context* c, unsigned codeSize) +makeFrameTable(MyThread* t, Context* c, unsigned codeSize) { Assembler* a = c->assembler; - unsigned count = a->frameSizeEventCount(); - int max = alignedFrameSize(t, c->method); - unsigned indexSize = ceiling(count * bitsNeeded(codeSize), 32); - unsigned tableSize = ceiling(count * bitsNeeded(max), 32); - object table = makeIntArray(t, 1 + indexSize + tableSize); + unsigned count = a->frameEventCount(); + if (count == 0) { + return 0; + } + + unsigned size = ceiling(count * bitsNeeded(codeSize), 32); + object table = makeIntArray(t, 1 + size); intArrayBody(t, table, 0) = count; unsigned index = 0; - int value = 0; - for (Assembler::FrameSizeEvent* e = a->firstFrameSizeEvent(); + for (Assembler::FrameEvent* e = a->firstFrameEvent(); e; e = e->next()) { assert(t, index < count); @@ -5245,17 +5242,8 @@ makeFrameSizeTable(MyThread* t, Context* c, unsigned codeSize) unsigned offset = e->offset(); assert(t, offset <= codeSize); - value += e->change(); - - fprintf(stderr, "offset %d change %d value %d\n", - offset, e->change(), value); - - assert(t, value >= 0); - assert(t, value <= max); - setTableValue(t, table, 1, codeSize, index, offset); - setTableValue(t, table, 1 + indexSize, max, index, value); - + ++ index; } @@ -5950,12 +5938,12 @@ finish(MyThread* t, Allocator* allocator, Context* context) PROTECT(t, newLineNumberTable); - object frameSizeTable = makeFrameSizeTable(t, context, codeSize); + object frameTable = makeFrameTable(t, context, codeSize); object code = methodCode(t, context->method); code = makeCode - (t, 0, newExceptionHandlerTable, newLineNumberTable, frameSizeTable, + (t, 0, newExceptionHandlerTable, newLineNumberTable, frameTable, reinterpret_cast(start), codeMaxStack(t, code), codeMaxLocals(t, code), 0); @@ -6700,6 +6688,7 @@ visitStack(MyThread* t, Heap::Visitor* v) MyThread::CallTrace* trace = t->trace; object targetMethod = (trace ? trace->targetMethod : 0); + object target = targetMethod; while (stack) { if (targetMethod) { @@ -6711,11 +6700,14 @@ visitStack(MyThread* t, Heap::Visitor* v) if (method) { PROTECT(t, method); - stack = nextFrame(t, ip, stack, method); + void* nextIp = ip; + nextFrame(t, &nextIp, &stack, method, target); visitStackAndLocals(t, v, stack, method, ip); - ip = t->arch->frameIp(stack); + ip = nextIp; + + target = method; } else if (trace) { stack = trace->stack; ip = t->arch->frameIp(stack); @@ -6723,6 +6715,9 @@ visitStack(MyThread* t, Heap::Visitor* v) if (trace) { targetMethod = trace->targetMethod; + target = targetMethod; + } else { + target = 0; } } else { break; @@ -7665,13 +7660,14 @@ class MyProcessor: public Processor { t(t), p(p), target(target), trace(0) { } - virtual void visit(void* ip, void* stack) { - MyThread::TraceContext c(target); + virtual void visit(void* ip, void* stack, void* link) { + MyThread::TraceContext c(target, link); if (methodForIp(t, ip)) { // we caught the thread in Java code - use the register values c.ip = ip; c.stack = stack; + c.javaStackLimit = stack; } else if (target->transition) { // we caught the thread in native code while in the middle // of updating the context fields (MyThread::stack, etc.) diff --git a/src/posix.cpp b/src/posix.cpp index 590d8e65ca..8b2496ae81 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -834,6 +834,7 @@ handleSignal(int signal, siginfo_t* info, void* context) void* ip = reinterpret_cast(IP_REGISTER(c)); void* stack = reinterpret_cast(STACK_REGISTER(c)); void* thread = reinterpret_cast(THREAD_REGISTER(c)); + void* link = reinterpret_cast(LINK_REGISTER(c)); unsigned index; @@ -841,7 +842,7 @@ handleSignal(int signal, siginfo_t* info, void* context) case VisitSignal: { index = VisitSignalIndex; - system->threadVisitor->visit(ip, stack); + system->threadVisitor->visit(ip, stack, link); System::Thread* t = system->visitTarget; system->visitTarget = 0; diff --git a/src/system.h b/src/system.h index 8cf08ea88a..258b04f440 100644 --- a/src/system.h +++ b/src/system.h @@ -35,7 +35,7 @@ class System { class ThreadVisitor { public: - virtual void visit(void* ip, void* stack) = 0; + virtual void visit(void* ip, void* stack, void* link) = 0; }; class Runnable { diff --git a/src/types.def b/src/types.def index 7509c431a9..24d4b1854c 100644 --- a/src/types.def +++ b/src/types.def @@ -86,7 +86,7 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) - (object frameSizeTable) + (object frameTable) (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) diff --git a/src/x86.cpp b/src/x86.cpp index 676c011da8..eb61e405ad 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -72,8 +72,6 @@ const int LongJumpRegister = r10; const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; -const int FrameSizePoison = -2147483647; - bool isInt8(intptr_t v) { @@ -88,7 +86,7 @@ isInt32(intptr_t v) class Task; class AlignmentPadding; -class MyFrameSizeEvent; +class MyFrameEvent; unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, @@ -97,17 +95,14 @@ padding(AlignmentPadding* p, unsigned index, unsigned offset, class Context; class MyBlock; -void -appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change); - ResolvedPromise* - resolved(Context* c, int64_t value); +resolved(Context* c, int64_t value); class MyBlock: public Assembler::Block { public: MyBlock(unsigned offset): - next(0), firstPadding(0), lastPadding(0), firstFrameSizeEvent(0), - lastFrameSizeEvent(0), offset(offset), start(~0), size(0) + next(0), firstPadding(0), lastPadding(0), firstFrameEvent(0), + lastFrameEvent(0), offset(offset), start(~0), size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { @@ -120,8 +115,8 @@ class MyBlock: public Assembler::Block { MyBlock* next; AlignmentPadding* firstPadding; AlignmentPadding* lastPadding; - MyFrameSizeEvent* firstFrameSizeEvent; - MyFrameSizeEvent* lastFrameSizeEvent; + MyFrameEvent* firstFrameEvent; + MyFrameEvent* lastFrameEvent; unsigned offset; unsigned start; unsigned size; @@ -164,8 +159,8 @@ class Context { Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), firstFrameSizeEvent(0), lastFrameSizeEvent(0), - ac(ac), frameSizeEventCount(0) + lastBlock(firstBlock), firstFrameEvent(0), lastFrameEvent(0), + ac(ac), frameEventCount(0) { } System* s; @@ -176,10 +171,10 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; - MyFrameSizeEvent* firstFrameSizeEvent; - MyFrameSizeEvent* lastFrameSizeEvent; + MyFrameEvent* firstFrameEvent; + MyFrameEvent* lastFrameEvent; ArchitectureContext* ac; - unsigned frameSizeEventCount; + unsigned frameEventCount; }; void NO_RETURN @@ -466,52 +461,45 @@ padding(AlignmentPadding* p, unsigned start, unsigned offset, return padding; } -class MyFrameSizeEvent: public Assembler::FrameSizeEvent { +class MyFrameEvent: public Assembler::FrameEvent { public: - MyFrameSizeEvent(Context* c, Promise* offset, int change): - c(c), next_(0), offset_(offset), change_(change) + MyFrameEvent(Context* c, Promise* offset): + c(c), next_(0), offset_(offset) { } virtual unsigned offset() { return offset_->value(); } - virtual int change() { - expect(c, change_ != FrameSizePoison); - - return change_; - } - - virtual Assembler::FrameSizeEvent* next() { + virtual Assembler::FrameEvent* next() { return next_; } Context* c; - MyFrameSizeEvent* next_; + MyFrameEvent* next_; Promise* offset_; - int change_; }; void -appendFrameSizeEvent(Context* c, MyBlock* b, Promise* offset, int change) +appendFrameEvent(Context* c, MyBlock* b, Promise* offset) { - MyFrameSizeEvent* e = new (c->zone->allocate(sizeof(MyFrameSizeEvent))) - MyFrameSizeEvent(c, offset, change); + MyFrameEvent* e = new (c->zone->allocate(sizeof(MyFrameEvent))) + MyFrameEvent(c, offset); - if (b->firstFrameSizeEvent) { - b->lastFrameSizeEvent->next_ = e; + if (b->firstFrameEvent) { + b->lastFrameEvent->next_ = e; } else { - b->firstFrameSizeEvent = e; + b->firstFrameEvent = e; } - b->lastFrameSizeEvent = e; + b->lastFrameEvent = e; - ++ c->frameSizeEventCount; + ++ c->frameEventCount; } void -appendFrameSizeEvent(Context* c, int change) +appendFrameEvent(Context* c) { - appendFrameSizeEvent(c, c->lastBlock, offset(c), change); + appendFrameEvent(c, c->lastBlock, offset(c)); } extern "C" bool @@ -2574,6 +2562,93 @@ absoluteRR(Context* c, unsigned aSize, Assembler::Register* a, c->client->releaseTemporary(rdx); } +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + +uint32_t +read4(uint8_t* p) +{ + uint32_t v; memcpy(&v, p, 4); + return v; +} + +void +nextFrame(ArchitectureContext* c, uint8_t* start, unsigned size, + unsigned footprint, int32_t*, void*, void* stackLimit, + unsigned targetParameterFootprint, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + size); + + uint8_t* instruction = static_cast(*ip); + + if (BytesPerWord == 4) { + if (*start == 0x39) { + // skip stack overflow check + start += 11; + } + } else if (*start == 0x48 and start[1] == 0x39) { + // skip stack overflow check + start += 12; + } + + if (instruction <= start) { + *ip = reinterpret_cast(*stack)[0]; + return; + } + + if (UseFramePointer) { + // skip preamble + start += (BytesPerWord == 4 ? 3 : 4); + + if (instruction <= start or *instruction == 0x5d) { + *ip = reinterpret_cast(*stack)[1]; + *stack = reinterpret_cast(*stack) + 1; + return; + } + } + + if (*instruction == 0xc3) { + *ip = reinterpret_cast(*stack)[0]; + return; + } + + unsigned offset = footprint + FrameHeaderSize + - (stackLimit == *stack ? 1 : 0); + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + if (BytesPerWord == 4) { + if ((*instruction == 0x83 or *instruction == 0x81) + and instruction[1] == 0xec) + { + offset + -= (*instruction == 0x83 ? instruction[2] : read4(instruction + 2)) + / BytesPerWord; + } + } else if (*instruction == 0x48 + and (instruction[1] == 0x83 or instruction[1] == 0x81) + and instruction[2] == 0xec) + { + offset + -= (instruction[1] == 0x83 ? instruction[3] : read4(instruction + 3)) + / BytesPerWord; + } + + // todo: use frameTable to check for and handle tail calls + } + + *ip = reinterpret_cast(*stack)[offset]; + *stack = reinterpret_cast(*stack) + offset; +} + void populateTables(ArchitectureContext* c) { @@ -2771,7 +2846,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return local::argumentFootprint(footprint); } virtual bool argumentAlignment() { @@ -2900,6 +2975,16 @@ class MyArchitecture: public Assembler::Architecture { - FrameHeaderSize; } + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + int32_t* frameTable, void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + local::nextFrame(&c, static_cast(start), size, footprint, + frameTable, link, stackLimit, targetParameterFootprint, + ip, stack); + } + virtual void* frameIp(void* stack) { return stack ? *static_cast(stack) : 0; } @@ -3397,28 +3482,20 @@ class MyAssembler: public Assembler { apply(Move, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &base); - - appendFrameSizeEvent(&c, 1); } Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); apply(Subtract, BytesPerWord, ConstantOperand, &footprintConstant, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); - - appendFrameSizeEvent(&c, footprint); } virtual void adjustFrame(unsigned difference) { - appendFrameSizeEvent(&c, - difference); - Register stack(rsp); Constant differenceConstant(resolved(&c, difference * BytesPerWord)); apply(Subtract, BytesPerWord, ConstantOperand, &differenceConstant, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); - - appendFrameSizeEvent(&c, difference); } virtual void popFrame(unsigned frameFootprint) { @@ -3428,19 +3505,13 @@ class MyAssembler: public Assembler { apply(Move, BytesPerWord, RegisterOperand, &base, BytesPerWord, RegisterOperand, &stack); - appendFrameSizeEvent(&c, - frameFootprint); - popR(&c, BytesPerWord, &base); - - appendFrameSizeEvent(&c, - 1); } else { Register stack(rsp); Constant footprint(resolved(&c, frameFootprint * BytesPerWord)); apply(Add, BytesPerWord, ConstantOperand, &footprint, BytesPerWord, RegisterOperand, &stack, BytesPerWord, RegisterOperand, &stack); - - appendFrameSizeEvent(&c, - frameFootprint); } } @@ -3451,13 +3522,18 @@ class MyAssembler: public Assembler { { if (TailCalls) { if (offset) { + appendFrameEvent(&c); + Register tmp(c.client->acquireTemporary()); - Memory returnAddressSrc(rsp, (frameFootprint + 1) * BytesPerWord); + unsigned baseSize = UseFramePointer ? 1 : 0; + + Memory returnAddressSrc + (rsp, (frameFootprint + baseSize) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); Memory returnAddressDst - (rsp, (frameFootprint - offset + 1) * BytesPerWord); + (rsp, (frameFootprint - offset + baseSize) * BytesPerWord); moveRM(&c, BytesPerWord, &tmp, BytesPerWord, &returnAddressDst); c.client->releaseTemporary(tmp.low); @@ -3470,11 +3546,9 @@ class MyAssembler: public Assembler { Register stack(rsp); Constant footprint - (resolved(&c, (frameFootprint - offset + 1) * BytesPerWord)); + (resolved(&c, (frameFootprint - offset + baseSize) * BytesPerWord)); addCR(&c, BytesPerWord, &footprint, BytesPerWord, &stack); - appendFrameSizeEvent(&c, - (frameFootprint - offset + 1)); - if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); @@ -3507,6 +3581,8 @@ class MyAssembler: public Assembler { assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (TailCalls and argumentFootprint > StackAlignmentInWords) { + appendFrameEvent(&c); + Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); @@ -3516,16 +3592,10 @@ class MyAssembler: public Assembler { * BytesPerWord)); addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack); - appendFrameSizeEvent(&c, - (argumentFootprint - StackAlignmentInWords)); - jumpR(&c, BytesPerWord, &returnAddress); } else { return_(&c); } - - // todo: this is not necessary if there are no instructions to - // follow: - appendFrameSizeEvent(&c, frameFootprint); } virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, @@ -3536,16 +3606,10 @@ class MyAssembler: public Assembler { Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); - appendFrameSizeEvent(&c, -1); - Register stack(rsp); Memory stackSrc(rbx, stackOffsetFromThread); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); - // we can't statically determine the frame size at this point, so - // we poison any attempt to query for it: - appendFrameSizeEvent(&c, FrameSizePoison); - jumpR(&c, BytesPerWord, &returnAddress); } @@ -3594,13 +3658,13 @@ class MyAssembler: public Assembler { c.result = dst; for (MyBlock* b = c.firstBlock; b; b = b->next) { - if (b->firstFrameSizeEvent) { - if (c.firstFrameSizeEvent) { - c.lastFrameSizeEvent->next_ = b->firstFrameSizeEvent; + if (b->firstFrameEvent) { + if (c.firstFrameEvent) { + c.lastFrameEvent->next_ = b->firstFrameEvent; } else { - c.firstFrameSizeEvent = b->firstFrameSizeEvent; + c.firstFrameEvent = b->firstFrameEvent; } - c.lastFrameSizeEvent = b->lastFrameSizeEvent; + c.lastFrameEvent = b->lastFrameEvent; } unsigned index = 0; @@ -3656,12 +3720,12 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual unsigned frameSizeEventCount() { - return c.frameSizeEventCount; + virtual unsigned frameEventCount() { + return c.frameEventCount; } - virtual FrameSizeEvent* firstFrameSizeEvent() { - return c.firstFrameSizeEvent; + virtual FrameEvent* firstFrameEvent() { + return c.firstFrameEvent; } virtual void dispose() { diff --git a/src/x86.h b/src/x86.h index 3073d1f46c..c277168ce0 100644 --- a/src/x86.h +++ b/src/x86.h @@ -29,20 +29,20 @@ # ifdef __APPLE__ # if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) # define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) -# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp) # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) +# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__ecx) # else # define IP_REGISTER(context) (context->uc_mcontext->ss.eip) -# define BASE_REGISTER(context) (context->uc_mcontext->ss.ebp) # define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) # define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) +# define LINK_REGISTER(context) (context->uc_mcontext->ss.ecx) # endif # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) +# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_ECX]) # endif extern "C" uint64_t @@ -65,20 +65,20 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, # ifdef __APPLE__ # if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) # define IP_REGISTER(context) (context->uc_mcontext->__ss.__rip) -# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__rbp) # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx) +# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__rcx) # else # define IP_REGISTER(context) (context->uc_mcontext->ss.rip) -# define BASE_REGISTER(context) (context->uc_mcontext->ss.rbp) # define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp) # define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx) +# define LINK_REGISTER(context) (context->uc_mcontext->ss.rcx) # endif # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) -# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) +# define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_RCX]) # endif extern "C" uint64_t From 5cedcf78338aac425da571a457c1a53aa8259a37 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 11:53:53 -0700 Subject: [PATCH 209/274] remove unnecessary exception checks from bootimage.cpp --- src/bootimage.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index f267232ee3..b9c4a0a438 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -409,35 +409,27 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, // runtime: { resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[B"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[Z"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[S"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[C"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[I"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[J"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[F"), true); - if (t->exception) return; resolveSystemClass (t, root(t, Machine::BootLoader), makeByteArray(t, "[D"), true); - if (t->exception) return; } collect(t, Heap::MajorCollection); From b7157c802a9a9534112381625573674ea3132f9e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 11:54:41 -0700 Subject: [PATCH 210/274] fix continuations=true build --- src/compile.cpp | 22 ++++++++++++++-------- src/continuations-x86.S | 4 ++++ src/machine.cpp | 23 +++++++---------------- src/machine.h | 20 ++++++++++++++++++-- src/x86.cpp | 2 +- 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 61112a5fc0..f7ad3591f4 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2133,14 +2133,14 @@ makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) object c = makeContinuation (t, 0, context, method, ip, - ((frameSize - + t->arch->frameFooterSize() - + t->arch->returnAddressOffset() - - t->arch->frameReturnAddressSize()) * BytesPerWord), - ((frameSize - + t->arch->frameFooterSize() - + t->arch->framePointerOffset() - - t->arch->frameReturnAddressSize()) * BytesPerWord), + (frameSize + + t->arch->frameFooterSize() + + t->arch->returnAddressOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord, + (frameSize + + t->arch->frameFooterSize() + + t->arch->framePointerOffset() + - t->arch->frameReturnAddressSize()) * BytesPerWord, totalSize); memcpy(&continuationBody(t, c, 0), top, totalSize * BytesPerWord); @@ -6780,6 +6780,8 @@ callContinuation(MyThread* t, object continuation, object result, t->trace->nativeMethod = 0; t->trace->targetMethod = 0; + popResources(t); + transition(t, ip, stack, continuation, t->trace); vmJump(ip, stack, t, reinterpret_cast(result), 0); @@ -6857,6 +6859,10 @@ jumpAndInvoke(MyThread* t, object method, void* stack, ...) RUNTIME_ARRAY_BODY(arguments)[i] = va_arg(a, uintptr_t); } va_end(a); + + assert(t, t->exception == 0); + + popResources(t); vmJumpAndInvoke (t, reinterpret_cast(methodAddress(t, method)), diff --git a/src/continuations-x86.S b/src/continuations-x86.S index de30be72ac..af2b399ea0 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -59,11 +59,13 @@ LOCAL(vmInvoke_continuationTest): #endif movq %r10,(%rsp,%rdi,1) +#ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movq CONTINUATION_FRAME_POINTER_OFFSET(%rcx),%rdi movq %rbp,(%rsp,%rdi,1) addq %rsp,%rdi movq %rdi,%rbp +#endif // consume the continuation movq CONTINUATION_NEXT(%rcx),%rdi @@ -151,11 +153,13 @@ LOCAL(vmInvoke_offset): #endif movl %esi,(%esp,%edi,1) +#ifdef AVIAN_USE_FRAME_POINTER // save the current base pointer in the frame and update it movl CONTINUATION_FRAME_POINTER_OFFSET(%ecx),%edi movl %ebp,(%esp,%edi,1) addl %esp,%edi movl %edi,%ebp +#endif // consume the continuation movl CONTINUATION_NEXT(%ecx),%edi diff --git a/src/machine.cpp b/src/machine.cpp index cd7c40cf51..b7975d0abb 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2843,28 +2843,19 @@ makeNewGeneral(Thread* t, object class_) return instance; } -void NO_RETURN -throw_(Thread* t, object e) +void +popResources(Thread* t) { - assert(t, t->exception == 0); - - Thread::Checkpoint* checkpoint = t->checkpoint; - - expect(t, not checkpoint->noThrow); - - t->exception = e; - - while (t->resource != checkpoint->resource) { + while (t->resource != t->checkpoint->resource) { Thread::Resource* r = t->resource; t->resource = r->next; + fprintf(stderr, "unwind resource %p %p %p\n", r, + reinterpret_cast(r)[0], + reinterpret_cast(r)[0][0]); r->release(); } - t->protector = checkpoint->protector; - - checkpoint->unwind(); - - abort(t); + t->protector = t->checkpoint->protector; } object diff --git a/src/machine.h b/src/machine.h index f721277b44..745ada691e 100644 --- a/src/machine.h +++ b/src/machine.h @@ -2572,8 +2572,24 @@ makeThrowable(Thread* t, Machine::Type type, const char* format, ...) return r; } -void NO_RETURN -throw_(Thread* t, object e); +void +popResources(Thread* t); + +inline void NO_RETURN +throw_(Thread* t, object e) +{ + assert(t, t->exception == 0); + + expect(t, not t->checkpoint->noThrow); + + t->exception = e; + + popResources(t); + + t->checkpoint->unwind(); + + abort(t); +} inline void NO_RETURN throwNew(Thread* t, Machine::Type type) diff --git a/src/x86.cpp b/src/x86.cpp index eb61e405ad..c5227cca26 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3029,7 +3029,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int framePointerOffset() { - return -1; + return UseFramePointer ? -1 : 0; } virtual void plan From e4e001500564a3505a1b2847909ac43db393dcd1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 21:03:39 -0700 Subject: [PATCH 211/274] fix GC safety issue in bootimage.cpp --- src/bootimage.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index b9c4a0a438..13a278ea8b 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -407,29 +407,29 @@ writeBootImage2(Thread* t, FILE* out, BootImage* image, uint8_t* code, // resolve primitive array classes in case they are needed at // runtime: - { resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[B"), true); + { object name = makeByteArray(t, "[B"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[Z"), true); + name = makeByteArray(t, "[Z"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[S"), true); + name = makeByteArray(t, "[S"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[C"), true); + name = makeByteArray(t, "[C"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[I"), true); + name = makeByteArray(t, "[I"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[J"), true); + name = makeByteArray(t, "[J"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[F"), true); + name = makeByteArray(t, "[F"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); - resolveSystemClass - (t, root(t, Machine::BootLoader), makeByteArray(t, "[D"), true); + name = makeByteArray(t, "[D"); + resolveSystemClass(t, root(t, Machine::BootLoader), name, true); } collect(t, Heap::MajorCollection); From b47dfdf5bd51e7be85e5a67d1223fec1f17da4d1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 21:05:22 -0700 Subject: [PATCH 212/274] remove debug logging --- src/machine.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index b7975d0abb..21338c441b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2849,9 +2849,6 @@ popResources(Thread* t) while (t->resource != t->checkpoint->resource) { Thread::Resource* r = t->resource; t->resource = r->next; - fprintf(stderr, "unwind resource %p %p %p\n", r, - reinterpret_cast(r)[0], - reinterpret_cast(r)[0][0]); r->release(); } From f980ceb13e95e87e012fb913876f6c45db8f095e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 21:06:01 -0700 Subject: [PATCH 213/274] enable use-frame-pointer=true build Also, include Continuations, Coroutines, and DynamicWind tests in test suite for continuations=true build. --- makefile | 17 +++++++++++++++-- src/arch.h | 4 ++-- src/compile.cpp | 37 ++++++++++++++++++++++++------------- src/machine.h | 2 +- src/posix.cpp | 12 +++++++++--- src/system.h | 3 ++- src/x86.S | 27 +++++++++++++++------------ src/x86.h | 6 ++++++ test/test.sh | 2 +- 9 files changed, 75 insertions(+), 35 deletions(-) diff --git a/makefile b/makefile index 5b34b5051b..db883dc741 100644 --- a/makefile +++ b/makefile @@ -151,12 +151,17 @@ rdynamic = -rdynamic warnings = -Wall -Wextra -Werror -Wunused-parameter -Winit-self \ -Wno-non-virtual-dtor -common-cflags = $(warnings) -fno-rtti -fno-exceptions -fno-omit-frame-pointer \ +common-cflags = $(warnings) -fno-rtti -fno-exceptions \ "-I$(JAVA_HOME)/include" -idirafter $(src) -I$(build) $(classpath-cflags) \ -D__STDC_LIMIT_MACROS -D_JNI_IMPLEMENTATION_ -DAVIAN_VERSION=\"$(version)\" \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" +ifeq ($(use-frame-pointer),true) + common-cflags += -fno-omit-frame-pointer -DAVIAN_USE_FRAME_POINTER + asmflags += -DAVIAN_USE_FRAME_POINTER +endif + build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread @@ -544,6 +549,13 @@ test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) test-extra-dep = $(test-build)-extra.dep +ifeq ($(continuations),true) + continuation-tests = \ + extra.Continuations \ + extra.Coroutines \ + extra.DynamicWind +endif + class-name = $(patsubst $(1)/%.class,%,$(2)) class-names = $(foreach x,$(2),$(call class-name,$(1),$(x))) @@ -575,7 +587,8 @@ vg: build test: build $(library-path) /bin/sh $(test)/test.sh 2>/dev/null \ $(test-executable) $(mode) "$(test-flags)" \ - $(call class-names,$(test-build),$(test-classes)) + $(call class-names,$(test-build),$(test-classes)) \ + $(continuation-tests) .PHONY: tarball tarball: diff --git a/src/arch.h b/src/arch.h index 56afe1d5c3..6e6d4b24a6 100644 --- a/src/arch.h +++ b/src/arch.h @@ -22,8 +22,8 @@ #include "common.h" extern "C" void NO_RETURN -vmJump(void* address, void* stack, void* thread, uintptr_t returnLow, - uintptr_t returnHigh); +vmJump(void* address, void* frame, void* stack, void* thread, + uintptr_t returnLow, uintptr_t returnHigh); namespace vm { diff --git a/src/compile.cpp b/src/compile.cpp index f7ad3591f4..afe20a7c95 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1992,8 +1992,8 @@ releaseLock(MyThread* t, object method, void* stack) } void -findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, - object* targetContinuation) +findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, + void** targetStack, object* targetContinuation) { void* ip; void* stack; @@ -2029,6 +2029,8 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, void** sp = static_cast(stackForFrame(t, stack, method)) + t->arch->frameReturnAddressSize(); + *targetFrame = static_cast + (stack) + t->arch->framePointerOffset(); *targetStack = sp; *targetContinuation = continuation; @@ -2046,6 +2048,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetStack, } } else { *targetIp = ip; + *targetFrame = 0; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); *targetContinuation = continuation; @@ -2172,13 +2175,14 @@ void NO_RETURN unwind(MyThread* t) { void* ip; + void* frame; void* stack; object continuation; - findUnwindTarget(t, &ip, &stack, &continuation); + findUnwindTarget(t, &ip, &frame, &stack, &continuation); transition(t, ip, stack, continuation, t->trace); - vmJump(ip, stack, t, 0, 0); + vmJump(ip, frame, stack, t, 0, 0); } class MyCheckpoint: public Thread::Checkpoint { @@ -6774,7 +6778,8 @@ callContinuation(MyThread* t, object continuation, object result, MyThread::TraceContext c(t, ip, stack, continuation, t->trace); - findUnwindTarget(t, &ip, &stack, &continuation); + void* frame; + findUnwindTarget(t, &ip, &frame, &stack, &continuation); } t->trace->nativeMethod = 0; @@ -6784,7 +6789,7 @@ callContinuation(MyThread* t, object continuation, object result, transition(t, ip, stack, continuation, t->trace); - vmJump(ip, stack, t, reinterpret_cast(result), 0); + vmJump(ip, 0, stack, t, reinterpret_cast(result), 0); } int8_t* @@ -6941,10 +6946,12 @@ callContinuation(MyThread* t, object continuation, object result, (t, root(t, Machine::BootLoader), "avian/Continuations", "rewind", "(Ljava/lang/Runnable;Lavian/Callback;Ljava/lang/Object;" "Ljava/lang/Throwable;)V"); - - setRoot(t, RewindMethod, method); + + PROTECT(t, method); compile(t, local::codeAllocator(t), 0, method); + + setRoot(t, RewindMethod, method); } } else { action = Call; @@ -6957,9 +6964,10 @@ callContinuation(MyThread* t, object continuation, object result, } void* ip; + void* frame; void* stack; object threadContinuation; - findUnwindTarget(t, &ip, &stack, &threadContinuation); + findUnwindTarget(t, &ip, &frame, &stack, &threadContinuation); switch (action) { case Call: { @@ -7037,7 +7045,7 @@ dynamicWind(MyThread* t, object before, object thunk, object after) object method = resolveMethod (t, root(t, Machine::BootLoader), "avian/Continuations", "wind", "(Ljava/lang/Runnable;Ljava/util/concurrent/Callable;" - "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); + "Ljava/lang/Runnable;)Lavian/Continuations$UnwindResult;"); if (method) { setRoot(t, WindMethod, method); @@ -7264,7 +7272,9 @@ class SignalHandler: public System::SignalHandler { SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): m(0), type(type), root(root), fixedSize(fixedSize) { } - virtual bool handleSignal(void** ip, void** stack, void** thread) { + virtual bool handleSignal(void** ip, void** frame, void** stack, + void** thread) + { MyThread* t = static_cast(m->localThread->get()); if (t and t->state == Thread::ActiveState) { object node = methodForIp(t, *ip); @@ -7289,7 +7299,7 @@ class SignalHandler: public System::SignalHandler { // printTrace(t, t->exception); object continuation; - findUnwindTarget(t, ip, stack, &continuation); + findUnwindTarget(t, ip, frame, stack, &continuation); transition(t, ip, stack, continuation, t->trace); @@ -8274,7 +8284,8 @@ fixupThunks(MyThread* t, BootImage* image, uint8_t* code) void fixupVirtualThunks(MyThread* t, BootImage* image, uint8_t* code) { - for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) { + for (unsigned i = 0; i < wordArrayLength(t, root(t, VirtualThunks)); i += 2) + { if (wordArrayBody(t, root(t, VirtualThunks), i)) { wordArrayBody(t, root(t, VirtualThunks), i) = (wordArrayBody(t, root(t, VirtualThunks), i) - image->codeBase) diff --git a/src/machine.h b/src/machine.h index 745ada691e..e7b30539dd 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1472,7 +1472,7 @@ class Thread { void* stack = this->stack; this->stack = 0; expect(t->m->system, stack); - vmJump(voidPointer(vmRun_returnAddress), stack, t, 0, 0); + vmJump(voidPointer(vmRun_returnAddress), 0, stack, t, 0, 0); } void* stack; diff --git a/src/posix.cpp b/src/posix.cpp index 8b2496ae81..de879c3496 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -815,7 +815,7 @@ class MySystem: public System { } class NullSignalHandler: public SignalHandler { - virtual bool handleSignal(void**, void**, void**) { return false; } + virtual bool handleSignal(void**, void**, void**, void**) { return false; } } nullHandler; SignalHandler* handlers[SignalCount]; @@ -835,6 +835,11 @@ handleSignal(int signal, siginfo_t* info, void* context) void* stack = reinterpret_cast(STACK_REGISTER(c)); void* thread = reinterpret_cast(THREAD_REGISTER(c)); void* link = reinterpret_cast(LINK_REGISTER(c)); +#ifdef FRAME_REGISTER + void* frame = reinterpret_cast(FRAME_REGISTER(c)); +#else + void* frame = 0; +#endif unsigned index; @@ -871,7 +876,8 @@ handleSignal(int signal, siginfo_t* info, void* context) abort(); } - bool jump = system->handlers[index]->handleSignal(&ip, &stack, &thread); + bool jump = system->handlers[index]->handleSignal + (&ip, &frame, &stack, &thread); if (jump) { // I'd like to use setcontext here (and get rid of the @@ -885,7 +891,7 @@ handleSignal(int signal, siginfo_t* info, void* context) sigaddset(&set, signal); sigprocmask(SIG_UNBLOCK, &set, 0); - vmJump(ip, stack, thread, 0, 0); + vmJump(ip, frame, stack, thread, 0, 0); } } break; diff --git a/src/system.h b/src/system.h index 258b04f440..4d155cfd66 100644 --- a/src/system.h +++ b/src/system.h @@ -96,7 +96,8 @@ class System { class SignalHandler { public: - virtual bool handleSignal(void** ip, void** stack, void** thread) = 0; + virtual bool handleSignal(void** ip, void** frame, void** stack, + void** thread) = 0; }; class MonitorResource { diff --git a/src/x86.S b/src/x86.S index 08e05e4aaf..72b25268fd 100644 --- a/src/x86.S +++ b/src/x86.S @@ -170,10 +170,11 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): - movq %r9,%rax - movq 40(%rsp),%rdx - movq %rdx,%rsp - movq %r8,%rbx + movq %rdx,%rbp + movq 40(%rsp),%rax + movq 48(%rsp),%rdx + movq %r8,%rsp + movq %r9,%rbx jmp *%rcx #define VMRUN_FRAME_SIZE 80 @@ -350,10 +351,11 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): - movq %rsi,%rsp - movq %rdx,%rbx - movq %rcx,%rax - movq %r8,%rdx + movq %rsi,%rbp + movq %rdx,%rsp + movq %rcx,%rbx + movq %r8,%rax + movq %r9,%rdx jmp *%rdi #define VMRUN_FRAME_SIZE 64 @@ -508,10 +510,11 @@ LOCAL(exit): .globl GLOBAL(vmJump) GLOBAL(vmJump): movl 4(%esp),%esi - movl 12(%esp),%ebx - movl 16(%esp),%eax - movl 20(%esp),%edx - movl 8(%esp),%esp + movl 8(%esp),%ebp + movl 16(%esp),%ebx + movl 20(%esp),%eax + movl 24(%esp),%edx + movl 12(%esp),%esp jmp *%esi #define VMRUN_FRAME_SIZE 32 diff --git a/src/x86.h b/src/x86.h index c277168ce0..ec90c7befb 100644 --- a/src/x86.h +++ b/src/x86.h @@ -32,17 +32,20 @@ # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) # define LINK_REGISTER(context) (context->uc_mcontext->__ss.__ecx) +# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__ebp) # else # define IP_REGISTER(context) (context->uc_mcontext->ss.eip) # define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) # define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) # define LINK_REGISTER(context) (context->uc_mcontext->ss.ecx) +# define FRAME_REGISTER(context) (context->uc_mcontext->ss.ebp) # endif # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX]) # define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_ECX]) +# define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP]) # endif extern "C" uint64_t @@ -68,17 +71,20 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx) # define LINK_REGISTER(context) (context->uc_mcontext->__ss.__rcx) +# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__rbp) # else # define IP_REGISTER(context) (context->uc_mcontext->ss.rip) # define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp) # define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx) # define LINK_REGISTER(context) (context->uc_mcontext->ss.rcx) +# define FRAME_REGISTER(context) (context->uc_mcontext->ss.rbp) # endif # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) # define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX]) # define LINK_REGISTER(context) (context->uc_mcontext.gregs[REG_RCX]) +# define FRAME_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP]) # endif extern "C" uint64_t diff --git a/test/test.sh b/test/test.sh index 72d7734832..defd6af06a 100644 --- a/test/test.sh +++ b/test/test.sh @@ -14,7 +14,7 @@ echo -n "" >${log} echo for test in ${tests}; do - printf "%16s" "${test}: " + printf "%24s" "${test}: " case ${mode} in debug|debug-fast|fast|small ) From 740fa7ad9d96279431e77379efba1c0c4576c731 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 27 Jan 2011 21:10:06 -0700 Subject: [PATCH 214/274] fix unused parameter warnings --- src/x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index c5227cca26..c572263fc4 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2576,7 +2576,7 @@ read4(uint8_t* p) } void -nextFrame(ArchitectureContext* c, uint8_t* start, unsigned size, +nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned, unsigned footprint, int32_t*, void*, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { From 35ae3dc39156061229b2a30b9c3dc80306e4d360 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Jan 2011 08:43:11 -0700 Subject: [PATCH 215/274] fix mode=debug build --- src/x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index c572263fc4..25d3e85f74 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2576,7 +2576,7 @@ read4(uint8_t* p) } void -nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned, +nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, unsigned footprint, int32_t*, void*, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { From 08a6025138df87df34e2de8c8ec9a2b365b6e146 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Jan 2011 17:05:42 -0700 Subject: [PATCH 216/274] only enable frame pointer on x86(_64) --- makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index db883dc741..81e75b9dff 100644 --- a/makefile +++ b/makefile @@ -157,9 +157,11 @@ common-cflags = $(warnings) -fno-rtti -fno-exceptions \ -DUSE_ATOMIC_OPERATIONS -DAVIAN_JAVA_HOME=\"$(javahome)\" \ -DAVIAN_EMBED_PREFIX=\"$(embed-prefix)\" -ifeq ($(use-frame-pointer),true) - common-cflags += -fno-omit-frame-pointer -DAVIAN_USE_FRAME_POINTER - asmflags += -DAVIAN_USE_FRAME_POINTER +ifneq (,$(filter i386 x86_64,$(arch))) + ifeq ($(use-frame-pointer),true) + common-cflags += -fno-omit-frame-pointer -DAVIAN_USE_FRAME_POINTER + asmflags += -DAVIAN_USE_FRAME_POINTER + endif endif build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ From cac232a84ec82280d47d24c64709b2565ac94841 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Jan 2011 17:15:57 -0700 Subject: [PATCH 217/274] add comments to x86.cpp --- src/x86.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 25d3e85f74..a52fdc5da2 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2585,13 +2585,12 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, uint8_t* instruction = static_cast(*ip); + // skip stack overflow check, if present: if (BytesPerWord == 4) { if (*start == 0x39) { - // skip stack overflow check start += 11; } } else if (*start == 0x48 and start[1] == 0x39) { - // skip stack overflow check start += 12; } @@ -2611,7 +2610,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, } } - if (*instruction == 0xc3) { + if (*instruction == 0xc3) { // return *ip = reinterpret_cast(*stack)[0]; return; } @@ -2625,6 +2624,8 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, - StackAlignmentInWords; } + // check for post-non-tail-call stack adjustment of the form "add + // $offset,%rsp": if (BytesPerWord == 4) { if ((*instruction == 0x83 or *instruction == 0x81) and instruction[1] == 0xec) From 17449eaf1bdf53e6b48385b245ed2a60a6766ae0 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 28 Jan 2011 17:16:08 -0700 Subject: [PATCH 218/274] progress towards fixing the ARM build --- src/arm.cpp | 219 ++++++++++++++++++++++++++++++---------------- src/arm.h | 1 + src/compile-arm.S | 2 +- 3 files changed, 145 insertions(+), 77 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 768e1af9a7..990c08f89a 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -164,13 +164,12 @@ inline int carry16(intptr_t v) { return static_cast(v) < 0 ? 1 : 0; } inline bool isOfWidth(long long i, int size) { return static_cast(i) >> size == 0; } inline bool isOfWidth(int i, int size) { return static_cast(i) >> size == 0; } -const unsigned FrameHeaderSize = (UseFramePointer ? 2 : 1); +const unsigned FrameHeaderSize = 1; const unsigned StackAlignmentInBytes = 8; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int ThreadRegister = 8; -const int FrameRegister = 12; const int StackRegister = 13; const int LinkRegister = 14; const int ProgramCounter = 15; @@ -865,6 +864,51 @@ void subR(Context* con, unsigned size, Assembler::Register* a, Assembler::Regist } } +void +addC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + assert(c, size == BytesPerWord); + + int32_t v = a->value->value(); + if (v) { + if (v > 0 and v < 1024 and v % 4 == 0) { + emit(c, addi(dst->low, b->low, v >> 2, 15)); + } else { + emit(c, addi(dst->low, b->low, lo8(v))); + if (not isOfWidth(v, 8)) { + emit(c, addi(dst->low, b->low, hi8(v), 12)); + if (not isOfWidth(v, 16)) { + emit(c, addi(dst->low, b->low, lo8(hi16(v)), 8)); + if (not isOfWidth(v, 24)) { + emit(c, addi(dst->low, b->low, hi8(hi16(v)), 4)); + } + } + } + } + } else { + moveRR(c, size, b, size, dst); + } +} + +void +subC(Context* c, unsigned size, Assembler::Constant* a, + Assembler::Register* b, Assembler::Register* dst) +{ + assert(c, size == BytesPerWord); + + int32_t v = a->value->value(); + if (v > 0 and v < 256) { + emit(c, subi(dst->low, b->low, v)); + } else if (v > 0 and v < 1024 and v % 4 == 0) { + emit(c, subi(dst->low, b->low, v >> 2, 15)); + } else { + ResolvedPromise promise(- v); + Assembler::Constant constant(&promise); + addC(c, size, &constant, b, dst); + } +} + void multiplyR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { if (size == 8) { bool useTemporaries = b->low == t->low; @@ -1569,6 +1613,55 @@ memoryBarrier(Context*) {} // END OPERATION COMPILERS +void +nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, + unsigned footprint, int32_t*, void* link, void* stackLimit, + unsigned targetParameterFootprint UNUSED, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + (size / BytesPerWord)); + + uint32_t* instruction = static_cast(*ip); + + if ((*start >> 20) == 0xe59) { + // skip stack overflow check + start += 3; + } + + if (instruction <= start) { + *ip = link; + return; + } + + unsigned offset = footprint + FrameHeaderSize + - (stackLimit == *stack ? 1 : 0); + + if (instruction <= start + 2) { + *ip = link; + *stack = reinterpret_cast(*stack) + offset; + } + + if (*instruction == 0xe12fff1e) { // return + *ip = link; + return; + } + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + // todo: check for post-non-tail-call stack adjustment of the form + // "add sp, sp, #offset" + + // todo: use frameTable to check for and handle tail calls + } + + *ip = reinterpret_cast(*stack)[offset]; + *stack = reinterpret_cast(*stack) + offset; +} + void populateTables(ArchitectureContext* c) { @@ -1701,9 +1794,6 @@ class MyArchitecture: public Assembler::Architecture { virtual bool reserved(int register_) { switch (register_) { - case FrameRegister: - return UseFramePointer; - case LinkRegister: case StackRegister: case ThreadRegister: @@ -1788,6 +1878,15 @@ class MyArchitecture: public Assembler::Architecture { - FrameHeaderSize; } + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + int32_t* frameTable, void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + ::nextFrame(&c, static_cast(start), size, footprint, frameTable, + link, stackLimit, targetParameterFootprint, ip, stack); + } + virtual void* frameIp(void* stack) { return stack ? static_cast(stack)[returnAddressOffset()] : 0; } @@ -1809,7 +1908,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int framePointerOffset() { - return -2; + return 0; } virtual void nextFrame(void** stack, void**) { @@ -2010,14 +2109,6 @@ class MyAssembler: public Assembler { } virtual void saveFrame(unsigned stackOffset) { - appendFrameSizeEvent(&c, FrameSizePoison); - - // ??? - Register returnAddress(LinkRegister); - Memory returnAddressDst(StackRegister, - BytesPerWord); - moveAndUpdateRM(&c, BytesPerWord, &returnAddress, BytesPerWord, - &returnAddressDst); - Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); @@ -2053,7 +2144,7 @@ class MyAssembler: public Assembler { offset += ceiling(arguments[i].size, BytesPerWord); } else { - Memory dst(ThreadRegister, (offset + FrameFooterSize) * BytesPerWord); + Memory dst(StackRegister, offset * BytesPerWord); apply(Move, arguments[i].size, arguments[i].type, arguments[i].operand, @@ -2065,79 +2156,62 @@ class MyAssembler: public Assembler { } virtual void allocateFrame(unsigned footprint) { - Register stack(StackRegister); - Constant footprintConstant(resolved(&c, footprint * BytesPerWord)); - subCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack, - BytesPerWord, &stack); + footprint += FrameHeaderSize; - appendFrameSizeEvent(&c, footprint); + // larger frames may require multiple subtract/add instructions + // to allocate/deallocate, and nextFrame will need to be taught + // how to handle them: + assert(&c, footprint < 256); + + Register stack(StackRegister); + ResolvedPromise footprintPromise(footprint * BytesPerWord); + Constant footprintConstant(&footprintPromise); + subC(&c, BytesPerWord, &footprintConstant, &stack, &stack); Register returnAddress(LinkRegister); Memory returnAddressDst(StackRegister, (footprint - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); - - if (UseFramePointer) { - Register frame(FrameRegister); - Memory frameDst(StackRegister, (footprint - 2) * BytesPerWord); - moveRM(&c, BytesPerWord, &frame, BytesPerWord, &frameDst); - } } virtual void adjustFrame(unsigned difference) { - appendFrameSizeEvent(&c, - difference); - Register stack(StackRegister); - Constant differenceConstant(resolved(&c, difference * BytesPerWord)); - subCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack, - BytesPerWord, &stack); - - appendFrameSizeEvent(&c, difference); + ResolvedPromise differencePromise(difference * BytesPerWord); + Constant differenceConstant(&differencePromise); + subC(&c, BytesPerWord, &differenceConstant, &stack, &stack); } - virtual void popFrame(unsigned frameFootprint) { - if (UseFramePointer) { - Register frame(FrameRegister); - Memory frameSrc(StackRegister, (frameFootprint - 1) * BytesPerWord); - moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame); - } + virtual void popFrame(unsigned footprint) { + footprint += FrameHeaderSize; Register returnAddress(LinkRegister); - Memory returnAddressSrc - (StackRegister, (frameFootprint - 1) * BytesPerWord); + Memory returnAddressSrc(StackRegister, (footprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); Register stack(StackRegister); - Constant differenceConstant(resolved(&c, frameFootprint * BytesPerWord)); - addCR(&c, BytesPerWord, &differenceConstant, BytesPerWord, &stack, - BytesPerWord, &stack); - - appendFrameSizeEvent(&c, - frameFootprint); + ResolvedPromise footprintPromise(footprint * BytesPerWord); + Constant footprintConstant(&footprintPromise); + addC(&c, BytesPerWord, &footprintConstant, &stack, &stack); } virtual void popFrameForTailCall(unsigned footprint, int offset, int returnAddressSurrogate, - int framePointerSurrogate) + int framePointerSurrogate UNUSED) { + assert(&c, framePointerSurrogate == NoRegister); + if (TailCalls) { if (offset) { - if (UseFramePointer) { - Register frame(FrameRegister); - Memory frameSrc(StackRegister, (footprint - 1) * BytesPerWord); - moveMR(&c, BytesPerWord, &frameSrc, BytesPerWord, &frame); - } - Register link(LinkRegister); Memory returnAddressSrc (StackRegister, (footprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link); Register stack(StackRegister); - Constant footprintConstant - (resolved(&c, (footprint - offset + 1) * BytesPerWord)); - addCR(&c, BytesPerWord, &footprintConstant, BytesPerWord, &stack); - - appendFrameSizeEvent(&c, - (frameFootprint - offset + 1)); + ResolvedPromise footprintPromise + ((footprint - offset + 1) * BytesPerWord); + Constant footprintConstant(&footprintPromise); + addC(&c, BytesPerWord, &footprintConstant, &stack, &stack); if (returnAddressSurrogate != NoRegister) { assert(&c, offset > 0); @@ -2146,14 +2220,6 @@ class MyAssembler: public Assembler { Memory dst(StackRegister, (offset - 1) * BytesPerWord); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } - - if (framePointerSurrogate != NoRegister) { - assert(&c, offset > 0); - - Register las(framePointerSurrogate); - Memory dst(StackRegister, (offset - 2) * BytesPerWord); - moveRM(&c, BytesPerWord, &las, BytesPerWord, &dst); - } } else { popFrame(footprint); } @@ -2175,26 +2241,19 @@ class MyAssembler: public Assembler { offset = argumentFootprint - StackAlignmentInWords; Register stack(StackRegister); - Constant adjustment(resolved(&c, offset * BytesPerWord)); - addCR(&c, BytesPerWord, &adjustment, BytesPerWord, &stack); - - appendFrameSizeEvent(&c, - offset); + ResolvedPromise adjustmentPromise(offset * BytesPerWord); + Constant adjustment(&adjustmentPromise); + addC(&c, BytesPerWord, &adjustment, &stack, &stack); } else { offset = 0; } return_(&c); - - // todo: this is not necessary if there are no instructions to - // follow: - appendFrameSizeEvent(&c, frameFootprint + offset); } virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, unsigned stackOffsetFromThread) { - appendFrameSizeEvent(&c, FrameSizePoison); - popFrame(frameFootprint); Register stack(StackRegister); @@ -2372,6 +2431,14 @@ class MyAssembler: public Assembler { return c.code.length(); } + virtual unsigned frameEventCount() { + return 0; + } + + virtual FrameEvent* firstFrameEvent() { + return 0; + } + virtual void dispose() { c.code.dispose(); } diff --git a/src/arm.h b/src/arm.h index 198a76945f..e5b47b2d0a 100644 --- a/src/arm.h +++ b/src/arm.h @@ -19,6 +19,7 @@ #define IP_REGISTER(context) (context->uc_mcontext.arm_pc) #define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) #define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) +#define LINK_REGISTER(context) (context->uc_mcontext.arm_lr) extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, diff --git a/src/compile-arm.S b/src/compile-arm.S index ed66b222a1..102db1a541 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -22,7 +22,7 @@ # define GLOBAL(x) x #endif -#define THREAD_STACK 2152 +#define THREAD_STACK 2148 #define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 #define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 From fb5c0bfebd762258f7dc66baae85270a9a353e31 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 11:10:54 -0700 Subject: [PATCH 219/274] fix ARM stack unwinding --- src/arm.cpp | 48 ++++++++++++++++++++++++----------------------- src/compile-arm.S | 23 ++++++++--------------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 990c08f89a..8db2de4692 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -872,19 +872,13 @@ addC(Context* c, unsigned size, Assembler::Constant* a, int32_t v = a->value->value(); if (v) { - if (v > 0 and v < 1024 and v % 4 == 0) { + if (v > 0 and v < 256) { + emit(c, addi(dst->low, b->low, v)); + } else if (v > 0 and v < 1024 and v % 4 == 0) { emit(c, addi(dst->low, b->low, v >> 2, 15)); } else { - emit(c, addi(dst->low, b->low, lo8(v))); - if (not isOfWidth(v, 8)) { - emit(c, addi(dst->low, b->low, hi8(v), 12)); - if (not isOfWidth(v, 16)) { - emit(c, addi(dst->low, b->low, lo8(hi16(v)), 8)); - if (not isOfWidth(v, 24)) { - emit(c, addi(dst->low, b->low, hi8(hi16(v)), 4)); - } - } - } + // todo + abort(c); } } else { moveRR(c, size, b, size, dst); @@ -898,14 +892,17 @@ subC(Context* c, unsigned size, Assembler::Constant* a, assert(c, size == BytesPerWord); int32_t v = a->value->value(); - if (v > 0 and v < 256) { - emit(c, subi(dst->low, b->low, v)); - } else if (v > 0 and v < 1024 and v % 4 == 0) { - emit(c, subi(dst->low, b->low, v >> 2, 15)); + if (v) { + if (v > 0 and v < 256) { + emit(c, subi(dst->low, b->low, v)); + } else if (v > 0 and v < 1024 and v % 4 == 0) { + emit(c, subi(dst->low, b->low, v >> 2, 15)); + } else { + // todo + abort(c); + } } else { - ResolvedPromise promise(- v); - Assembler::Constant constant(&promise); - addC(c, size, &constant, b, dst); + moveRR(c, size, b, size, dst); } } @@ -1613,9 +1610,15 @@ memoryBarrier(Context*) {} // END OPERATION COMPILERS +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + void nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, - unsigned footprint, int32_t*, void* link, void* stackLimit, + unsigned footprint, int32_t*, void* link, void*, unsigned targetParameterFootprint UNUSED, void** ip, void** stack) { assert(c, *ip >= start); @@ -1633,8 +1636,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, return; } - unsigned offset = footprint + FrameHeaderSize - - (stackLimit == *stack ? 1 : 0); + unsigned offset = footprint + FrameHeaderSize; if (instruction <= start + 2) { *ip = link; @@ -1658,7 +1660,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, // todo: use frameTable to check for and handle tail calls } - *ip = reinterpret_cast(*stack)[offset]; + *ip = reinterpret_cast(*stack)[offset - 1]; *stack = reinterpret_cast(*stack) + offset; } @@ -1810,7 +1812,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return ::argumentFootprint(footprint); } virtual bool argumentAlignment() { diff --git a/src/compile-arm.S b/src/compile-arm.S index 102db1a541..a7b0963a49 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -23,6 +23,7 @@ #endif #define THREAD_STACK 2148 +#define THREAD_SCRATCH 2152 #define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 #define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 @@ -50,24 +51,20 @@ GLOBAL(vmInvoke): [sp, #4] : returnType */ - // save stack frame - mov ip, sp - // save all non-volatile registers stmfd sp!, {r4-r11, lr} // save return type - ldr r4, [ip, #4] + ldr r4, [sp, #4] str r4, [sp, #-4]! - // we're at the bottom of our local stack frame; save it - mov ip, sp + str sp, [r0, #THREAD_SCRATCH] // align stack, if necessary eor r4, sp, r3 tst r4, #4 subne sp, sp, #4 - + // copy arguments into place sub sp, r3 mov r4, #0 @@ -82,9 +79,6 @@ LOCAL(vmInvoke_argumentTest): cmp r4, r3 blt LOCAL(vmInvoke_argumentLoop) - // save frame - str ip, [sp, #-8]! - // we use r8 to hold the thread pointer, by convention mov r8, r0 @@ -93,17 +87,16 @@ LOCAL(vmInvoke_argumentTest): .globl GLOBAL(vmInvoke_returnAddress) GLOBAL(vmInvoke_returnAddress): - - // restore frame - ldr sp, [sp] + // restore stack pointer + ldr sp, [r8, #THREAD_SCRATCH] // clear MyThread::stack to avoid confusing another thread calling // java.lang.Thread.getStackTrace on this one. See // MyProcess::getStackTrace in compile.cpp for details on how we get // a reliable stack trace from a thread that might be interrupted at // any point in its execution. - mov r5,#0 - str r5,[r8,#THREAD_STACK] + mov r5, #0 + str r5, [r8, #THREAD_STACK] .globl GLOBAL(vmInvoke_safeStack) GLOBAL(vmInvoke_safeStack): From 1186413be26ac42675b29801e3bc07be93d90fb5 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 11:11:27 -0700 Subject: [PATCH 220/274] debug logging tweaks in compile.cpp --- src/compile.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index afe20a7c95..67e2644263 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -437,7 +437,7 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) javaStackLimit = 0; } - // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s\n", + // fprintf(stderr, "nextFrame %s.%s%s target %s.%s%s ip %p sp %p\n", // &byteArrayBody(t, className(t, methodClass(t, method)), 0), // &byteArrayBody(t, methodName(t, method), 0), // &byteArrayBody(t, methodSpec(t, method), 0), @@ -449,13 +449,16 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) // : 0, // target // ? &byteArrayBody(t, methodSpec(t, target), 0) - // : 0); + // : 0, + // *ip, *sp); t->arch->nextFrame (reinterpret_cast(start), compiledSize(start), alignedFrameSize(t, method), table ? &intArrayBody(t, table, 0) : 0, link, javaStackLimit, target ? methodParameterFootprint(t, target) : -1, ip, sp); + + // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); } class MyStackWalker: public Processor::StackWalker { From 03f18ea00c5742a024a91136567107d5a4e29c9d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 18:07:52 -0700 Subject: [PATCH 221/274] change reinterpret_casts to static_casts in x86.cpp where appropriate --- src/x86.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index a52fdc5da2..c2432e2ad8 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2595,7 +2595,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, } if (instruction <= start) { - *ip = reinterpret_cast(*stack)[0]; + *ip = static_cast(*stack)[0]; return; } @@ -2604,14 +2604,14 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, start += (BytesPerWord == 4 ? 3 : 4); if (instruction <= start or *instruction == 0x5d) { - *ip = reinterpret_cast(*stack)[1]; - *stack = reinterpret_cast(*stack) + 1; + *ip = static_cast(*stack)[1]; + *stack = static_cast(*stack) + 1; return; } } if (*instruction == 0xc3) { // return - *ip = reinterpret_cast(*stack)[0]; + *ip = static_cast(*stack)[0]; return; } @@ -2646,8 +2646,8 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, // todo: use frameTable to check for and handle tail calls } - *ip = reinterpret_cast(*stack)[offset]; - *stack = reinterpret_cast(*stack) + offset; + *ip = static_cast(*stack)[offset]; + *stack = static_cast(*stack) + offset; } void From 6296350d7616f6b45546415caf7bc8e8b13717ef Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 18:09:47 -0700 Subject: [PATCH 222/274] fix ARM tails=true and continuations=true builds --- src/arm.cpp | 29 ++++++++++++++++++++--------- src/compile-arm.S | 44 +++++++++++--------------------------------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 8db2de4692..4abb6cf17e 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1617,7 +1617,7 @@ argumentFootprint(unsigned footprint) } void -nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, +nextFrame(ArchitectureContext* c, uint32_t* start, unsigned size UNUSED, unsigned footprint, int32_t*, void* link, void*, unsigned targetParameterFootprint UNUSED, void** ip, void** stack) { @@ -1640,7 +1640,8 @@ nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, if (instruction <= start + 2) { *ip = link; - *stack = reinterpret_cast(*stack) + offset; + *stack = static_cast(*stack) + offset; + return; } if (*instruction == 0xe12fff1e) { // return @@ -1654,14 +1655,23 @@ nextFrame(ArchitectureContext* c UNUSED, uint32_t* start, unsigned size UNUSED, - StackAlignmentInWords; } - // todo: check for post-non-tail-call stack adjustment of the form - // "add sp, sp, #offset" + // check for post-non-tail-call stack adjustment of the form "add + // sp, sp, #offset": + if ((*instruction >> 12) == 0xe24dd) { + unsigned value = *instruction & 0xff; + unsigned rotation = (*instruction >> 8) & 0xf; + switch (rotation) { + case 0: offset -= value / BytesPerWord; break; + case 15: offset -= value; break; + default: abort(c); + } + } - // todo: use frameTable to check for and handle tail calls + // todo: check for and handle tail calls } - *ip = reinterpret_cast(*stack)[offset - 1]; - *stack = reinterpret_cast(*stack) + offset; + *ip = static_cast(*stack)[offset - 1]; + *stack = static_cast(*stack) + offset; } void @@ -2204,14 +2214,15 @@ class MyAssembler: public Assembler { if (TailCalls) { if (offset) { + footprint += FrameHeaderSize; + Register link(LinkRegister); Memory returnAddressSrc (StackRegister, (footprint - 1) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &link); Register stack(StackRegister); - ResolvedPromise footprintPromise - ((footprint - offset + 1) * BytesPerWord); + ResolvedPromise footprintPromise((footprint - offset) * BytesPerWord); Constant footprintConstant(&footprintPromise); addC(&c, BytesPerWord, &footprintConstant, &stack, &stack); diff --git a/src/compile-arm.S b/src/compile-arm.S index a7b0963a49..8af887fdbb 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -36,8 +36,6 @@ #define CONTINUATION_FRAME_POINTER_OFFSET 24 #define CONTINUATION_LENGTH 28 #define CONTINUATION_BODY 32 - -#define ARGUMENT_BASE (BYTES_PER_WORD * 2) .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): @@ -117,12 +115,11 @@ GLOBAL(vmInvoke_safeStack): add r7,r5,#CONTINUATION_BODY mov r11,#0 - add r10,sp,#ARGUMENT_BASE b LOCAL(vmInvoke_continuationTest) LOCAL(vmInvoke_continuationLoop): ldr r9,[r7,r11] - str r9,[r10,r11] + str r9,[sp,r11] add r11,r11,#4 LOCAL(vmInvoke_continuationTest): @@ -137,12 +134,6 @@ LOCAL(vmInvoke_getAddress): ldr r11,[r11,r10] str r11,[sp,r7] - ldr r7,[r5,#CONTINUATION_FRAME_POINTER_OFFSET] - ldr r11,[sp] - add r7,r7,sp - str r11,[r7] - str r7,[sp] - ldr r7,[r5,#CONTINUATION_NEXT] str r7,[r8,#THREAD_CONTINUATION] @@ -198,40 +189,27 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r0: thread // r1: address - // r2: (unused) - // r3: stack - // [sp,#0]: argumentFootprint - // [sp,#4]: arguments - // [sp,#8]: frameSize + // r2: stack + // r3: argumentFootprint + // [sp,#0]: arguments + // [sp,#4]: frameSize - ldr r4,[sp] - ldr r5,[sp,#4] - ldr r6,[sp,#8] - - // restore (pseudo)-stack pointer (we don't want to touch the real - // stack pointer, since we haven't copied the arguments yet) - ldr r3,[r3] - - // make everything between sp and r3 one big stack frame while we - // shuffle things around - str r3,[sp] + ldr r5,[sp,#0] + ldr r6,[sp,#4] // allocate new frame, adding room for callee-saved registers - neg r10,r6 - add r10,r10,#-80 - mov r2,r3 - str r2,[r3,r10]! + sub r2,r2,r6 + sub r2,r2,#80 mov r8,r0 // copy arguments into place mov r6,#0 - add r9,r3,#ARGUMENT_BASE b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): ldr r12,[r5,r6] - str r12,[r9,r6] + str r12,[r2,r6] add r6,r6,#4 LOCAL(vmJumpAndInvoke_argumentTest): @@ -240,7 +218,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): // the arguments have been copied, so we can set the real stack // pointer now - mov sp,r3 + mov sp,r2 // set return address to vmInvoke_returnAddress ldr r10,LOCAL(vmInvoke_returnAddress_word) From 8064b702c01147df1ac0761cfad5755f995e618a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 20:03:28 -0700 Subject: [PATCH 223/274] use parentheses around VA_LIST value in x86.h --- src/x86.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.h b/src/x86.h index ec90c7befb..d52f7c875e 100644 --- a/src/x86.h +++ b/src/x86.h @@ -22,7 +22,7 @@ # undef interface #endif -#define VA_LIST(x) x +#define VA_LIST(x) (x) #ifdef ARCH_x86_32 From 1187613ad01008ab1287b18eae53d09e2f455730 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 29 Jan 2011 20:04:29 -0700 Subject: [PATCH 224/274] partial fix for PowerPC build --- src/compile-powerpc.S | 10 ++--- src/powerpc.S | 89 +++++++++++++++++++++++++++++++++++------ src/powerpc.cpp | 93 ++++++++++++++++++++++++++++++++++++++----- src/powerpc.h | 8 ++-- 4 files changed, 170 insertions(+), 30 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index d0cf0e14f4..e760287f1e 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,12 +24,12 @@ # define GLOBAL(x) x #endif -#define THREAD_STACK 2144 -#define THREAD_CONTINUATION 2148 +#define THREAD_STACK 2148 +#define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 -#define THREAD_EXCEPTION_OFFSET 2156 -#define THREAD_EXCEPTION_HANDLER 2160 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 diff --git a/src/powerpc.S b/src/powerpc.S index fce2079af7..b8034f5a7a 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -17,14 +17,15 @@ #define GPR_COUNT 8 #define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) #define LOCAL(x) L##x - + #ifdef __APPLE__ -.globl _vmNativeCall -_vmNativeCall: +# define GLOBAL(x) _##x #else -.globl vmNativeCall -vmNativeCall: +# define GLOBAL(x) x #endif + +.globl GLOBAL(vmNativeCall) +GLOBAL(vmNativeCall): // save return address mflr r0 stw r0,8(r1) @@ -151,16 +152,80 @@ LOCAL(exit): // return blr -#ifdef __APPLE__ -.globl _vmJump -_vmJump: -#else -.globl vmJump -vmJump: -#endif +.globl GLOBAL(vmJump) +GLOBAL(vmJump): mtlr r3 mr r1,r5 mr r13,r6 mr r4,r7 mr r3,r8 blr + +#define CHECKPOINT_THREAD 4 +#define CHECKPOINT_STACK 24 + +.globl GLOBAL(vmRun) +GLOBAL(vmRun): + // r3: function + // r4: arguments + // r5: checkpoint + + mflr r0 + stw r0,8(r1) + + stwu r1,-(MEMORY_BASE+80)(r1) + + stw r13,MEMORY_BASE+0(r1) + stw r14,MEMORY_BASE+4(r1) + stw r15,MEMORY_BASE+8(r1) + stw r16,MEMORY_BASE+12(r1) + stw r17,MEMORY_BASE+16(r1) + stw r18,MEMORY_BASE+20(r1) + stw r19,MEMORY_BASE+24(r1) + stw r20,MEMORY_BASE+28(r1) + stw r21,MEMORY_BASE+32(r1) + stw r22,MEMORY_BASE+36(r1) + stw r23,MEMORY_BASE+40(r1) + stw r24,MEMORY_BASE+44(r1) + stw r25,MEMORY_BASE+48(r1) + stw r26,MEMORY_BASE+52(r1) + stw r27,MEMORY_BASE+56(r1) + stw r28,MEMORY_BASE+60(r1) + stw r29,MEMORY_BASE+64(r1) + stw r30,MEMORY_BASE+68(r1) + stw r31,MEMORY_BASE+72(r1) + + stw r1,CHECKPOINT_STACK(r5) + + mr r6,r3 + lwz r3,CHECKPOINT_THREAD(r5) + + mtctr r6 + bctrl + +.globl GLOBAL(vmRun_returnAddress) +GLOBAL(vmRun_returnAddress): + lwz r13,MEMORY_BASE+0(r1) + lwz r14,MEMORY_BASE+4(r1) + lwz r15,MEMORY_BASE+8(r1) + lwz r16,MEMORY_BASE+12(r1) + lwz r17,MEMORY_BASE+16(r1) + lwz r18,MEMORY_BASE+20(r1) + lwz r19,MEMORY_BASE+24(r1) + lwz r20,MEMORY_BASE+28(r1) + lwz r21,MEMORY_BASE+32(r1) + lwz r22,MEMORY_BASE+36(r1) + lwz r23,MEMORY_BASE+40(r1) + lwz r24,MEMORY_BASE+44(r1) + lwz r25,MEMORY_BASE+48(r1) + lwz r26,MEMORY_BASE+52(r1) + lwz r27,MEMORY_BASE+56(r1) + lwz r28,MEMORY_BASE+60(r1) + lwz r29,MEMORY_BASE+64(r1) + lwz r30,MEMORY_BASE+68(r1) + lwz r31,MEMORY_BASE+72(r1) + + lwz r1,0(r1) + lwz r0,8(r1) + mtlr r0 + blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 9973ccc544..be5cfac378 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1691,6 +1691,55 @@ memoryBarrier(Context* c) // END OPERATION COMPILERS +unsigned +argumentFootprint(unsigned footprint) +{ + return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); +} + +void +nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size UNUSED, + unsigned footprint, int32_t*, void* link, void*, + unsigned targetParameterFootprint, void** ip, void** stack) +{ + assert(c, *ip >= start); + assert(c, *ip <= start + (size / BytesPerWord)); + + int32_t* instruction = static_cast(*ip); + + if ((*start >> 26) == 32) { + // skip stack overflow check + start += 3; + } + + if (instruction <= start + 2 + or *instruction == lwz(0, 1, 8) + or *instruction == mtlr(0) + or *instruction == blr()) + { + *ip = link; + return; + } + + unsigned offset = footprint; + + if (TailCalls) { + if (argumentFootprint(targetParameterFootprint) > StackAlignmentInWords) { + offset += argumentFootprint(targetParameterFootprint) + - StackAlignmentInWords; + } + + // check for post-non-tail-call stack adjustment of the form "lwzx + // r0,0(r1); stwux r0,offset(r1)": + + // todo + + // todo: check for and handle tail calls + } + + *ip = static_cast(*stack)[offset + 2]; + *stack = static_cast(*stack) + offset; +} void populateTables(ArchitectureContext* c) @@ -1847,7 +1896,11 @@ class MyArchitecture: public Assembler::Architecture { } virtual unsigned argumentFootprint(unsigned footprint) { - return max(pad(footprint, StackAlignmentInWords), StackAlignmentInWords); + return ::argumentFootprint(footprint); + } + + virtual bool argumentAlignment() { + return false; } virtual unsigned argumentRegisterCount() { @@ -1916,6 +1969,15 @@ class MyArchitecture: public Assembler::Architecture { return (ceiling(sizeInWords + FrameFooterSize, alignment) * alignment); } + virtual void nextFrame(void* start, unsigned size, unsigned footprint, + int32_t* frameTable, void* link, void* stackLimit, + unsigned targetParameterFootprint, void** ip, + void** stack) + { + ::nextFrame(&c, static_cast(start), size, footprint, frameTable, + link, stackLimit, targetParameterFootprint, ip, stack); + } + virtual void* frameIp(void* stack) { return stack ? static_cast(stack)[2] : 0; } @@ -2141,7 +2203,7 @@ class MyAssembler: public Assembler { return arch_; } - virtual void saveFrame(unsigned stackOffset, unsigned) { + virtual void saveFrame(unsigned stackOffset) { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); @@ -2206,16 +2268,16 @@ class MyAssembler: public Assembler { moveAndUpdateRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); } - virtual void adjustFrame(unsigned footprint) { + virtual void adjustFrame(unsigned difference) { Register nextStack(0); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &nextStack); - Memory stackDst(StackRegister, -footprint * BytesPerWord); + Memory stackDst(StackRegister, -difference * BytesPerWord); moveAndUpdateRM(&c, BytesPerWord, &nextStack, BytesPerWord, &stackDst); } - virtual void popFrame() { + virtual void popFrame(unsigned) { Register stack(StackRegister); Memory stackSrc(StackRegister, 0); moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); @@ -2262,15 +2324,17 @@ class MyAssembler: public Assembler { moveRM(&c, BytesPerWord, &fps, BytesPerWord, &dst); } } else { - popFrame(); + popFrame(footprint); } } else { abort(&c); } } - virtual void popFrameAndPopArgumentsAndReturn(unsigned argumentFootprint) { - popFrame(); + virtual void popFrameAndPopArgumentsAndReturn(unsigned frameFootprint, + unsigned argumentFootprint) + { + popFrame(frameFootprint); assert(&c, argumentFootprint >= StackAlignmentInWords); assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); @@ -2289,9 +2353,10 @@ class MyAssembler: public Assembler { return_(&c); } - virtual void popFrameAndUpdateStackAndReturn(unsigned stackOffsetFromThread) + virtual void popFrameAndUpdateStackAndReturn(unsigned frameFootprint, + unsigned stackOffsetFromThread) { - popFrame(); + popFrame(frameFootprint); Register tmp1(0); Memory stackSrc(StackRegister, 0); @@ -2401,6 +2466,14 @@ class MyAssembler: public Assembler { return c.code.length(); } + virtual unsigned frameEventCount() { + return 0; + } + + virtual FrameEvent* firstFrameEvent() { + return 0; + } + virtual void dispose() { c.code.dispose(); } diff --git a/src/powerpc.h b/src/powerpc.h index c5bf0613b5..fb84daf10a 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,20 +14,22 @@ #include "types.h" #include "common.h" +#define VA_LIST(x) (x) + #ifdef __APPLE__ # if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) # define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) # define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) # define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r13) +# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__lr) # else # define IP_REGISTER(context) (context->uc_mcontext->ss.srr0) # define STACK_REGISTER(context) (context->uc_mcontext->ss.r1) # define THREAD_REGISTER(context) (context->uc_mcontext->ss.r13) +# define LINK_REGISTER(context) (context->uc_mcontext->ss.lr) # endif #else -# define IP_REGISTER(context) (context->uc_mcontext.gregs[32]) -# define STACK_REGISTER(context) (context->uc_mcontext.gregs[1]) -# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[13]) +# error "non-Apple PowerPC-based platforms not yet supported" #endif extern "C" uint64_t From fff51bad063cfbefb7c96b755a9f4ad24e873aec Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 30 Jan 2011 14:14:57 -0700 Subject: [PATCH 225/274] more progress on PowerPC build Also, hide frame mapping for stack unwinding (which is still incomplete) in x86.cpp, since no other platform needs it. --- src/arm.cpp | 32 ++++++++++--------- src/assembler.h | 14 +++----- src/compile.cpp | 67 ++------------------------------------ src/compiler.cpp | 9 ++---- src/machine.cpp | 4 +-- src/powerpc.cpp | 83 ++++++++++++++++++++++++++++++++++++------------ src/types.def | 1 - src/x86.cpp | 63 +++++++++++++++++------------------- 8 files changed, 121 insertions(+), 152 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 4abb6cf17e..d0bb5f02c7 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1618,7 +1618,7 @@ argumentFootprint(unsigned footprint) void nextFrame(ArchitectureContext* c, uint32_t* start, unsigned size UNUSED, - unsigned footprint, int32_t*, void* link, void*, + unsigned footprint, void* link, void*, unsigned targetParameterFootprint UNUSED, void** ip, void** stack) { assert(c, *ip >= start); @@ -1891,12 +1891,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - int32_t* frameTable, void* link, void* stackLimit, + void* link, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { - ::nextFrame(&c, static_cast(start), size, footprint, frameTable, - link, stackLimit, targetParameterFootprint, ip, stack); + ::nextFrame(&c, static_cast(start), size, footprint, link, + stackLimit, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -1923,12 +1923,6 @@ class MyArchitecture: public Assembler::Architecture { return 0; } - virtual void nextFrame(void** stack, void**) { - assert(&c, *static_cast(*stack) != *stack); - - *stack = *static_cast(*stack); - } - virtual BinaryOperation hasBinaryIntrinsic(Thread*, object) { return NoBinaryOperation; } @@ -2120,6 +2114,18 @@ class MyAssembler: public Assembler { return arch_; } + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(StackRegister); + Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); + Constant handlerConstant + (new (c.zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + virtual void saveFrame(unsigned stackOffset) { Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); @@ -2444,11 +2450,7 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual unsigned frameEventCount() { - return 0; - } - - virtual FrameEvent* firstFrameEvent() { + virtual unsigned footerSize() { return 0; } diff --git a/src/assembler.h b/src/assembler.h index 7edc0b9001..d122a53207 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -304,12 +304,6 @@ class Assembler { virtual unsigned resolve(unsigned start, Block* next) = 0; }; - class FrameEvent { - public: - virtual unsigned offset() = 0; - virtual FrameEvent* next() = 0; - }; - class Architecture { public: virtual unsigned floatRegisterSize() = 0; @@ -351,7 +345,7 @@ class Assembler { virtual unsigned alignFrameSize(unsigned sizeInWords) = 0; virtual void nextFrame(void* start, unsigned size, unsigned footprint, - int32_t* frameTable, void* link, void* stackLimit, + void* link, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) = 0; virtual void* frameIp(void* stack) = 0; @@ -401,6 +395,8 @@ class Assembler { virtual Architecture* arch() = 0; + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) = 0; virtual void saveFrame(unsigned stackOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; @@ -440,9 +436,7 @@ class Assembler { virtual unsigned length() = 0; - virtual unsigned frameEventCount() = 0; - - virtual FrameEvent* firstFrameEvent() = 0; + virtual unsigned footerSize() = 0; virtual void dispose() = 0; }; diff --git a/src/compile.cpp b/src/compile.cpp index 67e2644263..cb4bd365d2 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -396,35 +396,10 @@ alignedFrameSize(MyThread* t, object method) + t->arch->frameFootprint(MaxNativeCallFootprint)); } -unsigned -bitsNeeded(unsigned v) -{ - return log(v + 1); -} - -void -setTableValue(Thread* t, object table, unsigned base, unsigned max, - unsigned index, unsigned value) -{ - unsigned bits = bitsNeeded(max); - setBits - (&intArrayBody(t, table, base), bits, index * bits, value); -} - -unsigned -getTableValue(Thread* t, object table, unsigned base, unsigned max, - unsigned index) -{ - unsigned bits = bitsNeeded(max); - return getBits - (&intArrayBody(t, table, base), bits, index * bits); -} - void nextFrame(MyThread* t, void** ip, void** sp, object method, object target) { object code = methodCode(t, method); - object table = codeFrameTable(t, code); intptr_t start = codeCompiled(t, code); void* link; void* javaStackLimit; @@ -454,9 +429,8 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) t->arch->nextFrame (reinterpret_cast(start), compiledSize(start), - alignedFrameSize(t, method), table ? &intArrayBody(t, table, 0) : 0, - link, javaStackLimit, target ? methodParameterFootprint(t, target) : -1, - ip, sp); + alignedFrameSize(t, method), link, javaStackLimit, + target ? methodParameterFootprint(t, target) : -1, ip, sp); // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); } @@ -5226,37 +5200,6 @@ translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start) } } -object -makeFrameTable(MyThread* t, Context* c, unsigned codeSize) -{ - Assembler* a = c->assembler; - unsigned count = a->frameEventCount(); - if (count == 0) { - return 0; - } - - unsigned size = ceiling(count * bitsNeeded(codeSize), 32); - object table = makeIntArray(t, 1 + size); - - intArrayBody(t, table, 0) = count; - - unsigned index = 0; - for (Assembler::FrameEvent* e = a->firstFrameEvent(); - e; e = e->next()) - { - assert(t, index < count); - - unsigned offset = e->offset(); - assert(t, offset <= codeSize); - - setTableValue(t, table, 1, codeSize, index, offset); - - ++ index; - } - - return table; -} - void printSet(uintptr_t m, unsigned limit) { @@ -5943,14 +5886,10 @@ finish(MyThread* t, Allocator* allocator, Context* context) (t, c, methodCode(t, context->method), reinterpret_cast(start)); - PROTECT(t, newLineNumberTable); - - object frameTable = makeFrameTable(t, context, codeSize); - object code = methodCode(t, context->method); code = makeCode - (t, 0, newExceptionHandlerTable, newLineNumberTable, frameTable, + (t, 0, newExceptionHandlerTable, newLineNumberTable, reinterpret_cast(start), codeMaxStack(t, code), codeMaxLocals(t, code), 0); diff --git a/src/compiler.cpp b/src/compiler.cpp index 65b5437cad..18dc98e06f 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -5720,12 +5720,7 @@ compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) Block* block = firstBlock; if (stackOverflowHandler) { - Assembler::Register stack(c->arch->stack()); - Assembler::Memory stackLimit(c->arch->thread(), stackLimitOffset); - Assembler::Constant handler(resolved(c, stackOverflowHandler)); - a->apply(JumpIfGreaterOrEqual, BytesPerWord, RegisterOperand, &stack, - BytesPerWord, MemoryOperand, &stackLimit, - BytesPerWord, ConstantOperand, &handler); + a->checkStackOverflow(stackOverflowHandler, stackLimitOffset); } a->allocateFrame(c->alignedFrameSize); @@ -5854,7 +5849,7 @@ compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) block = next; } - return block->assemblerBlock->resolve(block->start, 0); + return block->assemblerBlock->resolve(block->start, 0) + a->footerSize(); } unsigned diff --git a/src/machine.cpp b/src/machine.cpp index 21338c441b..da705b5db6 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1227,7 +1227,7 @@ parseCode(Thread* t, Stream& s, object pool) unsigned maxLocals = s.read2(); unsigned length = s.read4(); - object code = makeCode(t, pool, 0, 0, 0, 0, maxStack, maxLocals, length); + object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length); s.read(&codeBody(t, code, 0), length); PROTECT(t, code); @@ -2065,7 +2065,7 @@ boot(Thread* t) m->processor->boot(t, 0); - { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 1); + { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1); codeBody(t, bootCode, 0) = impdep1; object bootMethod = makeMethod (t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode); diff --git a/src/powerpc.cpp b/src/powerpc.cpp index be5cfac378..55c2658dc0 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -191,13 +191,15 @@ class MyBlock: public Assembler::Block { class Task; class ConstantPoolEntry; +class JumpPromise; class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), constantPool(0), constantPoolCount(0) + lastBlock(firstBlock), constantPool(0), jumps(0), constantPoolCount(0), + jumpCount(0) { } System* s; @@ -209,7 +211,9 @@ class Context { MyBlock* firstBlock; MyBlock* lastBlock; ConstantPoolEntry* constantPool; + JumpPromise* jumps; unsigned constantPoolCount; + unsigned jumpCount; }; class Task { @@ -312,6 +316,38 @@ offset(Context* c) Offset(c, c->lastBlock, c->code.length()); } +class JumpPromise: public Promise { + public: + JumpPromise(Context* c, uintptr_t target): + c(c), target(target), next(c->jumps), index(c->jumpCount++) + { + c->jumps = this; + } + + virtual bool resolved() { + return c->result != 0; + } + + virtual int64_t value() { + assert(c, resolved()); + + return reinterpret_cast + (c->result + c->code.length() + (index * BytesPerWord)); + } + + Context* c; + uintptr_t target; + JumpPromise* next; + unsigned index; +}; + +Promise* +jump(Context* c, uintptr_t target) +{ + return new (c->zone->allocate(sizeof(JumpPromise))) + JumpPromise(c, target); +} + bool bounded(int right, int left, int32_t v) { @@ -659,7 +695,6 @@ class ConstantPoolEntry: public Promise { Promise* constant; ConstantPoolEntry* next; void* address; - unsigned constantPoolCount; }; ConstantPoolEntry* @@ -1699,7 +1734,7 @@ argumentFootprint(unsigned footprint) void nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size UNUSED, - unsigned footprint, int32_t*, void* link, void*, + unsigned footprint, void* link, void*, unsigned targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); @@ -1970,12 +2005,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - int32_t* frameTable, void* link, void* stackLimit, + void* link, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { - ::nextFrame(&c, static_cast(start), size, footprint, frameTable, - link, stackLimit, targetParameterFootprint, ip, stack); + ::nextFrame(&c, static_cast(start), size, footprint, link, + stackLimit, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -2002,12 +2037,6 @@ class MyArchitecture: public Assembler::Architecture { return 0; } - virtual void nextFrame(void** stack, void**) { - assert(&c, *static_cast(*stack) != *stack); - - *stack = *static_cast(*stack); - } - virtual BinaryOperation hasBinaryIntrinsic(Thread*, object) { return NoBinaryOperation; } @@ -2203,6 +2232,16 @@ class MyAssembler: public Assembler { return arch_; } + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(StackRegister); + Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); + Constant handlerConstant(jump(&c, handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + virtual void saveFrame(unsigned stackOffset) { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); @@ -2420,12 +2459,20 @@ class MyAssembler: public Assembler { virtual void writeTo(uint8_t* dst) { c.result = dst; - + for (MyBlock* b = c.firstBlock; b; b = b->next) { memcpy(dst + b->start, c.code.data + b->offset, b->size); } + + for (JumpPromise* j = c.jumps; j; j = j->next) { + uint8_t* instruction + = dst + c.code.length() + (c.jumpCount - j->index - 1); + int32_t op = ::b(0); + memcpy(instruction, &op, BytesPerWord); + updateOffset(c.s, instruction, false, j->target); + } - unsigned index = c.code.length(); + unsigned index = c.code.length() + (c.jumpCount * BytesPerWord); assert(&c, index % BytesPerWord == 0); for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { e->address = dst + index; @@ -2466,12 +2513,8 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual unsigned frameEventCount() { - return 0; - } - - virtual FrameEvent* firstFrameEvent() { - return 0; + virtual unsigned footerSize() { + return (c.jumpCount + c.constantPoolCount) * BytesPerWord; } virtual void dispose() { diff --git a/src/types.def b/src/types.def index 24d4b1854c..8b8d980ffc 100644 --- a/src/types.def +++ b/src/types.def @@ -86,7 +86,6 @@ (object pool) (object exceptionHandlerTable) (object lineNumberTable) - (object frameTable) (intptr_t compiled) (uint16_t maxStack) (uint16_t maxLocals) diff --git a/src/x86.cpp b/src/x86.cpp index c2432e2ad8..0f7a672459 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -86,7 +86,7 @@ isInt32(intptr_t v) class Task; class AlignmentPadding; -class MyFrameEvent; +class FrameEvent; unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, @@ -115,8 +115,8 @@ class MyBlock: public Assembler::Block { MyBlock* next; AlignmentPadding* firstPadding; AlignmentPadding* lastPadding; - MyFrameEvent* firstFrameEvent; - MyFrameEvent* lastFrameEvent; + FrameEvent* firstFrameEvent; + FrameEvent* lastFrameEvent; unsigned offset; unsigned start; unsigned size; @@ -171,8 +171,8 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; - MyFrameEvent* firstFrameEvent; - MyFrameEvent* lastFrameEvent; + FrameEvent* firstFrameEvent; + FrameEvent* lastFrameEvent; ArchitectureContext* ac; unsigned frameEventCount; }; @@ -461,33 +461,25 @@ padding(AlignmentPadding* p, unsigned start, unsigned offset, return padding; } -class MyFrameEvent: public Assembler::FrameEvent { +class FrameEvent { public: - MyFrameEvent(Context* c, Promise* offset): - c(c), next_(0), offset_(offset) + FrameEvent(Context* c, Promise* offset): + c(c), next(0), offset(offset) { } - virtual unsigned offset() { - return offset_->value(); - } - - virtual Assembler::FrameEvent* next() { - return next_; - } - Context* c; - MyFrameEvent* next_; - Promise* offset_; + FrameEvent* next; + Promise* offset; }; void appendFrameEvent(Context* c, MyBlock* b, Promise* offset) { - MyFrameEvent* e = new (c->zone->allocate(sizeof(MyFrameEvent))) - MyFrameEvent(c, offset); + FrameEvent* e = new (c->zone->allocate(sizeof(FrameEvent))) + FrameEvent(c, offset); if (b->firstFrameEvent) { - b->lastFrameEvent->next_ = e; + b->lastFrameEvent->next = e; } else { b->firstFrameEvent = e; } @@ -2577,7 +2569,7 @@ read4(uint8_t* p) void nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, - unsigned footprint, int32_t*, void*, void* stackLimit, + unsigned footprint, void*, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { assert(c, *ip >= start); @@ -2643,7 +2635,7 @@ nextFrame(ArchitectureContext* c UNUSED, uint8_t* start, unsigned size UNUSED, / BytesPerWord; } - // todo: use frameTable to check for and handle tail calls + // todo: check for and handle tail calls } *ip = static_cast(*stack)[offset]; @@ -2977,13 +2969,12 @@ class MyArchitecture: public Assembler::Architecture { } virtual void nextFrame(void* start, unsigned size, unsigned footprint, - int32_t* frameTable, void* link, void* stackLimit, + void* link, void* stackLimit, unsigned targetParameterFootprint, void** ip, void** stack) { local::nextFrame(&c, static_cast(start), size, footprint, - frameTable, link, stackLimit, targetParameterFootprint, - ip, stack); + link, stackLimit, targetParameterFootprint, ip, stack); } virtual void* frameIp(void* stack) { @@ -3421,6 +3412,16 @@ class MyAssembler: public Assembler { return arch_; } + virtual void checkStackOverflow(uintptr_t handler, + unsigned stackLimitOffsetFromThread) + { + Register stack(rsp); + Memory stackLimit(rbx, stackLimitOffsetFromThread); + Constant handlerConstant(resolved(&c, handler)); + branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, + &handlerConstant); + } + virtual void saveFrame(unsigned stackOffset) { Register stack(rsp); Memory stackDst(rbx, stackOffset); @@ -3661,7 +3662,7 @@ class MyAssembler: public Assembler { for (MyBlock* b = c.firstBlock; b; b = b->next) { if (b->firstFrameEvent) { if (c.firstFrameEvent) { - c.lastFrameEvent->next_ = b->firstFrameEvent; + c.lastFrameEvent->next = b->firstFrameEvent; } else { c.firstFrameEvent = b->firstFrameEvent; } @@ -3721,12 +3722,8 @@ class MyAssembler: public Assembler { return c.code.length(); } - virtual unsigned frameEventCount() { - return c.frameEventCount; - } - - virtual FrameEvent* firstFrameEvent() { - return c.firstFrameEvent; + virtual unsigned footerSize() { + return 0; } virtual void dispose() { From 8a46ee92b47adbe4d77d6d45d882c01d71989806 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 30 Jan 2011 14:28:02 -0700 Subject: [PATCH 226/274] use thunks for integer division on PowerPC PowerPC doesn't generate traps for divides-by-zero, so we defer to thunks which do explicit checks. --- src/powerpc.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 55c2658dc0..e6be245100 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2158,7 +2158,13 @@ class MyArchitecture: public Assembler::Architecture { case Divide: case Remainder: - if (BytesPerWord == 4 and aSize == 8) { + // todo: we shouldn't need to defer to thunks for integers which + // are smaller than or equal to tne native word size, but + // PowerPC doesn't generate traps for divide by zero, so we'd + // need to do the checks ourselves. Using an inline check + // should be faster than calling an out-of-line thunk, but the + // thunk is easier, so they's what we do for now. + if (true) {//if (BytesPerWord == 4 and aSize == 8) { *thunk = true; } else { *aTypeMask = (1 << RegisterOperand); From 309c1cac6d6a64566cbd1c042577480f9b09ed50 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 30 Jan 2011 19:11:23 -0700 Subject: [PATCH 227/274] fix PowerPC tails and continuations builds --- src/compile-powerpc.S | 33 ++++++++++++++++----------------- src/powerpc.cpp | 11 ++++++++--- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index e760287f1e..7e40816105 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -241,43 +241,42 @@ GLOBAL(vmJumpAndInvoke): #ifdef AVIAN_CONTINUATIONS // r3: thread // r4: address - // r5: (unused) - // r6: stack - // r7: argumentFootprint - // r8: arguments - // r9: frameSize + // r5: stack + // r6: argumentFootprint + // r7: arguments + // r8: frameSize // restore (pseudo)-stack pointer (we don't want to touch the real // stack pointer, since we haven't copied the arguments yet) - lwz r6,0(r6) + lwz r5,0(r5) - // make everything between r1 and r6 one big stack frame while we + // make everything between r1 and r5 one big stack frame while we // shuffle things around - stw r6,0(r1) + stw r5,0(r1) // allocate new frame, adding room for callee-saved registers - subfic r10,r9,-80 - stwux r6,r6,r10 + subfic r10,r8,-80 + stwux r5,r5,r10 mr r13,r3 // copy arguments into place - li r9,0 - addi r11,r6,ARGUMENT_BASE + li r8,0 + addi r11,r5,ARGUMENT_BASE b LOCAL(vmJumpAndInvoke_argumentTest) LOCAL(vmJumpAndInvoke_argumentLoop): - lwzx r12,r8,r9 - stwx r12,r11,r9 - addi r9,r9,4 + lwzx r12,r7,r8 + stwx r12,r11,r8 + addi r8,r8,4 LOCAL(vmJumpAndInvoke_argumentTest): - cmplw r9,r7 + cmplw r8,r6 ble LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack // pointer now - mr r1,r6 + mr r1,r5 // set return address to vmInvoke_returnAddress bl LOCAL(vmJumpAndInvoke_getPC) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index e6be245100..c3d21e3dcd 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1765,9 +1765,14 @@ nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size UNUSED, } // check for post-non-tail-call stack adjustment of the form "lwzx - // r0,0(r1); stwux r0,offset(r1)": - - // todo + // r0,0(r1); stwu r0,offset(r1)": + if (instruction < start + (size / BytesPerWord) - 1 + and (static_cast(instruction[1]) >> 16) == 0x9421) + { + offset += static_cast(instruction[1]); + } else if ((static_cast(*instruction) >> 16) == 0x9421) { + offset += static_cast(*instruction); + } // todo: check for and handle tail calls } From 69501a05b804c50818e91345ac3d9c8ccc70da87 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 30 Jan 2011 19:29:53 -0700 Subject: [PATCH 228/274] remove UNUSED modifier from parameter which is now used --- src/powerpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index c3d21e3dcd..edcd587132 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1733,7 +1733,7 @@ argumentFootprint(unsigned footprint) } void -nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size UNUSED, +nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, unsigned footprint, void* link, void*, unsigned targetParameterFootprint, void** ip, void** stack) { From 69af8a13aaee4617489bc3808e1c6db5e8019c92 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 31 Jan 2011 09:54:38 -0700 Subject: [PATCH 229/274] add Thread.getStackTrace test --- test/Trace.java | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 test/Trace.java diff --git a/test/Trace.java b/test/Trace.java new file mode 100644 index 0000000000..238e8e0329 --- /dev/null +++ b/test/Trace.java @@ -0,0 +1,89 @@ +public class Trace implements Runnable { + private volatile boolean alive = true; + + private static void throwSomething() { + throw new RuntimeException(); + } + + private void bar(Object o) { + o.toString(); + } + + private void foo() { + { long a = 42; + long b = 25; + long c = a / b; + } + + try { + long a = 42; + long b = 0; + long c = a / b; + } catch (Exception e) { } + + try { + throw new Exception(); + } catch (Exception e) { } + + try { + throwSomething(); + } catch (Exception e) { } + + try { + Trace.class.getMethod("bar", Object.class).invoke(this, this); + } catch (Exception e) { } + } + + private static void dummy() { + byte[] a = new byte[10]; + byte[] b = new byte[10]; + System.arraycopy(a, 0, b, 0, 10); + } + + private static void tail1(int a, int b, int c, int d, int e, int f) { + dummy(); + } + + private static void tail2() { + tail1(1, 2, 3, 4, 5, 6); + tail1(1, 2, 3, 4, 5, 6); + } + + private static void test(Trace trace) { + tail1(1, 2, 3, 4, 5, 6); + tail2(); + trace.foo(); + } + + public void run() { + synchronized (this) { + notifyAll(); + } + + try { + for (int i = 0; i < 10000; ++i) { + test(this); + } + } finally { + alive = false; + } + } + + public static void main(String[] args) throws Exception { + Trace trace = new Trace(); + Thread thread = new Thread(trace); + + synchronized (trace) { + thread.start(); + trace.wait(); + + int count = 0; + while (trace.alive) { + thread.getStackTrace(); + ++ count; + } + + System.out.println("got " + count + " traces"); + } + } +} From 9ed1ffff3559afb4afefe89d08d3b7adf94cd431 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 31 Jan 2011 15:39:59 -0700 Subject: [PATCH 230/274] implement syncInstructionCache for ARM Like, PowerPC, ARM has an instruction cache which must be manually flushed if/when we compile a new method. This commit updates syncInstructionCache to use GCC's builtin __clear_cache routine. --- src/arm.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/arm.h b/src/arm.h index e66377e7f6..c2e933a1b0 100644 --- a/src/arm.h +++ b/src/arm.h @@ -55,9 +55,11 @@ loadMemoryBarrier() } inline void -syncInstructionCache(const void* start UNUSED, unsigned size UNUSED) +syncInstructionCache(const void* start, unsigned size) { - asm("nop"); + __clear_cache + (const_cast(start), + const_cast(static_cast(start) + size)); } typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); From 635f5ba7e692d032f146bda414a8831624d37f2a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 31 Jan 2011 21:18:55 -0700 Subject: [PATCH 231/274] avoid garbage collection from e.g. divideLong thunk It is dangerous to initiate a GC from a thunk like divideLong (which was possible when allocating a new ArithmeticException to signal divide-by-zero) since we don't currently generate a GC root frame map for the return address of the thunk call. Instead, we use the backup heap area if there is room, or else throw a pre-allocated exception instead. --- src/compile.cpp | 65 ++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index cb4bd365d2..3a098969c6 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -2430,13 +2430,49 @@ absoluteInt(int32_t a) return a > 0 ? a : -a; } +unsigned +traceSize(Thread* t) +{ + class Counter: public Processor::StackVisitor { + public: + Counter(): count(0) { } + + virtual bool visit(Processor::StackWalker*) { + ++ count; + return true; + } + + unsigned count; + } counter; + + t->m->processor->walkStack(t, &counter); + + return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray) + + (counter.count * FixedSizeOfTraceElement); +} + +void NO_RETURN +throwArithmetic(MyThread* t) +{ + if (ensure(t, FixedSizeOfArithmeticException + traceSize(t))) { + atomicOr(&(t->flags), Thread::TracingFlag); + THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); + + throwNew(t, Machine::ArithmeticExceptionType); + } else { + // not enough memory available for a new exception and stack trace + // -- use a preallocated instance instead + throw_(t, root(t, Machine::ArithmeticException)); + } +} + int64_t divideLong(MyThread* t, int64_t b, int64_t a) { if (LIKELY(b)) { return a / b; } else { - throwNew(t, Machine::ArithmeticExceptionType); + throwArithmetic(t); } } @@ -2446,7 +2482,7 @@ divideInt(MyThread* t, int32_t b, int32_t a) if (LIKELY(b)) { return a / b; } else { - throwNew(t, Machine::ArithmeticExceptionType); + throwArithmetic(t); } } @@ -2456,7 +2492,7 @@ moduloLong(MyThread* t, int64_t b, int64_t a) if (LIKELY(b)) { return a % b; } else { - throwNew(t, Machine::ArithmeticExceptionType); + throwArithmetic(t); } } @@ -2466,7 +2502,7 @@ moduloInt(MyThread* t, int32_t b, int32_t a) if (LIKELY(b)) { return a % b; } else { - throwNew(t, Machine::ArithmeticExceptionType); + throwArithmetic(t); } } @@ -2656,27 +2692,6 @@ makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions, (t, class_, static_cast(t->stack) + offset, dimensions)); } -unsigned -traceSize(Thread* t) -{ - class Counter: public Processor::StackVisitor { - public: - Counter(): count(0) { } - - virtual bool visit(Processor::StackWalker*) { - ++ count; - return true; - } - - unsigned count; - } counter; - - t->m->processor->walkStack(t, &counter); - - return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray) - + (counter.count * FixedSizeOfTraceElement); -} - void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { From 8ed2bb9dbbe3fe0f90bd658e10c61c3b0b338a83 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 08:38:59 -0700 Subject: [PATCH 232/274] remove FrameEvent code from x86.cpp That code was unused and will be unecessary until we add proper support for unwinding through tail calls in nextFrame, at which point it may be reinstated in some form. --- src/x86.cpp | 59 +++-------------------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/src/x86.cpp b/src/x86.cpp index 0f7a672459..97ef3c2bb3 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -86,7 +86,6 @@ isInt32(intptr_t v) class Task; class AlignmentPadding; -class FrameEvent; unsigned padding(AlignmentPadding* p, unsigned index, unsigned offset, @@ -101,8 +100,8 @@ resolved(Context* c, int64_t value); class MyBlock: public Assembler::Block { public: MyBlock(unsigned offset): - next(0), firstPadding(0), lastPadding(0), firstFrameEvent(0), - lastFrameEvent(0), offset(offset), start(~0), size(0) + next(0), firstPadding(0), lastPadding(0), offset(offset), start(~0), + size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { @@ -115,8 +114,6 @@ class MyBlock: public Assembler::Block { MyBlock* next; AlignmentPadding* firstPadding; AlignmentPadding* lastPadding; - FrameEvent* firstFrameEvent; - FrameEvent* lastFrameEvent; unsigned offset; unsigned start; unsigned size; @@ -159,8 +156,7 @@ class Context { Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), firstFrameEvent(0), lastFrameEvent(0), - ac(ac), frameEventCount(0) + lastBlock(firstBlock), ac(ac) { } System* s; @@ -171,10 +167,7 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; - FrameEvent* firstFrameEvent; - FrameEvent* lastFrameEvent; ArchitectureContext* ac; - unsigned frameEventCount; }; void NO_RETURN @@ -461,39 +454,6 @@ padding(AlignmentPadding* p, unsigned start, unsigned offset, return padding; } -class FrameEvent { - public: - FrameEvent(Context* c, Promise* offset): - c(c), next(0), offset(offset) - { } - - Context* c; - FrameEvent* next; - Promise* offset; -}; - -void -appendFrameEvent(Context* c, MyBlock* b, Promise* offset) -{ - FrameEvent* e = new (c->zone->allocate(sizeof(FrameEvent))) - FrameEvent(c, offset); - - if (b->firstFrameEvent) { - b->lastFrameEvent->next = e; - } else { - b->firstFrameEvent = e; - } - b->lastFrameEvent = e; - - ++ c->frameEventCount; -} - -void -appendFrameEvent(Context* c) -{ - appendFrameEvent(c, c->lastBlock, offset(c)); -} - extern "C" bool detectFeature(unsigned ecx, unsigned edx); @@ -3524,8 +3484,6 @@ class MyAssembler: public Assembler { { if (TailCalls) { if (offset) { - appendFrameEvent(&c); - Register tmp(c.client->acquireTemporary()); unsigned baseSize = UseFramePointer ? 1 : 0; @@ -3583,8 +3541,6 @@ class MyAssembler: public Assembler { assert(&c, (argumentFootprint % StackAlignmentInWords) == 0); if (TailCalls and argumentFootprint > StackAlignmentInWords) { - appendFrameEvent(&c); - Register returnAddress(rcx); popR(&c, BytesPerWord, &returnAddress); @@ -3660,15 +3616,6 @@ class MyAssembler: public Assembler { c.result = dst; for (MyBlock* b = c.firstBlock; b; b = b->next) { - if (b->firstFrameEvent) { - if (c.firstFrameEvent) { - c.lastFrameEvent->next = b->firstFrameEvent; - } else { - c.firstFrameEvent = b->firstFrameEvent; - } - c.lastFrameEvent = b->lastFrameEvent; - } - unsigned index = 0; unsigned padding = 0; for (AlignmentPadding* p = b->firstPadding; p; p = p->next) { From a0a8c554d55e2e55b46f171b13c8c00a3aa6ca93 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 08:40:56 -0700 Subject: [PATCH 233/274] add a couple of test cases to NullPointer.java --- test/NullPointer.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/NullPointer.java b/test/NullPointer.java index c09dc83340..6c6e5c7b50 100644 --- a/test/NullPointer.java +++ b/test/NullPointer.java @@ -2,10 +2,33 @@ public class NullPointer { private int x; private Object y; + private static void throw_(Object o) { + o.toString(); + } + + private static void throwAndCatch(Object o) { + try { + o.toString(); + throw new RuntimeException(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + } + public static void main(String[] args) { + try { + throw_(null); + throw new RuntimeException(); + } catch (NullPointerException e) { + e.printStackTrace(); + } + + throwAndCatch(null); + // invokeinterface try { ((Runnable) null).run(); + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -13,6 +36,7 @@ public class NullPointer { // invokevirtual try { ((Object) null).toString(); + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -20,6 +44,7 @@ public class NullPointer { // arraylength try { int a = ((byte[]) null).length; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -27,6 +52,7 @@ public class NullPointer { // iaload try { int a = ((byte[]) null)[42]; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -34,6 +60,7 @@ public class NullPointer { // aaload try { Object a = ((Object[]) null)[42]; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -41,6 +68,7 @@ public class NullPointer { // getfield (int) try { int a = ((NullPointer) null).x; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -48,6 +76,7 @@ public class NullPointer { // getfield (Object) try { Object a = ((NullPointer) null).y; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -55,6 +84,7 @@ public class NullPointer { // iastore try { ((byte[]) null)[42] = 42; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -62,6 +92,7 @@ public class NullPointer { // aastore try { ((Object[]) null)[42] = null; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -69,6 +100,7 @@ public class NullPointer { // putfield (int) try { ((NullPointer) null).x = 42; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -76,6 +108,7 @@ public class NullPointer { // putfield (Object) try { ((NullPointer) null).y = null; + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } @@ -85,6 +118,7 @@ public class NullPointer { synchronized ((Object) null) { int a = 42; } + throw new RuntimeException(); } catch (NullPointerException e) { e.printStackTrace(); } From d4c39e07a20aaf7e8ca35682cdf28226c84ea39b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 08:48:30 -0700 Subject: [PATCH 234/274] update readme.txt to reflect that 64-bit Windows does not use an underscore prefix for symbols --- readme.txt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/readme.txt b/readme.txt index 0f0ad44bb7..8e88b4abb4 100644 --- a/readme.txt +++ b/readme.txt @@ -316,11 +316,15 @@ setting the boot classpath to "[bootJar]". #include "stdint.h" #include "jni.h" -#ifdef __MINGW32__ +#if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) -# define SYMBOL(x) binary_boot_jar_##x #else # define EXPORT __attribute__ ((visibility("default"))) +#endif + +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) +# define SYMBOL(x) binary_boot_jar_##x +#else # define SYMBOL(x) _binary_boot_jar_##x #endif @@ -520,11 +524,15 @@ containing them. See the previous example for instructions. #include "stdint.h" #include "jni.h" -#ifdef __MINGW32__ +#if (defined __MINGW32__) || (defined _MSC_VER) # define EXPORT __declspec(dllexport) -# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x #else # define EXPORT __attribute__ ((visibility("default"))) +#endif + +#if (! defined __x86_64__) && ((defined __MINGW32__) || (defined _MSC_VER)) +# define BOOTIMAGE_BIN(x) binary_bootimage_bin_##x +#else # define BOOTIMAGE_BIN(x) _binary_bootimage_bin_##x #endif From 78a80534e62f1bed54da296aa79fc4bd37339ee2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 11:01:28 -0700 Subject: [PATCH 235/274] ensure stack remains aligned in compile-x86.S If AVIAN_USE_FRAME_POINTER is not defined, the caller of vmInvoke will calculate a frame size which assumes vmInvoke does not push rbp on the stack before allocating the frame. However, vmInvoke pushes rbp reguardless, so we need to adjust the frame size to ensure the stack remains aligned. --- src/compile-x86.S | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index 6bf13a5bfb..3f839ce3c5 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -26,9 +26,15 @@ #define THREAD_STACK 2224 #define THREAD_SCRATCH 2232 +#ifdef AVIAN_USE_FRAME_POINTER +# define ALIGNMENT_ADJUSTMENT 0 +#else +# define ALIGNMENT_ADJUSTMENT 8 +#endif + #if defined __MINGW32__ || defined __CYGWIN32__ -#define CALLEE_SAVED_REGISTER_FOOTPRINT 64 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 64 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): @@ -163,7 +169,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): #else // not __MINGW32__ || __CYGWIN32__ -#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 +#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): @@ -296,7 +302,13 @@ LOCAL(vmJumpAndInvoke_argumentTest): #define THREAD_STACK 2148 #define THREAD_SCRATCH 2152 -#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 +#ifdef AVIAN_USE_FRAME_POINTER +# define ALIGNMENT_ADJUSTMENT 0 +#else +# define ALIGNMENT_ADJUSTMENT 12 +#endif + +#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 + ALIGNMENT_ADJUSTMENT .globl GLOBAL(vmInvoke) GLOBAL(vmInvoke): From 132f188ff05e18dd7bc49824004710972701cf41 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 14:23:53 -0700 Subject: [PATCH 236/274] fix cut-and-paste error in jnienv.cpp release0 should call release, not acquire. --- src/jnienv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 027025b1e3..479fe9deb5 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2212,7 +2212,7 @@ MonitorEnter(Thread* t, jobject o) void release0(Thread* t, object o) { - return acquire(t, o); + return release(t, o); } jint JNICALL From 9ef9d9619d8aee4a0805b304516d33e803483a1b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 17:45:43 -0700 Subject: [PATCH 237/274] avoid deadlock due to entering active state before running destroyJavaVM We risked deadlock when waiting for other non-daemon threads to exit since they could not exit without entering exclusive state, which required waiting for all other threads to go idle. --- src/jnienv.cpp | 2 +- src/machine.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 479fe9deb5..eebbf2ad6d 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -91,7 +91,7 @@ DestroyJavaVM(Machine* m) { Thread* t; AttachCurrentThread(m, &t, 0); - if (run(t, destroyJavaVM, 0)) { + if (runRaw(t, destroyJavaVM, 0)) { t->exit(); return 0; } else { diff --git a/src/machine.h b/src/machine.h index e7b30539dd..cdaa703caa 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1912,12 +1912,19 @@ instanceOf(Thread* t, object class_, object o); #include "type-declarations.cpp" +inline uint64_t +runRaw(Thread* t, + uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) +{ + Thread::RunCheckpoint checkpoint(t); + return vmRun(function, arguments, &checkpoint); +} + inline uint64_t run(Thread* t, uint64_t (*function)(Thread*, uintptr_t*), uintptr_t* arguments) { ENTER(t, Thread::ActiveState); - Thread::RunCheckpoint checkpoint(t); - return vmRun(function, arguments, &checkpoint); + return runRaw(t, function, arguments); } inline void From aa9c887fb4c34d604d7bfad3b67b0dc439938286 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 18:14:32 -0700 Subject: [PATCH 238/274] implement Thread.yield --- src/classpath-avian.cpp | 7 +++++++ src/classpath-openjdk.cpp | 8 ++------ src/posix.cpp | 5 +++++ src/system.h | 1 + src/windows.cpp | 4 ++++ 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 656086f4c1..95b2a32703 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -579,6 +579,13 @@ Avian_java_lang_Thread_enumerate return count; } +extern "C" JNIEXPORT void JNICALL +Avian_java_lang_Thread_yield +(Thread* t, object, uintptr_t*) +{ + t->m->system->yield(); +} + extern "C" JNIEXPORT void JNICALL Avian_avian_Classes_acquireClassLock (Thread* t, object, uintptr_t*) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 8882976f3c..b06d1406f4 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2210,13 +2210,9 @@ EXPORT(JVM_SetThreadPriority)(Thread*, jobject, jint) } extern "C" JNIEXPORT void JNICALL -EXPORT(JVM_Yield)(Thread*, jclass) +EXPORT(JVM_Yield)(Thread* t, jclass) { -#ifdef PLATFORM_WINDOWS - SwitchToThread(); -#else - sched_yield(); -#endif + t->m->system->yield(); } uint64_t diff --git a/src/posix.cpp b/src/posix.cpp index de879c3496..53dfb0bb90 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -30,6 +30,7 @@ #include "sys/ucontext.h" #include "stdint.h" #include "dirent.h" +#include "sched.h" #include "arch.h" #include "system.h" @@ -795,6 +796,10 @@ class MySystem: public System { (static_cast(tv.tv_usec) / 1000); } + virtual void yield() { + sched_yield(); + } + virtual void exit(int code) { ::exit(code); } diff --git a/src/system.h b/src/system.h index 4d155cfd66..6e2ea14721 100644 --- a/src/system.h +++ b/src/system.h @@ -141,6 +141,7 @@ class System { virtual char pathSeparator() = 0; virtual char fileSeparator() = 0; virtual int64_t now() = 0; + virtual void yield() = 0; virtual void exit(int code) = 0; virtual void abort() = 0; virtual void dispose() = 0; diff --git a/src/windows.cpp b/src/windows.cpp index b86d2fa99e..0079121d2f 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -807,6 +807,10 @@ class MySystem: public System { | time.dwLowDateTime) / 10000) - 11644473600000LL; } + virtual void yield() { + SwitchToThread(); + } + virtual void exit(int code) { ::exit(code); } From c4ededda8332391836b7f09db4f99651ea805cf3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 18:14:53 -0700 Subject: [PATCH 239/274] add progress indicators to Trace test Also, add a yield call to the tracing thread so it doesn't monopolize the CPU. --- test/Trace.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/Trace.java b/test/Trace.java index 238e8e0329..79aa3b421d 100644 --- a/test/Trace.java +++ b/test/Trace.java @@ -63,6 +63,11 @@ public class Trace implements Runnable { try { for (int i = 0; i < 10000; ++i) { test(this); + + if (i % 100 == 0) { + System.out.print("r"); + System.out.flush(); + } } } finally { alive = false; @@ -81,9 +86,15 @@ public class Trace implements Runnable { while (trace.alive) { thread.getStackTrace(); ++ count; + + if (count % 100 == 0) { + Thread.yield(); + System.out.print("t"); + System.out.flush(); + } } - System.out.println("got " + count + " traces"); + System.out.println("\ngot " + count + " traces"); } } } From 79247a9885e6cf9fe60442a9ca16d42cd7ac0614 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 19:23:25 -0700 Subject: [PATCH 240/274] ensure native method frame always popped in interpret.cpp's invokeNative If a native method using the fast calling convention throws an exception, we need to make sure the frame for that method is popped before handling the exception. --- src/interpret.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index 7ca4fcb0a2..2c3c0f88d8 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -658,23 +658,25 @@ invokeNative(Thread* t, object method) if (nativeFast(t, native)) { pushFrame(t, method); - unsigned footprint = methodParameterFootprint(t, method); - RUNTIME_ARRAY(uintptr_t, args, footprint); - unsigned sp = frameBase(t, t->frame); - unsigned argOffset = 0; - if ((methodFlags(t, method) & ACC_STATIC) == 0) { - RUNTIME_ARRAY_BODY(args)[argOffset++] - = reinterpret_cast(peekObject(t, sp++)); + uint64_t result; + { THREAD_RESOURCE0(t, popFrame(static_cast(t))); + + unsigned footprint = methodParameterFootprint(t, method); + RUNTIME_ARRAY(uintptr_t, args, footprint); + unsigned sp = frameBase(t, t->frame); + unsigned argOffset = 0; + if ((methodFlags(t, method) & ACC_STATIC) == 0) { + RUNTIME_ARRAY_BODY(args)[argOffset++] + = reinterpret_cast(peekObject(t, sp++)); + } + + marshalArguments + (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, true); + + result = reinterpret_cast + (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); } - marshalArguments - (t, RUNTIME_ARRAY_BODY(args) + argOffset, 0, sp, method, true); - - uint64_t result = reinterpret_cast - (nativeFunction(t, native))(t, method, RUNTIME_ARRAY_BODY(args)); - - popFrame(t); - pushResult(t, methodReturnCode(t, method), result, false); return methodReturnCode(t, method); From ac49eb8c9a35d05e4d7f100aa69ddb51bd3d0b7f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Feb 2011 19:51:00 -0700 Subject: [PATCH 241/274] return empty array instead of null from interpret.cpp's getStackTrace This avoids a crash elsewhere when we try to use the result. --- src/interpret.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interpret.cpp b/src/interpret.cpp index 2c3c0f88d8..3da5ca97d5 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -3203,9 +3203,9 @@ class MyProcessor: public Processor { return ::invoke(t, method); } - virtual object getStackTrace(vm::Thread*, vm::Thread*) { + virtual object getStackTrace(vm::Thread* t, vm::Thread*) { // not implemented - return 0; + return makeObjectArray(t, 0); } virtual void initialize(BootImage*, uint8_t*, unsigned) { From cce89c8dddbfc588fa211ebb23bcfb6ce233844c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 08:15:07 -0700 Subject: [PATCH 242/274] fix MSVC build --- src/machine.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine.h b/src/machine.h index cdaa703caa..100e6f1e04 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1568,20 +1568,20 @@ class Classpath { #ifdef _MSC_VER template -class RuntimeArray: public Thread::Resource { +class ThreadRuntimeArray: public Thread::Resource { public: - RuntimeArray(Thread* t, unsigned size): + ThreadRuntimeArray(Thread* t, unsigned size): Resource(t), body(static_cast(t->m->heap->allocate(size * sizeof(T)))), size(size) { } - ~RuntimeArray() { + ~ThreadRuntimeArray() { t->m->heap->free(body, size * sizeof(T)); } virtual void release() { - RuntimeArray::~RuntimeArray(); + ThreadRuntimeArray::~ThreadRuntimeArray(); } T* body; @@ -1589,7 +1589,7 @@ class RuntimeArray: public Thread::Resource { }; # define THREAD_RUNTIME_ARRAY(thread, type, name, size) \ - RuntimeArray name(thread, size); + ThreadRuntimeArray name(thread, size); #else // not _MSC_VER From 5586f8133c965ee20e0180ee862ffddd9ce1227f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 08:31:52 -0700 Subject: [PATCH 243/274] update readme.txt to reflect new test classpath --- readme.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.txt b/readme.txt index 8e88b4abb4..708c948d13 100644 --- a/readme.txt +++ b/readme.txt @@ -4,24 +4,24 @@ Quick Start on Linux: $ export JAVA_HOME=/usr/local/java # or wherever you have the JDK installed $ make - $ build/linux-i386/avian -cp build/test Hello + $ build/linux-i386/avian -cp build/linux-i386/test Hello on Mac OS X: $ export JAVA_HOME=/Library/Java/Home $ make - $ build/darwin-i386/avian -cp build/test Hello + $ build/darwin-i386/avian -cp build/darwin-i386/test Hello on Windows (MSYS): $ git clone git://oss.readytalk.com/win32.git ../win32 $ export JAVA_HOME="C:/Program Files/Java/jdk1.6.0_07" $ make - $ build/windows-i386/avian -cp build/test Hello + $ build/windows-i386/avian -cp build/windows-i386/test Hello on Windows (Cygwin): $ git clone git://oss.readytalk.com/win32.git ../win32 $ export JAVA_HOME="/cygdrive/c/Program Files/Java/jdk1.6.0_07" $ make - $ build/windows-i386/avian -cp build/test Hello + $ build/windows-i386/avian -cp build/windows-i386/test Hello Adjust JAVA_HOME according to your system, but be sure to use forward slashes in the path. From 4d5aeb5ab2dba42052e6346f766d2126adc6325e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 08:32:40 -0700 Subject: [PATCH 244/274] disable debug logging in compile.cpp --- src/compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 3a098969c6..12189c216a 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -37,7 +37,7 @@ namespace { namespace local { -const bool DebugCompile = true; +const bool DebugCompile = false; const bool DebugNatives = false; const bool DebugCallTable = false; const bool DebugMethodTree = false; From 51a1081adc0744a4b04be7c7a5b2e9bcf23d5fc3 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 08:46:20 -0700 Subject: [PATCH 245/274] remove unused Heap::Client::outOfMemory method The heap-dump-on-OOM feature has been moved to the collect function. --- src/heap.cpp | 7 ------- src/heap.h | 1 - src/machine.cpp | 30 +++++++++++++++--------------- src/machine.h | 1 + 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/heap.cpp b/src/heap.cpp index 7f923da02d..02e0e99a19 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -70,7 +70,6 @@ System* system(Context*); void* tryAllocate(Context* c, unsigned size); void* allocate(Context* c, unsigned size); void free(Context* c, const void* p, unsigned size); -void outOfMemory(Context*); #ifdef USE_ATOMIC_OPERATIONS inline void @@ -1780,12 +1779,6 @@ free_(Context* c, const void* p, unsigned size) free(c, p, size); } -void -outOfMemory(Context* c) -{ - c->client->outOfMemory(); -} - class MyHeap: public Heap { public: MyHeap(System* system, unsigned limit): diff --git a/src/heap.h b/src/heap.h index 3f454d6be0..ecb60d2637 100644 --- a/src/heap.h +++ b/src/heap.h @@ -49,7 +49,6 @@ class Heap: public Allocator { virtual unsigned copiedSizeInWords(void*) = 0; virtual void copy(void*, void*) = 0; virtual void walk(void*, Walker*) = 0; - virtual void outOfMemory() = 0; }; virtual void setClient(Client* client) = 0; diff --git a/src/machine.cpp b/src/machine.cpp index da705b5db6..31dad80726 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2156,21 +2156,6 @@ class HeapClient: public Heap::Client { ::walk(m->rootThread, w, o, 0); } - virtual void outOfMemory() { -#ifdef AVIAN_HEAPDUMP - const char* path = findProperty(m->rootThread, "avian.heap.dump"); - if (path) { - FILE* out = vm::fopen(path, "wb"); - if (out) { - dumpHeap(m->rootThread, out); - fclose(out); - } - } -#endif//AVIAN_HEAPDUMP - - abort(m->system); - } - void dispose() { m->heap->free(this, sizeof(*this)); } @@ -2282,6 +2267,7 @@ Machine::Machine(System* system, Heap* heap, Finder* bootFinder, tenuredWeakReferences(0), unsafe(false), triedBuiltinOnLoad(false), + dumpedHeapOnOOM(false), heapPoolIndex(0) { heap->setClient(heapClient); @@ -3798,6 +3784,20 @@ collect(Thread* t, Heap::CollectionType type) // into the smallest possible space: doCollect(t, Heap::MajorCollection); } + +#ifdef AVIAN_HEAPDUMP + if ((not t->m->dumpedHeapOnOOM) and t->m->heap->limitExceeded()) { + t->m->dumpedHeapOnOOM = true; + const char* path = findProperty(t, "avian.heap.dump"); + if (path) { + FILE* out = vm::fopen(path, "wb"); + if (out) { + dumpHeap(t, out); + fclose(out); + } + } + } +#endif//AVIAN_HEAPDUMP } void diff --git a/src/machine.h b/src/machine.h index 100e6f1e04..3ab23cc2f4 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1307,6 +1307,7 @@ class Machine { object tenuredWeakReferences; bool unsafe; bool triedBuiltinOnLoad; + bool dumpedHeapOnOOM; JavaVMVTable javaVMVTable; JNIEnvVTable jniEnvVTable; uintptr_t* heapPool[ThreadHeapPoolSize]; From 5f9a2a1b9bd629303bf5ff82e57a4061aaf70ab1 Mon Sep 17 00:00:00 2001 From: jet Date: Wed, 2 Feb 2011 10:02:15 -0700 Subject: [PATCH 246/274] Added -marm flag to ARM cflags, as we don't support Thumb. --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 5b34b5051b..9f75fbd8ec 100644 --- a/makefile +++ b/makefile @@ -196,7 +196,7 @@ endif ifeq ($(arch),arm) asm = arm pointer-size = 4 - cflags += -Wno-psabi + cflags += -marm -Wno-psabi ifneq ($(arch),$(build-arch)) cxx = arm-linux-gnueabi-g++ From cdb75ef6d7a1b38c1023db330066b9778ce3bf60 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 15:11:34 -0700 Subject: [PATCH 247/274] define VA_LIST(x) (&x) on Windows Each platform and architecture defines the va_list type differently; on some we can treat it as a pointer and on others we must treat it as a non-pointer. Turns out Windows is one of the latter. --- src/x86.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/x86.h b/src/x86.h index d52f7c875e..dd291091e3 100644 --- a/src/x86.h +++ b/src/x86.h @@ -22,7 +22,11 @@ # undef interface #endif -#define VA_LIST(x) (x) +#ifdef PLATFORM_WINDOWS +# define VA_LIST(x) (&x) +#else +# define VA_LIST(x) (x) +#endif #ifdef ARCH_x86_32 From 85bd36c75ad4cc14c7277f68a3243bf1a8d2ade1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 15:34:18 -0700 Subject: [PATCH 248/274] fix 64-bit Windows implementation of vmRun --- src/x86.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x86.S b/src/x86.S index 72b25268fd..9d7bbfa1a8 100644 --- a/src/x86.S +++ b/src/x86.S @@ -196,10 +196,10 @@ GLOBAL(vmRun): movq %rsi,56(%rsp) movq %rdi,64(%rsp) - movq %rsp,CHECKPOINT_STACK(%rcx) + movq %rsp,CHECKPOINT_STACK(%r8) movq %rcx,%r11 - movq CHECKPOINT_THREAD(%rdx),%rcx + movq CHECKPOINT_THREAD(%r8),%rcx call *%r11 From 12ab9355972e71b8368ffc8cd2c187c717c59111 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 2 Feb 2011 16:06:09 -0700 Subject: [PATCH 249/274] fix 32-bit vmRun stack alignment --- src/x86.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x86.S b/src/x86.S index 9d7bbfa1a8..d711d17056 100644 --- a/src/x86.S +++ b/src/x86.S @@ -517,7 +517,7 @@ GLOBAL(vmJump): movl 12(%esp),%esp jmp *%esi -#define VMRUN_FRAME_SIZE 32 +#define VMRUN_FRAME_SIZE 24 .globl GLOBAL(vmRun) GLOBAL(vmRun): From 6e79e98d18c00680910cf2cff4650ff35623a43e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 7 Feb 2011 11:45:39 -0700 Subject: [PATCH 250/274] increase default stack size to 128KB 64KB was too small for many apps. SWT in particular can use a lot of stack space, especially on 64-bit systems. --- src/machine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.h b/src/machine.h index 3ab23cc2f4..23e1743a49 100644 --- a/src/machine.h +++ b/src/machine.h @@ -106,7 +106,7 @@ const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; const unsigned ThreadBackupHeapSizeInWords = ThreadBackupHeapSizeInBytes / BytesPerWord; -const unsigned StackSizeInBytes = 64 * 1024; +const unsigned StackSizeInBytes = 128 * 1024; const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord; const unsigned ThreadHeapPoolSize = 64; From a63909b8180a6e383065b34991595a45acab5b6d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 7 Feb 2011 16:28:17 -0700 Subject: [PATCH 251/274] update VA_LIST definition for various platforms Apparently, 64-bit Linux and OS X are the only ones where we must define VA_LIST(x) as (x) instead of (&x). --- src/powerpc.h | 2 +- src/x86.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/powerpc.h b/src/powerpc.h index fb84daf10a..b109c9dc5a 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,7 +14,7 @@ #include "types.h" #include "common.h" -#define VA_LIST(x) (x) +#define VA_LIST(x) (&x) #ifdef __APPLE__ # if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) diff --git a/src/x86.h b/src/x86.h index dd291091e3..f393ad8727 100644 --- a/src/x86.h +++ b/src/x86.h @@ -22,7 +22,7 @@ # undef interface #endif -#ifdef PLATFORM_WINDOWS +#if (defined ARCH_x86_32) || (defined PLATFORM_WINDOWS) # define VA_LIST(x) (&x) #else # define VA_LIST(x) (x) From b72473f651eaf5a098ffa53f9c36d04e5b46e254 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 7 Feb 2011 19:44:59 -0700 Subject: [PATCH 252/274] ensure stack alignment in powerpc.S's vmRun --- src/powerpc.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/powerpc.S b/src/powerpc.S index b8034f5a7a..2b26f7985f 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -173,7 +173,7 @@ GLOBAL(vmRun): mflr r0 stw r0,8(r1) - stwu r1,-(MEMORY_BASE+80)(r1) + stwu r1,-(MEMORY_BASE+88)(r1) stw r13,MEMORY_BASE+0(r1) stw r14,MEMORY_BASE+4(r1) From c2cbecbaf0924e48c2f7b68ad4158d693dec6c54 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 8 Feb 2011 10:37:54 -0700 Subject: [PATCH 253/274] switch to using mingw-w64 tools for 32-bit Windows cross build This allows us to use the same tools for 32-bit and 64-bit builds. --- makefile | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/makefile b/makefile index 81e75b9dff..bd707edde2 100644 --- a/makefile +++ b/makefile @@ -276,18 +276,12 @@ ifeq ($(platform),windows) ifeq (,$(filter mingw32 cygwin,$(build-platform))) openjdk-extra-cflags += -I$(src)/openjdk/caseSensitive - # cxx = x86_64-w64-mingw32-g++ -m32 - # cc = x86_64-w64-mingw32-gcc -m32 - # dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 - # ar = x86_64-w64-mingw32-ar - # ranlib = x86_64-w64-mingw32-ranlib - # strip = x86_64-w64-mingw32-strip --strip-all - cxx = i586-mingw32msvc-g++ - cc = i586-mingw32msvc-gcc - dlltool = i586-mingw32msvc-dlltool - ar = i586-mingw32msvc-ar - ranlib = i586-mingw32msvc-ranlib - strip = i586-mingw32msvc-strip --strip-all + cxx = x86_64-w64-mingw32-g++ -m32 + cc = x86_64-w64-mingw32-gcc -m32 + dlltool = x86_64-w64-mingw32-dlltool -mi386 --as-flags=--32 + ar = x86_64-w64-mingw32-ar + ranlib = x86_64-w64-mingw32-ranlib + strip = x86_64-w64-mingw32-strip --strip-all else build-system = windows common-cflags += "-I$(JAVA_HOME)/include/win32" From a8645b6b2da383da98cff9ee31300291b31653be Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 8 Feb 2011 18:56:25 -0700 Subject: [PATCH 254/274] fix BufferedInputStream.read regression In commit 7fffba2, I had modified BufferedInputStream.read to keep reading until in.available() <= 0 or an EOF was reached, but neglected to update the offset into the destination buffer after each read. This caused the previously-read data to be overwritten. This commit fixes that regression. --- classpath/java/io/BufferedInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/classpath/java/io/BufferedInputStream.java b/classpath/java/io/BufferedInputStream.java index b20309fd51..67ac256a21 100644 --- a/classpath/java/io/BufferedInputStream.java +++ b/classpath/java/io/BufferedInputStream.java @@ -66,6 +66,7 @@ public class BufferedInputStream extends InputStream { } break; } else { + offset += c; count += c; length -= c; From 8e57639ff51deaa905d7b54793172cb0b49fad3e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 10 Feb 2011 11:54:00 -0700 Subject: [PATCH 255/274] use packed version of MINIDUMP_EXCEPTION_INFORMATION dbghelp.dll expects that MINIDUMP_EXCEPTION_INFORMATION has a packed layout and will crash if it doesn't (at least on 64-bit systems), but as of this writing mingw-w64's version is not declared to be so. Hence this workaround. --- src/windows.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/windows.cpp b/src/windows.cpp index 0079121d2f..d230e1eb3d 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -856,6 +856,16 @@ typedef BOOL (*MiniDumpWriteDumpType) const MINIDUMP_USER_STREAM_INFORMATION* userStream, const MINIDUMP_CALLBACK_INFORMATION* callback); +// dbghelp.dll expects that MINIDUMP_EXCEPTION_INFORMATION has a +// packed layout and will crash if it doesn't (at least on 64-bit +// systems), but as of this writing mingw-w64's version is not +// declared to be so. Hence this workaround: +struct __attribute__ ((__packed__)) My_MINIDUMP_EXCEPTION_INFORMATION { + DWORD ThreadId; + PEXCEPTION_POINTERS ExceptionPointers; + WINBOOL ClientPointers; +}; + void dump(LPEXCEPTION_POINTERS e, const char* directory) { @@ -877,7 +887,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) (name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0); if (file != INVALID_HANDLE_VALUE) { - MINIDUMP_EXCEPTION_INFORMATION exception + My_MINIDUMP_EXCEPTION_INFORMATION exception = { GetCurrentThreadId(), e, true }; MiniDumpWriteDump @@ -885,7 +895,7 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) GetCurrentProcessId(), file, MiniDumpWithFullMemory, - &exception, + reinterpret_cast(&exception), 0, 0); From 5c88f7741277b82dd9ebe7f9f277ec2ed8388899 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 10 Feb 2011 13:33:21 -0700 Subject: [PATCH 256/274] fix aliasing warning introduced in last commit --- src/windows.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/windows.cpp b/src/windows.cpp index d230e1eb3d..21b9a0ed64 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -888,16 +888,23 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) if (file != INVALID_HANDLE_VALUE) { My_MINIDUMP_EXCEPTION_INFORMATION exception - = { GetCurrentThreadId(), e, true }; + = { GetCurrentThreadId(), e, true }; + + union { + MINIDUMP_EXCEPTION_INFORMATION* exceptionPointer; + My_MINIDUMP_EXCEPTION_INFORMATION* myExceptionPointer; + }; - MiniDumpWriteDump - (GetCurrentProcess(), - GetCurrentProcessId(), - file, - MiniDumpWithFullMemory, - reinterpret_cast(&exception), - 0, - 0); + myExceptionPointer = &exception; + + MiniDumpWriteDump + (GetCurrentProcess(), + GetCurrentProcessId(), + file, + MiniDumpWithFullMemory, + exceptionPointer, + 0, + 0); CloseHandle(file); } From eae79fdb34f8a223cb1b58de24de80771c14adb7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 11 Feb 2011 15:02:09 -0700 Subject: [PATCH 257/274] clean up MINIDUMP_EXCEPTION_INFORMATION mess in windows.cpp The last two commits were meant to work around a supposed bug in mingw-w64's dbghelp.h, but closer inspection reminded me that we're not using dbghelp.h at all; legacy mingw doesn't have it, so we had to declare the structures we needed ourselves based on the MSDN documentation. What that documentation doesn't mention is that MINIDUMP_EXCEPTION_INFORMATION is subject to a special, packed layout, which we must represent using the __packed__ attribute. --- src/windows.cpp | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/windows.cpp b/src/windows.cpp index 21b9a0ed64..c4809c072c 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -833,7 +833,7 @@ class MySystem: public System { const char* crashDumpDirectory; }; -struct MINIDUMP_EXCEPTION_INFORMATION { +struct __attribute__ ((__packed__)) MINIDUMP_EXCEPTION_INFORMATION { DWORD thread; LPEXCEPTION_POINTERS exception; BOOL exceptionInCurrentAddressSpace; @@ -856,16 +856,6 @@ typedef BOOL (*MiniDumpWriteDumpType) const MINIDUMP_USER_STREAM_INFORMATION* userStream, const MINIDUMP_CALLBACK_INFORMATION* callback); -// dbghelp.dll expects that MINIDUMP_EXCEPTION_INFORMATION has a -// packed layout and will crash if it doesn't (at least on 64-bit -// systems), but as of this writing mingw-w64's version is not -// declared to be so. Hence this workaround: -struct __attribute__ ((__packed__)) My_MINIDUMP_EXCEPTION_INFORMATION { - DWORD ThreadId; - PEXCEPTION_POINTERS ExceptionPointers; - WINBOOL ClientPointers; -}; - void dump(LPEXCEPTION_POINTERS e, const char* directory) { @@ -887,22 +877,15 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) (name, FILE_WRITE_DATA, 0, 0, CREATE_ALWAYS, 0, 0); if (file != INVALID_HANDLE_VALUE) { - My_MINIDUMP_EXCEPTION_INFORMATION exception + MINIDUMP_EXCEPTION_INFORMATION exception = { GetCurrentThreadId(), e, true }; - - union { - MINIDUMP_EXCEPTION_INFORMATION* exceptionPointer; - My_MINIDUMP_EXCEPTION_INFORMATION* myExceptionPointer; - }; - - myExceptionPointer = &exception; MiniDumpWriteDump (GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpWithFullMemory, - exceptionPointer, + &exception, 0, 0); From cb7dc1aeef8b5aa1a0da6164c6eb3aef2687d5f4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 11 Feb 2011 21:13:11 -0700 Subject: [PATCH 258/274] fix various regressions due to 0.5 work --- src/classpath-openjdk.cpp | 6 +++--- src/machine.cpp | 3 ++- src/machine.h | 12 ++++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index b06d1406f4..56782758db 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -616,11 +616,11 @@ checkFileAccess return 0; } } else { - return booleanValue + return intValue (t, t->m->processor->invoke (t, nativeInterceptOriginal (t, methodRuntimeDataNative(t, getMethodRuntimeData(t, method))), - reinterpret_cast(arguments[0]), file, mask)); + reinterpret_cast(arguments[0]), file, mask)) != 0; } } @@ -3128,7 +3128,7 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) } object result; - if (arguments) { + if (args) { result = t->m->processor->invokeArray (t, vmMethod, instance ? *instance : 0, *args); } else { diff --git a/src/machine.cpp b/src/machine.cpp index 31dad80726..92cca91a1b 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -3523,7 +3523,8 @@ postInitClass(Thread* t, object c) object exception = t->exception; t->exception = 0; - throwNew(t, Machine::ExceptionInInitializerErrorType, 0, 0, exception); + throwNew(t, Machine::ExceptionInInitializerErrorType, + static_cast(0), 0, exception); } else { classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag); } diff --git a/src/machine.h b/src/machine.h index 23e1743a49..3c152223ab 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1971,6 +1971,8 @@ addThread(Thread* t, Thread* p) p->peer = p->parent->child; p->parent->child = p; + + threadPeer(t, p->javaThread) = reinterpret_cast(p); } inline void @@ -1985,6 +1987,8 @@ removeThread(Thread* t, Thread* p) t->m->stateLock->notifyAll(t->systemThread); p->parent->child = p->peer; + + threadPeer(t, p->javaThread) = 0; } inline Thread* @@ -2592,6 +2596,8 @@ throw_(Thread* t, object e) t->exception = e; + // printTrace(t, e); + popResources(t); t->checkpoint->unwind(); @@ -2600,9 +2606,11 @@ throw_(Thread* t, object e) } inline void NO_RETURN -throwNew(Thread* t, Machine::Type type) +throwNew +(Thread* t, Machine::Type type, object message = 0, object trace = 0, + object cause = 0) { - throw_(t, makeThrowable(t, type)); + throw_(t, makeThrowable(t, type, message, trace, cause)); } inline void NO_RETURN From 8d50d0fd76adb570176b30177d993128a05cdfa7 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 11 Feb 2011 21:57:27 -0700 Subject: [PATCH 259/274] fix aliasing bug in util.cpp We use a template function called "cast" to get raw access to fields in in the VM. In particular, we use this function in util.cpp to treat reference fields as intptr_t fields so we can use the least significant bit as the red/black flag in red/black tree nodes. Unfortunately, this runs afoul of the type aliasing rules in C/C++, and the compiler is permitted to optimize in a way that assumes such aliasing cannot occur. Such optimization caused all the nodes in the tree to be black, leading to extremely unbalanced trees and thus slow performance. The fix in this case is to use the __may_alias__ attribute to tell the compiler we're doing something devious. I've also used this technique to avoid other potential aliasing problems. There may be others lurking, so a complete audit of the VM might be a good idea. --- src/common.h | 4 ++++ src/machine.cpp | 8 ++++---- src/machine.h | 12 ++++++------ src/util.cpp | 22 +++++++++++++++------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/common.h b/src/common.h index 1514369d15..d4af04aa32 100644 --- a/src/common.h +++ b/src/common.h @@ -59,6 +59,8 @@ typedef uint64_t uintptr_t; # error "unsupported architecture" # endif +typedef intptr_t alias_t; + #else // not _MSC_VER # include "stdint.h" @@ -86,6 +88,8 @@ typedef uint64_t uintptr_t; # error "unsupported architecture" # endif +typedef intptr_t __attribute__((__may_alias__)) alias_t; + #endif // not _MSC_VER #undef JNIEXPORT diff --git a/src/machine.cpp b/src/machine.cpp index 92cca91a1b..4933d30f7c 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2145,8 +2145,8 @@ class HeapClient: public Heap::Client { memcpy(dst, src, n * BytesPerWord); if (hashTaken(t, src)) { - cast(dst, 0) &= PointerMask; - cast(dst, 0) |= ExtendedMark; + cast(dst, 0) &= PointerMask; + cast(dst, 0) |= ExtendedMark; extendedWord(t, dst, base) = takeHash(t, src); } } @@ -2781,7 +2781,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + cast(o, 0) = FixedMark; t->m->fixedFootprint += total; @@ -2796,7 +2796,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + cast(o, 0) = FixedMark; return o; } diff --git a/src/machine.h b/src/machine.h index 3c152223ab..78ce6d5448 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1878,8 +1878,8 @@ setObjectClass(Thread*, object o, object value) { cast(o, 0) = reinterpret_cast - (reinterpret_cast(value) - | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); + (reinterpret_cast(value) + | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); } inline const char* @@ -2094,19 +2094,19 @@ setType(Thread* t, Machine::Type type, object value) inline bool objectFixed(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == FixedMark; + return (cast(o, 0) & (~PointerMask)) == FixedMark; } inline bool objectExtended(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == ExtendedMark; + return (cast(o, 0) & (~PointerMask)) == ExtendedMark; } inline bool hashTaken(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == HashTakenMark; + return (cast(o, 0) & (~PointerMask)) == HashTakenMark; } inline unsigned @@ -2237,7 +2237,7 @@ markHashTaken(Thread* t, object o) ACQUIRE_RAW(t, t->m->heapLock); - cast(o, 0) |= HashTakenMark; + cast(o, 0) |= HashTakenMark; t->m->heap->pad(o); } diff --git a/src/util.cpp b/src/util.cpp index 511389ade8..7ae8de1217 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -66,32 +66,32 @@ inline object getTreeNodeValue(Thread*, object n) { return reinterpret_cast - (cast(n, TreeNodeValue) & PointerMask); + (cast(n, TreeNodeValue) & PointerMask); } inline void setTreeNodeValue(Thread* t, object n, object value) { - intptr_t red = cast(n, TreeNodeValue) & (~PointerMask); + alias_t red = cast(n, TreeNodeValue) & (~PointerMask); set(t, n, TreeNodeValue, value); - cast(n, TreeNodeValue) |= red; + cast(n, TreeNodeValue) |= red; } inline bool treeNodeRed(Thread*, object n) { - return (cast(n, TreeNodeValue) & (~PointerMask)) == 1; + return (cast(n, TreeNodeValue) & (~PointerMask)) == 1; } inline void setTreeNodeRed(Thread*, object n, bool red) { if (red) { - cast(n, TreeNodeValue) |= 1; + cast(n, TreeNodeValue) |= 1; } else { - cast(n, TreeNodeValue) &= PointerMask; + cast(n, TreeNodeValue) &= PointerMask; } } @@ -108,7 +108,7 @@ cloneTreeNode(Thread* t, object n) object treeFind(Thread* t, object tree, intptr_t key, object sentinal, - intptr_t (*compare)(Thread* t, intptr_t key, object b)) + intptr_t (*compare)(Thread* t, intptr_t key, object b)) { object node = tree; while (node != sentinal) { @@ -140,6 +140,7 @@ treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node, object new_ = newRoot; PROTECT(t, new_); + int count = 0; while (old != sentinal) { c->ancestors = path(c, new_, c->ancestors); @@ -162,6 +163,13 @@ treeFind(Thread* t, TreeContext* c, object old, intptr_t key, object node, c->ancestors = c->ancestors->next; return; } + + if (++ count > 100) { + // if we've gone this deep, we probably have an unbalanced tree, + // which should only happen if there's a serious bug somewhere + // in our insertion process + abort(t); + } } setTreeNodeValue(t, new_, getTreeNodeValue(t, node)); From 2e0770b0f32976a039335325756428d1d575f2f6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 14 Feb 2011 08:48:44 -0700 Subject: [PATCH 260/274] fix MSVC build MSVC doesn't support __attribute__((__packed__)), but both it and GCC support pack pragmas, so that's what we'll use. --- src/windows.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/windows.cpp b/src/windows.cpp index c4809c072c..5a03a8bc80 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -833,11 +833,13 @@ class MySystem: public System { const char* crashDumpDirectory; }; -struct __attribute__ ((__packed__)) MINIDUMP_EXCEPTION_INFORMATION { +#pragma pack(push,4) +struct MINIDUMP_EXCEPTION_INFORMATION { DWORD thread; LPEXCEPTION_POINTERS exception; BOOL exceptionInCurrentAddressSpace; }; +#pragma pack(pop) struct MINIDUMP_USER_STREAM_INFORMATION; struct MINIDUMP_CALLBACK_INFORMATION; From 468edb97d2d73b6c1df0cccf499e9008ea161789 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 14 Feb 2011 11:47:59 -0700 Subject: [PATCH 261/274] work around GCC name mangling bug It seems that older versions of GCC (4.0 and older, at least) generate assembly files with duplicate symbols for function templates which differ only by the attributes of the templated types. Newer versions have no such problem, but we need to support both, hence the workaround in this commit of using a dedicated, non-template "alias" function where we previously used "cast". --- src/common.h | 21 +++++++++++++++++++-- src/machine.cpp | 8 ++++---- src/machine.h | 13 +++++++------ src/util.cpp | 12 ++++++------ 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/common.h b/src/common.h index d4af04aa32..13957bedfd 100644 --- a/src/common.h +++ b/src/common.h @@ -59,7 +59,15 @@ typedef uint64_t uintptr_t; # error "unsupported architecture" # endif -typedef intptr_t alias_t; +namespace vm { + +inline intptr_t& +alias(void* p, unsigned offset) +{ + return *reinterpret_cast(static_cast(p) + offset); +} + +} // namespace vm #else // not _MSC_VER @@ -88,7 +96,16 @@ typedef intptr_t alias_t; # error "unsupported architecture" # endif -typedef intptr_t __attribute__((__may_alias__)) alias_t; +namespace vm { + +typedef intptr_t __attribute__((__may_alias__)) intptr_alias_t; +inline intptr_alias_t& +alias(void* p, unsigned offset) +{ + return *reinterpret_cast(static_cast(p) + offset); +} + +} // namespace vm #endif // not _MSC_VER diff --git a/src/machine.cpp b/src/machine.cpp index 4933d30f7c..c174f4aafd 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2145,8 +2145,8 @@ class HeapClient: public Heap::Client { memcpy(dst, src, n * BytesPerWord); if (hashTaken(t, src)) { - cast(dst, 0) &= PointerMask; - cast(dst, 0) |= ExtendedMark; + alias(dst, 0) &= PointerMask; + alias(dst, 0) |= ExtendedMark; extendedWord(t, dst, base) = takeHash(t, src); } } @@ -2781,7 +2781,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + alias(o, 0) = FixedMark; t->m->fixedFootprint += total; @@ -2796,7 +2796,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, memset(o, 0, sizeInBytes); - cast(o, 0) = FixedMark; + alias(o, 0) = FixedMark; return o; } diff --git a/src/machine.h b/src/machine.h index 78ce6d5448..af79ca2372 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1878,8 +1878,9 @@ setObjectClass(Thread*, object o, object value) { cast(o, 0) = reinterpret_cast - (reinterpret_cast(value) - | (reinterpret_cast(cast(o, 0)) & (~PointerMask))); + (reinterpret_cast(value) + | (reinterpret_cast + (cast(o, 0)) & (~PointerMask))); } inline const char* @@ -2094,19 +2095,19 @@ setType(Thread* t, Machine::Type type, object value) inline bool objectFixed(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == FixedMark; + return (alias(o, 0) & (~PointerMask)) == FixedMark; } inline bool objectExtended(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == ExtendedMark; + return (alias(o, 0) & (~PointerMask)) == ExtendedMark; } inline bool hashTaken(Thread*, object o) { - return (cast(o, 0) & (~PointerMask)) == HashTakenMark; + return (alias(o, 0) & (~PointerMask)) == HashTakenMark; } inline unsigned @@ -2237,7 +2238,7 @@ markHashTaken(Thread* t, object o) ACQUIRE_RAW(t, t->m->heapLock); - cast(o, 0) |= HashTakenMark; + alias(o, 0) |= HashTakenMark; t->m->heap->pad(o); } diff --git a/src/util.cpp b/src/util.cpp index 7ae8de1217..1c7702d853 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -66,32 +66,32 @@ inline object getTreeNodeValue(Thread*, object n) { return reinterpret_cast - (cast(n, TreeNodeValue) & PointerMask); + (alias(n, TreeNodeValue) & PointerMask); } inline void setTreeNodeValue(Thread* t, object n, object value) { - alias_t red = cast(n, TreeNodeValue) & (~PointerMask); + intptr_t red = alias(n, TreeNodeValue) & (~PointerMask); set(t, n, TreeNodeValue, value); - cast(n, TreeNodeValue) |= red; + alias(n, TreeNodeValue) |= red; } inline bool treeNodeRed(Thread*, object n) { - return (cast(n, TreeNodeValue) & (~PointerMask)) == 1; + return (alias(n, TreeNodeValue) & (~PointerMask)) == 1; } inline void setTreeNodeRed(Thread*, object n, bool red) { if (red) { - cast(n, TreeNodeValue) |= 1; + alias(n, TreeNodeValue) |= 1; } else { - cast(n, TreeNodeValue) &= PointerMask; + alias(n, TreeNodeValue) &= PointerMask; } } From 2f727dc3ce12e0f9c999466055a2ce1c9d3bac4d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 14 Feb 2011 18:53:47 -0700 Subject: [PATCH 262/274] move java.net.PlainDatagramSocketImpl to posix-only openjdk-headers-classes This class is not present in the Windows build of OpenJDK 6u20. --- openjdk-src.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openjdk-src.mk b/openjdk-src.mk index 04edd8d73f..190c8622e9 100644 --- a/openjdk-src.mk +++ b/openjdk-src.mk @@ -98,7 +98,6 @@ openjdk-headers-classes = \ java.net.Inet6AddressImpl \ java.net.NetworkInterface \ java.net.PlainSocketImpl \ - java.net.PlainDatagramSocketImpl \ java.net.SocketInputStream \ java.net.SocketOutputStream \ java.nio.MappedByteBuffer \ @@ -280,6 +279,7 @@ else endif openjdk-headers-classes += \ + java.net.PlainDatagramSocketImpl \ java.io.UnixFileSystem \ sun.nio.ch.InheritedChannel \ sun.nio.ch.EPollArrayWrapper \ From 6e19f4dccadece16e6656f44a62e5024158a7725 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 14 Feb 2011 18:55:11 -0700 Subject: [PATCH 263/274] use vmRun to execute implementations of JVM_MonitorWait/Notify/NotifyAll These methods can all throw exceptions, so they must be run using vmRun to avoid unwinding past the JVM entry points. --- src/classpath-openjdk.cpp | 45 +++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 56782758db..69e4d67b68 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1806,28 +1806,61 @@ EXPORT(JVM_IHashCode)(Thread* t, jobject o) return objectHash(t, *o); } +uint64_t +jvmWait(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + jlong milliseconds; memcpy(&milliseconds, arguments + 1, sizeof(jlong)); + + vm::wait(t, *o, milliseconds); + + return 1; +} + extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorWait)(Thread* t, jobject o, jlong milliseconds) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[1 + (sizeof(jlong) / BytesPerWord)]; + arguments[0] = reinterpret_cast(o); + memcpy(arguments + 1, &milliseconds, sizeof(jlong)); - vm::wait(t, *o, milliseconds); + run(t, jvmWait, arguments); +} + +uint64_t +jvmNotify(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + notify(t, *o); + + return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorNotify)(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o) }; - notify(t, *o); + run(t, jvmNotify, arguments); +} + +uint64_t +jvmNotifyAll(Thread* t, uintptr_t* arguments) +{ + jobject o = reinterpret_cast(arguments[0]); + + notifyAll(t, *o); + + return 1; } extern "C" JNIEXPORT void JNICALL EXPORT(JVM_MonitorNotifyAll)(Thread* t, jobject o) { - ENTER(t, Thread::ActiveState); + uintptr_t arguments[] = { reinterpret_cast(o) }; - notifyAll(t, *o); + run(t, jvmNotifyAll, arguments); } uint64_t From 6461e0a1af69398c831fa14251e405ba04aa9639 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 14 Feb 2011 18:57:47 -0700 Subject: [PATCH 264/274] fix SetEvent assert SetEvent returns nonzero on success, so the assert was backwards. --- src/windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows.cpp b/src/windows.cpp index 5a03a8bc80..4c75b80870 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -96,7 +96,7 @@ class MySystem: public System { if (flags & Waiting) { int r UNUSED = SetEvent(event); - assert(s, r == 0); + assert(s, r != 0); } } From 86c48f3ff67ba7202e4e054257860c58446df4f8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Feb 2011 08:47:48 -0700 Subject: [PATCH 265/274] handle null p->javaThread in addThread and removeThread These functions may be called when p->javaThread is null, in which case we must not try to set the threadPeer field. --- src/machine.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/machine.h b/src/machine.h index af79ca2372..2db27532e7 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1973,7 +1973,9 @@ addThread(Thread* t, Thread* p) p->peer = p->parent->child; p->parent->child = p; - threadPeer(t, p->javaThread) = reinterpret_cast(p); + if (p->javaThread) { + threadPeer(t, p->javaThread) = reinterpret_cast(p); + } } inline void @@ -1989,7 +1991,9 @@ removeThread(Thread* t, Thread* p) p->parent->child = p->peer; - threadPeer(t, p->javaThread) = 0; + if (p->javaThread) { + threadPeer(t, p->javaThread) = 0; + } } inline Thread* From 0bbd11e9be43ad97307772a178ce0d6189fe2a3e Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 15 Feb 2011 21:44:27 -0700 Subject: [PATCH 266/274] return false if javaThread is null in Thread::Runnable::interrupted This field may be null if the thread is in the process of being attached to the VM. --- src/machine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine.h b/src/machine.h index 2db27532e7..c342b9f695 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1500,7 +1500,7 @@ class Thread { } virtual bool interrupted() { - return threadInterrupted(t, t->javaThread); + return t->javaThread and threadInterrupted(t, t->javaThread); } virtual void setInterrupted(bool v) { @@ -2059,10 +2059,10 @@ attachThread(Machine* m, bool daemon) addThread(t, t); - uintptr_t arguments[] = { daemon }; - enter(t, Thread::ActiveState); + uintptr_t arguments[] = { daemon }; + if (run(t, initAttachedThread, arguments)) { enter(t, Thread::IdleState); return t; From c743140e08b026ee2be255dd98822221479c55d4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 16 Feb 2011 11:41:33 -0700 Subject: [PATCH 267/274] add new subroutine test This test covers the case where a local stack slot is first used to store an object reference and later to store a subroutine return address. Unfortunately, this confuses the VM's stack mapping code; I'll be working on a fix for that next. The new test requires generating bytecode from scratch, since there's no reliable way to get javac to generate the code we want. Since we already had primitive bytecode construction code in Proxy.java, I factored it out so we can reuse it in Subroutine.java. --- classpath/avian/Assembler.java | 116 ++++++++ classpath/avian/ConstantPool.java | 242 +++++++++++++++++ classpath/avian/Stream.java | 6 + classpath/java/lang/reflect/Proxy.java | 362 ++++--------------------- makefile | 2 +- test/Subroutine.java | 180 +++++++++--- 6 files changed, 553 insertions(+), 355 deletions(-) create mode 100644 classpath/avian/Assembler.java create mode 100644 classpath/avian/ConstantPool.java diff --git a/classpath/avian/Assembler.java b/classpath/avian/Assembler.java new file mode 100644 index 0000000000..57cd605da8 --- /dev/null +++ b/classpath/avian/Assembler.java @@ -0,0 +1,116 @@ +/* Copyright (c) 2011, 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 avian; + +import static avian.Stream.write1; +import static avian.Stream.write2; +import static avian.Stream.write4; + +import avian.ConstantPool.PoolEntry; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; + +public class Assembler { + public static final int ACC_PUBLIC = 1 << 0; + public static final int ACC_STATIC = 1 << 3; + + public static final int aaload = 0x32; + public static final int aastore = 0x53; + public static final int aload = 0x19; + public static final int aload_0 = 0x2a; + public static final int aload_1 = 0x2b; + public static final int astore_0 = 0x4b; + public static final int anewarray = 0xbd; + public static final int areturn = 0xb0; + public static final int dload = 0x18; + public static final int dreturn = 0xaf; + public static final int dup = 0x59; + public static final int fload = 0x17; + public static final int freturn = 0xae; + public static final int getfield = 0xb4; + public static final int goto_ = 0xa7; + public static final int iload = 0x15; + public static final int invokeinterface = 0xb9; + public static final int invokespecial = 0xb7; + public static final int invokestatic = 0xb8; + public static final int invokevirtual = 0xb6; + public static final int ireturn = 0xac; + public static final int jsr = 0xa8; + public static final int ldc_w = 0x13; + public static final int lload = 0x16; + public static final int lreturn = 0xad; + public static final int new_ = 0xbb; + public static final int pop = 0x57; + public static final int putfield = 0xb5; + public static final int ret = 0xa9; + public static final int return_ = 0xb1; + + public static void writeClass(OutputStream out, + List pool, + int name, + int super_, + int[] interfaces, + MethodData[] methods) + throws IOException + { + int codeAttributeName = ConstantPool.addUtf8(pool, "Code"); + + write4(out, 0xCAFEBABE); + write2(out, 0); // minor version + write2(out, 0); // major version + + write2(out, pool.size() + 1); + for (PoolEntry e: pool) { + e.writeTo(out); + } + + write2(out, 0); // flags + write2(out, name + 1); + write2(out, super_ + 1); + + write2(out, interfaces.length); + for (int i: interfaces) { + write2(out, i + 1); + } + + write2(out, 0); // field count + + write2(out, methods.length); + for (MethodData m: methods) { + write2(out, m.flags); + write2(out, m.nameIndex + 1); + write2(out, m.specIndex + 1); + + write2(out, 1); // attribute count + write2(out, codeAttributeName + 1); + write4(out, m.code.length); + out.write(m.code); + } + + write2(out, 0); // attribute count + } + + public static class MethodData { + public final int flags; + public final int nameIndex; + public final int specIndex; + public final byte[] code; + + public MethodData(int flags, int nameIndex, int specIndex, byte[] code) { + this.flags = flags; + this.nameIndex = nameIndex; + this.specIndex = specIndex; + this.code = code; + } + } +} diff --git a/classpath/avian/ConstantPool.java b/classpath/avian/ConstantPool.java new file mode 100644 index 0000000000..3a1e273c24 --- /dev/null +++ b/classpath/avian/ConstantPool.java @@ -0,0 +1,242 @@ +/* Copyright (c) 2011, 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 avian; + +import static avian.Stream.write1; +import static avian.Stream.write2; +import static avian.Stream.write4; + +import java.util.List; +import java.io.OutputStream; +import java.io.IOException; + +public class ConstantPool { + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_String = 8; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + + public static int add(List pool, PoolEntry e) { + int i = 0; + for (PoolEntry existing: pool) { + if (existing.equals(e)) { + return i; + } else { + ++i; + } + } + pool.add(e); + return pool.size() - 1; + } + + public static int addInteger(List pool, int value) { + return add(pool, new IntegerPoolEntry(value)); + } + + public static int addUtf8(List pool, String value) { + return add(pool, new Utf8PoolEntry(value)); + } + + public static int addString(List pool, String value) { + return add(pool, new StringPoolEntry(addUtf8(pool, value))); + } + + public static int addClass(List pool, String name) { + return add(pool, new ClassPoolEntry(addUtf8(pool, name))); + } + + public static int addNameAndType(List pool, + String name, + String type) + { + return add(pool, new NameAndTypePoolEntry + (addUtf8(pool, name), + addUtf8(pool, type))); + } + + public static int addFieldRef(List pool, + String className, + String name, + String spec) + { + return add(pool, new FieldRefPoolEntry + (addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public static int addMethodRef(List pool, + String className, + String name, + String spec) + { + return add(pool, new MethodRefPoolEntry + (addClass(pool, className), + addNameAndType(pool, name, spec))); + } + + public interface PoolEntry { + public void writeTo(OutputStream out) throws IOException; + } + + private static class IntegerPoolEntry implements PoolEntry { + private final int value; + + public IntegerPoolEntry(int value) { + this.value = value; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Integer); + write4(out, value); + } + + public boolean equals(Object o) { + return o instanceof IntegerPoolEntry + && ((IntegerPoolEntry) o).value == value; + } + } + + private static class Utf8PoolEntry implements PoolEntry { + private final String data; + + public Utf8PoolEntry(String data) { + this.data = data; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Utf8); + byte[] bytes = data.getBytes(); + write2(out, bytes.length); + out.write(bytes); + } + + public boolean equals(Object o) { + return o instanceof Utf8PoolEntry + && ((Utf8PoolEntry) o).data.equals(data); + } + } + + private static class StringPoolEntry implements PoolEntry { + private final int valueIndex; + + public StringPoolEntry(int valueIndex) { + this.valueIndex = valueIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_String); + write2(out, valueIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof StringPoolEntry + && ((StringPoolEntry) o).valueIndex == valueIndex; + } + } + + private static class ClassPoolEntry implements PoolEntry { + private final int nameIndex; + + public ClassPoolEntry(int nameIndex) { + this.nameIndex = nameIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Class); + write2(out, nameIndex + 1); + } + + public boolean equals(Object o) { + return o instanceof ClassPoolEntry + && ((ClassPoolEntry) o).nameIndex == nameIndex; + } + } + + private static class NameAndTypePoolEntry implements PoolEntry { + private final int nameIndex; + private final int typeIndex; + + public NameAndTypePoolEntry(int nameIndex, int typeIndex) { + this.nameIndex = nameIndex; + this.typeIndex = typeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_NameAndType); + write2(out, nameIndex + 1); + write2(out, typeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof NameAndTypePoolEntry) { + NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; + return other.nameIndex == nameIndex && other.typeIndex == typeIndex; + } else { + return false; + } + } + } + + private static class FieldRefPoolEntry implements PoolEntry { + private final int classIndex; + private final int nameAndTypeIndex; + + public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Fieldref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof FieldRefPoolEntry) { + FieldRefPoolEntry other = (FieldRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } + + private static class MethodRefPoolEntry implements PoolEntry { + private final int classIndex; + private final int nameAndTypeIndex; + + public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { + this.classIndex = classIndex; + this.nameAndTypeIndex = nameAndTypeIndex; + } + + public void writeTo(OutputStream out) throws IOException { + write1(out, CONSTANT_Methodref); + write2(out, classIndex + 1); + write2(out, nameAndTypeIndex + 1); + } + + public boolean equals(Object o) { + if (o instanceof MethodRefPoolEntry) { + MethodRefPoolEntry other = (MethodRefPoolEntry) o; + return other.classIndex == classIndex + && other.nameAndTypeIndex == nameAndTypeIndex; + } else { + return false; + } + } + } +} diff --git a/classpath/avian/Stream.java b/classpath/avian/Stream.java index c7f54bb912..14e6fc5773 100644 --- a/classpath/avian/Stream.java +++ b/classpath/avian/Stream.java @@ -71,4 +71,10 @@ public abstract class Stream { (b5 << 24) | (b6 << 16) | (b7 << 8) | (b8)); } + public static void set4(byte[] array, int offset, int v) { + array[offset ] = (byte) ((v >>> 24) & 0xFF); + array[offset + 1] = (byte) ((v >>> 16) & 0xFF); + array[offset + 2] = (byte) ((v >>> 8) & 0xFF); + array[offset + 3] = (byte) ((v ) & 0xFF); + } } diff --git a/classpath/java/lang/reflect/Proxy.java b/classpath/java/lang/reflect/Proxy.java index 27fc88582d..2801f96618 100644 --- a/classpath/java/lang/reflect/Proxy.java +++ b/classpath/java/lang/reflect/Proxy.java @@ -13,6 +13,14 @@ package java.lang.reflect; import static avian.Stream.write1; import static avian.Stream.write2; import static avian.Stream.write4; +import static avian.Stream.set4; +import static avian.Assembler.*; + +import avian.ConstantPool; +import avian.ConstantPool.PoolEntry; + +import avian.Assembler; +import avian.Assembler.MethodData; import java.util.List; import java.util.ArrayList; @@ -23,40 +31,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; public class Proxy { - private static final int CONSTANT_Integer = 3; - private static final int CONSTANT_Utf8 = 1; - private static final int CONSTANT_Class = 7; - private static final int CONSTANT_NameAndType = 12; - private static final int CONSTANT_Fieldref = 9; - private static final int CONSTANT_Methodref = 10; - - private static final int aaload = 0x32; - private static final int aastore = 0x53; - private static final int aload = 0x19; - private static final int aload_0 = 0x2a; - private static final int aload_1 = 0x2b; - private static final int anewarray = 0xbd; - private static final int areturn = 0xb0; - private static final int dload = 0x18; - private static final int dreturn = 0xaf; - private static final int dup = 0x59; - private static final int fload = 0x17; - private static final int freturn = 0xae; - private static final int getfield = 0xb4; - private static final int iload = 0x15; - private static final int invokeinterface = 0xb9; - private static final int invokespecial = 0xb7; - private static final int invokestatic = 0xb8; - private static final int invokevirtual = 0xb6; - private static final int ireturn = 0xac; - private static final int ldc_w = 0x13; - private static final int lload = 0x16; - private static final int lreturn = 0xad; - private static final int new_ = 0xbb; - private static final int pop = 0x57; - private static final int putfield = 0xb5; - private static final int return_ = 0xb1; - private static int nextNumber; protected InvocationHandler h; @@ -92,67 +66,6 @@ public class Proxy { return ((Proxy) proxy).h; } - private static void set4(byte[] array, int offset, int v) { - array[offset ] = (byte) ((v >>> 24) & 0xFF); - array[offset + 1] = (byte) ((v >>> 16) & 0xFF); - array[offset + 2] = (byte) ((v >>> 8) & 0xFF); - array[offset + 3] = (byte) ((v ) & 0xFF); - } - - private static int poolAdd(List pool, PoolEntry e) { - int i = 0; - for (PoolEntry existing: pool) { - if (existing.equals(e)) { - return i; - } else { - ++i; - } - } - pool.add(e); - return pool.size() - 1; - } - - private static int poolAddInteger(List pool, int value) { - return poolAdd(pool, new IntegerPoolEntry(value)); - } - - private static int poolAddUtf8(List pool, String value) { - return poolAdd(pool, new Utf8PoolEntry(value)); - } - - private static int poolAddClass(List pool, String name) { - return poolAdd(pool, new ClassPoolEntry(poolAddUtf8(pool, name))); - } - - private static int poolAddNameAndType(List pool, - String name, - String type) - { - return poolAdd(pool, new NameAndTypePoolEntry - (poolAddUtf8(pool, name), - poolAddUtf8(pool, type))); - } - - private static int poolAddFieldRef(List pool, - String className, - String name, - String spec) - { - return poolAdd(pool, new FieldRefPoolEntry - (poolAddClass(pool, className), - poolAddNameAndType(pool, name, spec))); - } - - private static int poolAddMethodRef(List pool, - String className, - String name, - String spec) - { - return poolAdd(pool, new MethodRefPoolEntry - (poolAddClass(pool, className), - poolAddNameAndType(pool, name, spec))); - } - private static byte[] makeInvokeCode(List pool, String className, byte[] spec, @@ -168,37 +81,37 @@ public class Proxy { write1(out, aload_0); write1(out, getfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, aload_0); write1(out, new_); - write2(out, poolAddClass(pool, "java/lang/reflect/Method") + 1); + write2(out, ConstantPool.addClass(pool, "java/lang/reflect/Method") + 1); write1(out, dup); write1(out, ldc_w); - write2(out, poolAddClass(pool, className) + 1); + write2(out, ConstantPool.addClass(pool, className) + 1); write1(out, getfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/Class", "vmClass", "Lavian/VMClass;") + 1); write1(out, getfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "avian/VMClass", "methodTable", "[Lavian/VMMethod;") + 1); write1(out, ldc_w); - write2(out, poolAddInteger(pool, index) + 1); + write2(out, ConstantPool.addInteger(pool, index) + 1); write1(out, aaload); write1(out, invokespecial); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/reflect/Method", "", "(Lavian/VMMethod;)V") + 1); write1(out, ldc_w); - write2(out, poolAddInteger(pool, parameterCount) + 1); + write2(out, ConstantPool.addInteger(pool, parameterCount) + 1); write1(out, anewarray); - write2(out, poolAddClass(pool, "java/lang/Object") + 1); + write2(out, ConstantPool.addClass(pool, "java/lang/Object") + 1); int ai = 0; int si; @@ -206,7 +119,7 @@ public class Proxy { write1(out, dup); write1(out, ldc_w); - write2(out, poolAddInteger(pool, ai) + 1); + write2(out, ConstantPool.addInteger(pool, ai) + 1); switch (spec[si]) { case 'L': @@ -239,7 +152,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;") + 1); break; @@ -249,7 +162,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;") + 1); break; @@ -259,7 +172,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;") + 1); break; @@ -269,7 +182,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;") + 1); break; @@ -279,7 +192,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;") + 1); break; @@ -289,7 +202,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;") + 1); break; @@ -299,7 +212,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;") + 1); ++ ai; @@ -310,7 +223,7 @@ public class Proxy { write1(out, ai + 1); write1(out, invokestatic); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;") + 1); ++ ai; @@ -325,7 +238,7 @@ public class Proxy { } write1(out, invokeinterface); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;" @@ -342,56 +255,56 @@ public class Proxy { case 'Z': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Boolean", "booleanValue", "()Z") + 1); write1(out, ireturn); break; case 'B': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Byte", "byteValue", "()B") + 1); write1(out, ireturn); break; case 'C': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Character", "charValue", "()C") + 1); write1(out, ireturn); break; case 'S': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Short", "shortValue", "()S") + 1); write1(out, ireturn); break; case 'I': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Integer", "intValue", "()I") + 1); write1(out, ireturn); break; case 'F': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Float", "floatValue", "()F") + 1); write1(out, freturn); break; case 'J': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Long", "longValue", "()J") + 1); write1(out, lreturn); break; case 'D': write1(out, invokevirtual); - write2(out, poolAddMethodRef + write2(out, ConstantPool.addMethodRef (pool, "java/lang/Double", "doubleValue", "()D") + 1); write1(out, dreturn); break; @@ -424,7 +337,7 @@ public class Proxy { write1(out, aload_0); write1(out, aload_1); write1(out, putfield); - write2(out, poolAddFieldRef + write2(out, ConstantPool.addFieldRef (pool, "java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;") + 1); write1(out, return_); @@ -444,7 +357,8 @@ public class Proxy { int[] interfaceIndexes = new int[interfaces.length]; for (int i = 0; i < interfaces.length; ++i) { - interfaceIndexes[i] = poolAddClass(pool, interfaces[i].getName()); + interfaceIndexes[i] = ConstantPool.addClass + (pool, interfaces[i].getName()); } Map virtualMap = new HashMap(); @@ -461,57 +375,28 @@ public class Proxy { { int i = 0; for (avian.VMMethod m: virtualMap.values()) { methodTable[i] = new MethodData - (poolAddUtf8(pool, Method.getName(m)), - poolAddUtf8(pool, Method.getSpec(m)), + (0, + ConstantPool.addUtf8(pool, Method.getName(m)), + ConstantPool.addUtf8(pool, Method.getSpec(m)), makeInvokeCode(pool, name, m.spec, m.parameterCount, m.parameterFootprint, i)); ++ i; } methodTable[i++] = new MethodData - (poolAddUtf8(pool, ""), - poolAddUtf8(pool, "(Ljava/lang/reflect/InvocationHandler;)V"), + (0, + ConstantPool.addUtf8(pool, ""), + ConstantPool.addUtf8 + (pool, "(Ljava/lang/reflect/InvocationHandler;)V"), makeConstructorCode(pool)); } - int nameIndex = poolAddClass(pool, name); - int superIndex = poolAddClass(pool, "java/lang/reflect/Proxy"); - int codeAttributeNameIndex = poolAddUtf8(pool, "Code"); + int nameIndex = ConstantPool.addClass(pool, name); + int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy"); ByteArrayOutputStream out = new ByteArrayOutputStream(); - write4(out, 0xCAFEBABE); - write2(out, 0); // minor version - write2(out, 0); // major version - - write2(out, pool.size() + 1); - for (PoolEntry e: pool) { - e.writeTo(out); - } - - write2(out, 0); // flags - write2(out, nameIndex + 1); - write2(out, superIndex + 1); - - write2(out, interfaces.length); - for (int i: interfaceIndexes) { - write2(out, i + 1); - } - - write2(out, 0); // field count - - write2(out, methodTable.length); - for (MethodData m: methodTable) { - write2(out, 0); // flags - write2(out, m.nameIndex + 1); - write2(out, m.specIndex + 1); - - write2(out, 1); // attribute count - write2(out, codeAttributeNameIndex + 1); - write4(out, m.code.length); - out.write(m.code); - } - - write2(out, 0); // attribute count + Assembler.writeClass + (out, pool, nameIndex, superIndex, interfaceIndexes, methodTable); byte[] classData = out.toByteArray(); return avian.SystemClassLoader.getClass @@ -532,153 +417,4 @@ public class Proxy { throw error; } } - - private static class MethodData { - public final int nameIndex; - public final int specIndex; - public final byte[] code; - - public MethodData(int nameIndex, int specIndex, byte[] code) { - this.nameIndex = nameIndex; - this.specIndex = specIndex; - this.code = code; - } - } - - public interface PoolEntry { - public void writeTo(OutputStream out) throws IOException; - } - - public static class IntegerPoolEntry implements PoolEntry { - private final int value; - - public IntegerPoolEntry(int value) { - this.value = value; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Integer); - write4(out, value); - } - - public boolean equals(Object o) { - return o instanceof IntegerPoolEntry - && ((IntegerPoolEntry) o).value == value; - } - } - - public static class Utf8PoolEntry implements PoolEntry { - private final String data; - - public Utf8PoolEntry(String data) { - this.data = data; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Utf8); - byte[] bytes = data.getBytes(); - write2(out, bytes.length); - out.write(bytes); - } - - public boolean equals(Object o) { - return o instanceof Utf8PoolEntry - && ((Utf8PoolEntry) o).data.equals(data); - } - } - - public static class ClassPoolEntry implements PoolEntry { - private final int nameIndex; - - public ClassPoolEntry(int nameIndex) { - this.nameIndex = nameIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Class); - write2(out, nameIndex + 1); - } - - public boolean equals(Object o) { - return o instanceof ClassPoolEntry - && ((ClassPoolEntry) o).nameIndex == nameIndex; - } - } - - public static class NameAndTypePoolEntry implements PoolEntry { - private final int nameIndex; - private final int typeIndex; - - public NameAndTypePoolEntry(int nameIndex, int typeIndex) { - this.nameIndex = nameIndex; - this.typeIndex = typeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_NameAndType); - write2(out, nameIndex + 1); - write2(out, typeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof NameAndTypePoolEntry) { - NameAndTypePoolEntry other = (NameAndTypePoolEntry) o; - return other.nameIndex == nameIndex && other.typeIndex == typeIndex; - } else { - return false; - } - } - } - - public static class FieldRefPoolEntry implements PoolEntry { - private final int classIndex; - private final int nameAndTypeIndex; - - public FieldRefPoolEntry(int classIndex, int nameAndTypeIndex) { - this.classIndex = classIndex; - this.nameAndTypeIndex = nameAndTypeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Fieldref); - write2(out, classIndex + 1); - write2(out, nameAndTypeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof FieldRefPoolEntry) { - FieldRefPoolEntry other = (FieldRefPoolEntry) o; - return other.classIndex == classIndex - && other.nameAndTypeIndex == nameAndTypeIndex; - } else { - return false; - } - } - } - - public static class MethodRefPoolEntry implements PoolEntry { - private final int classIndex; - private final int nameAndTypeIndex; - - public MethodRefPoolEntry(int classIndex, int nameAndTypeIndex) { - this.classIndex = classIndex; - this.nameAndTypeIndex = nameAndTypeIndex; - } - - public void writeTo(OutputStream out) throws IOException { - write1(out, CONSTANT_Methodref); - write2(out, classIndex + 1); - write2(out, nameAndTypeIndex + 1); - } - - public boolean equals(Object o) { - if (o instanceof MethodRefPoolEntry) { - MethodRefPoolEntry other = (MethodRefPoolEntry) o; - return other.classIndex == classIndex - && other.nameAndTypeIndex == nameAndTypeIndex; - } else { - return false; - } - } - } } diff --git a/makefile b/makefile index 8258b819a9..0ab4f780ec 100644 --- a/makefile +++ b/makefile @@ -636,7 +636,7 @@ $(test-dep): $(test-sources) $(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \ fi $(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \ - test/Subroutine.java + -bootclasspath $(boot-classpath) test/Subroutine.java @touch $(@) $(test-extra-dep): $(test-extra-sources) diff --git a/test/Subroutine.java b/test/Subroutine.java index d46bafe543..c44c5df8ef 100644 --- a/test/Subroutine.java +++ b/test/Subroutine.java @@ -1,8 +1,93 @@ +import avian.Stream; +import avian.ConstantPool; +import avian.ConstantPool.PoolEntry; +import avian.Assembler; +import avian.Assembler.MethodData; + +import java.util.ArrayList; +import java.util.List; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.IOException; + public class Subroutine { private static void expect(boolean v) { if (! v) throw new RuntimeException(); } + private static byte[] makeTestCode(List pool) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Stream.write2(out, 1); // max stack + Stream.write2(out, 1); // max locals + Stream.write4(out, 0); // length (we'll set the real value later) + + // 0: + Stream.write1(out, Assembler.ldc_w); + Stream.write2(out, ConstantPool.addString(pool, "foo") + 1); + + // 3: + Stream.write1(out, Assembler.astore_0); + + // 4: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 7: + Stream.write1(out, Assembler.goto_); + Stream.write2(out, 9); // 16 + + // 10: + Stream.write1(out, Assembler.astore_0); + + // 11: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 14: + Stream.write1(out, Assembler.ret); + Stream.write1(out, 0); + + // 16: + Stream.write1(out, Assembler.jsr); + Stream.write2(out, -6); // 10 + + // 19: + Stream.write1(out, Assembler.invokestatic); + Stream.write2(out, ConstantPool.addMethodRef + (pool, "java/lang/System", "gc", "()V") + 1); + + // 22: + Stream.write1(out, Assembler.return_); + + Stream.write2(out, 0); // exception handler table length + Stream.write2(out, 0); // attribute count + + byte[] result = out.toByteArray(); + Stream.set4(result, 4, result.length - 12); + + return result; + } + + private static Class makeTestClass() throws IOException { + List pool = new ArrayList(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + String name = "$SubroutineTest$"; + + Assembler.writeClass + (out, pool, ConstantPool.addClass(pool, name), + ConstantPool.addClass(pool, "java/lang/Object"), + new int[0], new MethodData[] + { new MethodData(Assembler.ACC_STATIC | Assembler.ACC_PUBLIC, + ConstantPool.addUtf8(pool, "test"), + ConstantPool.addUtf8(pool, "()V"), + makeTestCode(pool)) }); + + return new MyClassLoader(Subroutine.class.getClassLoader()) + .defineClass(name, out.toByteArray()); + } + // These tests are intended to cover the jsr and ret instructions. // However, recent Sun javac versions avoid generating these // instructions by default, so we must compile this class using @@ -138,7 +223,7 @@ public class Subroutine { } } - public boolean test5(boolean predicate) { + private boolean test5(boolean predicate) { try { if (predicate) { return false; @@ -151,60 +236,73 @@ public class Subroutine { return true; } - public static void main(String[] args) { - test(false, false); - test(false, true); - test(true, false); + public static void main(String[] args) throws Exception { + // test(false, false); + // test(false, true); + // test(true, false); - String.valueOf(test2(1)); - String.valueOf(test2(2)); - String.valueOf(test2(3)); + // String.valueOf(test2(1)); + // String.valueOf(test2(2)); + // String.valueOf(test2(3)); - String.valueOf(test3(1, 1, 1)); - String.valueOf(test3(2, 1, 1)); - String.valueOf(test3(3, 1, 1)); + // String.valueOf(test3(1, 1, 1)); + // String.valueOf(test3(2, 1, 1)); + // String.valueOf(test3(3, 1, 1)); - String.valueOf(test3(1, 2, 1)); - String.valueOf(test3(2, 2, 1)); - String.valueOf(test3(3, 2, 1)); + // String.valueOf(test3(1, 2, 1)); + // String.valueOf(test3(2, 2, 1)); + // String.valueOf(test3(3, 2, 1)); - String.valueOf(test3(1, 3, 1)); - String.valueOf(test3(2, 3, 1)); - String.valueOf(test3(3, 3, 1)); + // String.valueOf(test3(1, 3, 1)); + // String.valueOf(test3(2, 3, 1)); + // String.valueOf(test3(3, 3, 1)); - String.valueOf(test3(1, 1, 2)); - String.valueOf(test3(2, 1, 2)); - String.valueOf(test3(3, 1, 2)); + // String.valueOf(test3(1, 1, 2)); + // String.valueOf(test3(2, 1, 2)); + // String.valueOf(test3(3, 1, 2)); - String.valueOf(test3(1, 2, 2)); - String.valueOf(test3(2, 2, 2)); - String.valueOf(test3(3, 2, 2)); + // String.valueOf(test3(1, 2, 2)); + // String.valueOf(test3(2, 2, 2)); + // String.valueOf(test3(3, 2, 2)); - String.valueOf(test3(1, 3, 2)); - String.valueOf(test3(2, 3, 2)); - String.valueOf(test3(3, 3, 2)); + // String.valueOf(test3(1, 3, 2)); + // String.valueOf(test3(2, 3, 2)); + // String.valueOf(test3(3, 3, 2)); - String.valueOf(test3(1, 1, 3)); - String.valueOf(test3(2, 1, 3)); - String.valueOf(test3(3, 1, 3)); + // String.valueOf(test3(1, 1, 3)); + // String.valueOf(test3(2, 1, 3)); + // String.valueOf(test3(3, 1, 3)); - String.valueOf(test3(1, 2, 3)); - String.valueOf(test3(2, 2, 3)); - String.valueOf(test3(3, 2, 3)); + // String.valueOf(test3(1, 2, 3)); + // String.valueOf(test3(2, 2, 3)); + // String.valueOf(test3(3, 2, 3)); - String.valueOf(test3(1, 3, 3)); - String.valueOf(test3(2, 3, 3)); - String.valueOf(test3(3, 3, 3)); + // String.valueOf(test3(1, 3, 3)); + // String.valueOf(test3(2, 3, 3)); + // String.valueOf(test3(3, 3, 3)); - String.valueOf(test4(1)); - String.valueOf(test4(2)); - String.valueOf(test4(3)); + // String.valueOf(test4(1)); + // String.valueOf(test4(2)); + // String.valueOf(test4(3)); - expect(test4(1) == 0xFABFABFABFL); + // expect(test4(1) == 0xFABFABFABFL); - new Subroutine().test5(true); - new Subroutine().test5(false); + // new Subroutine().test5(true); + // new Subroutine().test5(false); + + makeTestClass().getMethod("test", new Class[0]).invoke + (null, new Object[0]); } private static class DummyException extends RuntimeException { } + + private static class MyClassLoader extends ClassLoader { + public MyClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] bytes) { + return super.defineClass(name, bytes, 0, bytes.length); + } + } } From 59183c78216135a2fbe58323b76a4dc5944c65cc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 16 Feb 2011 14:29:57 -0700 Subject: [PATCH 268/274] fix subroutine stack mapping bug leading to crashes during GC The stack mapping code was broken for cases of stack slots being reused to hold primitives or addresses within subroutines after previously being used to hold object references. We now bitwise "and" the stack map upon return from the subroutine with the map as it existed prior to calling the subroutine, which has the effect of clearing map locations previously marked as GC roots where appropriate. --- src/compile.cpp | 35 +++++++++++++++--- test/Subroutine.java | 84 ++++++++++++++++++++++---------------------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/compile.cpp b/src/compile.cpp index 12189c216a..37374f03c0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -5288,7 +5288,8 @@ calculateTryCatchRoots(Context* context, SubroutinePath* subroutinePath, unsigned calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, - unsigned eventIndex, SubroutinePath* subroutinePath = 0) + unsigned eventIndex, SubroutinePath* subroutinePath = 0, + uintptr_t* resultRoots = 0) { // for each instruction with more than one predecessor, and for each // stack position, determine if there exists a path to that @@ -5321,11 +5322,12 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, switch (e) { case PushContextEvent: { eventIndex = calculateFrameMaps - (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath); + (t, context, RUNTIME_ARRAY_BODY(roots), eventIndex, subroutinePath, + resultRoots); } break; case PopContextEvent: - return eventIndex; + goto exit; case IpEvent: { ip = context->eventLog.get2(eventIndex); @@ -5491,18 +5493,41 @@ calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots, makeRootTable(t, &(context->zone), context->method)); } + THREAD_RUNTIME_ARRAY(t, uintptr_t, subroutineRoots, mapSize); + calculateFrameMaps (t, context, RUNTIME_ARRAY_BODY(roots), call->subroutine->logIndex, - path); + path, RUNTIME_ARRAY_BODY(subroutineRoots)); + + for (unsigned wi = 0; wi < mapSize; ++wi) { + RUNTIME_ARRAY_BODY(roots)[wi] + &= RUNTIME_ARRAY_BODY(subroutineRoots)[wi]; + } } break; case PopSubroutineEvent: - return static_cast(-1); + eventIndex = static_cast(-1); + goto exit; default: abort(t); } } + exit: + if (resultRoots and ip != -1) { + if (DebugFrameMaps) { + fprintf(stderr, "result roots at ip %3d: ", ip); + printSet(*RUNTIME_ARRAY_BODY(roots), mapSize); + if (subroutinePath) { + fprintf(stderr, " "); + print(subroutinePath); + } + fprintf(stderr, "\n"); + } + + memcpy(resultRoots, RUNTIME_ARRAY_BODY(roots), mapSize * BytesPerWord); + } + return eventIndex; } diff --git a/test/Subroutine.java b/test/Subroutine.java index c44c5df8ef..b02ec9ba81 100644 --- a/test/Subroutine.java +++ b/test/Subroutine.java @@ -31,7 +31,7 @@ public class Subroutine { // 4: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef - (pool, "java/lang/System", "gc", "()V") + 1); + (pool, "java/lang/System", "gc", "()V") + 1); // 7: Stream.write1(out, Assembler.goto_); @@ -43,7 +43,7 @@ public class Subroutine { // 11: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef - (pool, "java/lang/System", "gc", "()V") + 1); + (pool, "java/lang/System", "gc", "()V") + 1); // 14: Stream.write1(out, Assembler.ret); @@ -56,7 +56,7 @@ public class Subroutine { // 19: Stream.write1(out, Assembler.invokestatic); Stream.write2(out, ConstantPool.addMethodRef - (pool, "java/lang/System", "gc", "()V") + 1); + (pool, "java/lang/System", "gc", "()V") + 1); // 22: Stream.write1(out, Assembler.return_); @@ -237,58 +237,58 @@ public class Subroutine { } public static void main(String[] args) throws Exception { - // test(false, false); - // test(false, true); - // test(true, false); + test(false, false); + test(false, true); + test(true, false); - // String.valueOf(test2(1)); - // String.valueOf(test2(2)); - // String.valueOf(test2(3)); + String.valueOf(test2(1)); + String.valueOf(test2(2)); + String.valueOf(test2(3)); - // String.valueOf(test3(1, 1, 1)); - // String.valueOf(test3(2, 1, 1)); - // String.valueOf(test3(3, 1, 1)); + String.valueOf(test3(1, 1, 1)); + String.valueOf(test3(2, 1, 1)); + String.valueOf(test3(3, 1, 1)); - // String.valueOf(test3(1, 2, 1)); - // String.valueOf(test3(2, 2, 1)); - // String.valueOf(test3(3, 2, 1)); + String.valueOf(test3(1, 2, 1)); + String.valueOf(test3(2, 2, 1)); + String.valueOf(test3(3, 2, 1)); - // String.valueOf(test3(1, 3, 1)); - // String.valueOf(test3(2, 3, 1)); - // String.valueOf(test3(3, 3, 1)); + String.valueOf(test3(1, 3, 1)); + String.valueOf(test3(2, 3, 1)); + String.valueOf(test3(3, 3, 1)); - // String.valueOf(test3(1, 1, 2)); - // String.valueOf(test3(2, 1, 2)); - // String.valueOf(test3(3, 1, 2)); + String.valueOf(test3(1, 1, 2)); + String.valueOf(test3(2, 1, 2)); + String.valueOf(test3(3, 1, 2)); - // String.valueOf(test3(1, 2, 2)); - // String.valueOf(test3(2, 2, 2)); - // String.valueOf(test3(3, 2, 2)); + String.valueOf(test3(1, 2, 2)); + String.valueOf(test3(2, 2, 2)); + String.valueOf(test3(3, 2, 2)); - // String.valueOf(test3(1, 3, 2)); - // String.valueOf(test3(2, 3, 2)); - // String.valueOf(test3(3, 3, 2)); + String.valueOf(test3(1, 3, 2)); + String.valueOf(test3(2, 3, 2)); + String.valueOf(test3(3, 3, 2)); - // String.valueOf(test3(1, 1, 3)); - // String.valueOf(test3(2, 1, 3)); - // String.valueOf(test3(3, 1, 3)); + String.valueOf(test3(1, 1, 3)); + String.valueOf(test3(2, 1, 3)); + String.valueOf(test3(3, 1, 3)); - // String.valueOf(test3(1, 2, 3)); - // String.valueOf(test3(2, 2, 3)); - // String.valueOf(test3(3, 2, 3)); + String.valueOf(test3(1, 2, 3)); + String.valueOf(test3(2, 2, 3)); + String.valueOf(test3(3, 2, 3)); - // String.valueOf(test3(1, 3, 3)); - // String.valueOf(test3(2, 3, 3)); - // String.valueOf(test3(3, 3, 3)); + String.valueOf(test3(1, 3, 3)); + String.valueOf(test3(2, 3, 3)); + String.valueOf(test3(3, 3, 3)); - // String.valueOf(test4(1)); - // String.valueOf(test4(2)); - // String.valueOf(test4(3)); + String.valueOf(test4(1)); + String.valueOf(test4(2)); + String.valueOf(test4(3)); - // expect(test4(1) == 0xFABFABFABFL); + expect(test4(1) == 0xFABFABFABFL); - // new Subroutine().test5(true); - // new Subroutine().test5(false); + new Subroutine().test5(true); + new Subroutine().test5(false); makeTestClass().getMethod("test", new Class[0]).invoke (null, new Object[0]); From 2216b22ccbac5b1e717959abe0ddbb74a4e5eb11 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Feb 2011 14:11:37 -0700 Subject: [PATCH 269/274] add lib/currency.data to javahome-files on Windows This file is needed by OpenJDK for both Windows and Posix systems. --- makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/makefile b/makefile index 0ab4f780ec..dcd331b8d2 100644 --- a/makefile +++ b/makefile @@ -86,11 +86,9 @@ ifneq ($(openjdk),) openjdk-jar-dep = $(build)/openjdk-jar.dep classpath-jar-dep = $(openjdk-jar-dep) javahome = $(embed-prefix)/javahomeJar - javahome-files = lib/zi + javahome-files = lib/zi lib/currency.data ifeq ($(platform),windows) javahome-files += lib/tzmappings - else - javahome-files += lib/currency.data endif javahome-object = $(build)/javahome-jar.o boot-javahome-object = $(build)/boot-javahome.o From c761ac671780a4ebe9bbf6a3cfd0dfee2625e01b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Feb 2011 14:28:51 -0700 Subject: [PATCH 270/274] fix Subroutine test for use with OpenJDK build --- classpath/avian/Assembler.java | 2 +- makefile | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/classpath/avian/Assembler.java b/classpath/avian/Assembler.java index 57cd605da8..3e1eae271b 100644 --- a/classpath/avian/Assembler.java +++ b/classpath/avian/Assembler.java @@ -74,7 +74,7 @@ public class Assembler { e.writeTo(out); } - write2(out, 0); // flags + write2(out, ACC_PUBLIC); // flags write2(out, name + 1); write2(out, super_ + 1); diff --git a/makefile b/makefile index dcd331b8d2..cb00635cbc 100644 --- a/makefile +++ b/makefile @@ -501,17 +501,23 @@ dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) executable-dynamic = $(build)/$(name)-dynamic${exe-suffix} ifneq ($(classpath),avian) +# Assembler, ConstantPool, and Stream are not technically needed for a +# working build, but we include them since our Subroutine test uses +# them to synthesize a class: classpath-sources := \ - $(classpath-src)/avian/Continuations.java \ + $(classpath-src)/avian/Addendum.java \ + $(classpath-src)/avian/Assembler.java \ $(classpath-src)/avian/Callback.java \ $(classpath-src)/avian/CallbackReceiver.java \ - $(classpath-src)/avian/IncompatibleContinuationException.java \ - $(classpath-src)/avian/SystemClassLoader.java \ - $(classpath-src)/avian/Machine.java \ - $(classpath-src)/avian/Addendum.java \ $(classpath-src)/avian/ClassAddendum.java \ - $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/ConstantPool.java \ + $(classpath-src)/avian/Continuations.java \ $(classpath-src)/avian/FieldAddendum.java \ + $(classpath-src)/avian/IncompatibleContinuationException.java \ + $(classpath-src)/avian/Machine.java \ + $(classpath-src)/avian/MethodAddendum.java \ + $(classpath-src)/avian/Stream.java \ + $(classpath-src)/avian/SystemClassLoader.java \ $(classpath-src)/avian/VMClass.java \ $(classpath-src)/avian/VMField.java \ $(classpath-src)/avian/VMMethod.java \ From 1ca8a207313502e67c1209ebecf1aaff10a30cfc Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 17 Feb 2011 17:39:41 -0700 Subject: [PATCH 271/274] enable i686-apple-darwin8 cross compile --- makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 0ab4f780ec..8a40669a95 100644 --- a/makefile +++ b/makefile @@ -215,9 +215,20 @@ ifeq ($(arch),arm) endif ifeq ($(platform),darwin) + ifneq ($(build-platform),darwin) + cxx = i686-apple-darwin8-g++ $(mflag) + cc = i686-apple-darwin8-gcc $(mflag) + ar = i686-apple-darwin8-ar + ranlib = i686-apple-darwin8-ranlib + strip = i686-apple-darwin8-strip + extra-cflags = -I$(JAVA_HOME)/include/linux + else + build-lflags += -framework CoreFoundation + endif + + build-cflags = $(common-cflags) $(extra-cflags) -fPIC -fvisibility=hidden \ + -I$(src) version-script-flag = - build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) - build-lflags += -framework CoreFoundation lflags = $(common-lflags) -ldl -framework CoreFoundation \ -framework CoreServices ifeq ($(bootimage),true) From 2ce549d3f83a4e86734073d47f7d39b501e75131 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Feb 2011 14:07:45 -0700 Subject: [PATCH 272/274] fix GC safety bug in jvmGetClassInterfaces --- src/classpath-openjdk.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 69e4d67b68..ab7ba61179 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2722,6 +2722,8 @@ jvmGetClassInterfaces(Thread* t, uintptr_t* arguments) object table = classInterfaceTable(t, jclassVmClass(t, *c)); if (table) { + PROTECT(t, table); + unsigned stride = (classFlags(t, jclassVmClass(t, *c)) & ACC_INTERFACE) == 0 ? 2 : 1; From 00307b9b3037a6bf3ce7d21fba8ea0ff7fef0feb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Feb 2011 14:20:02 -0700 Subject: [PATCH 273/274] fix Mac OS MySystem::visit and MySystem::Thread::interrupt implementations On Mac OS, signals sent using pthread_kill are never delivered if the target thread is blocked (e.g. acquiring a lock or waiting on a condition), so we can't rely on it and must use the Mach-specific thread execution API instead to implement Thread.getStackTrace. For Thread.interrupt, we must not only use pthread_kill but also pthread_cond_signal to ensure the thread is woken up. --- src/posix.cpp | 39 ++++++++++++++++++++++-- src/powerpc.h | 35 ++++++++++++++++------ src/x86.h | 82 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 53dfb0bb90..4187a8e4b6 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,6 +14,7 @@ # include "CoreFoundation/CoreFoundation.h" # undef assert # define _XOPEN_SOURCE +# define _DARWIN_C_SOURCE #endif #include "sys/mman.h" @@ -144,6 +145,12 @@ class MySystem: public System { r->setInterrupted(true); pthread_kill(thread, InterruptSignal); + + // pthread_kill won't necessarily wake a thread blocked in + // pthread_cond_{timed}wait (it does on Linux but not Mac OS), + // so we signal the condition as well: + int rv UNUSED = pthread_cond_signal(&condition); + expect(s, rv == 0); } virtual void join() { @@ -641,14 +648,41 @@ class MySystem: public System { return registerHandler(handler, DivideByZeroSignalIndex); } - virtual Status visit(System::Thread* st, System::Thread* sTarget, + virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { assert(this, st != sTarget); - Thread* t = static_cast(st); Thread* target = static_cast(sTarget); +#ifdef __APPLE__ + // On Mac OS, signals sent using pthread_kill are never delivered + // if the target thread is blocked (e.g. acquiring a lock or + // waiting on a condition), so we can't rely on it and must use + // the Mach-specific thread execution API instead. + + mach_port_t port = pthread_mach_thread_np(target->thread); + + if (thread_suspend(port)) return -1; + + THREAD_STATE_TYPE state; + mach_msg_type_number_t stateCount = THREAD_STATE_COUNT; + kern_return_t rv = thread_get_state + (port, THREAD_STATE, reinterpret_cast(&state), + &stateCount); + + if (rv == 0) { + visitor->visit(reinterpret_cast(THREAD_STATE_IP(state)), + reinterpret_cast(THREAD_STATE_STACK(state)), + reinterpret_cast(THREAD_STATE_LINK(state))); + } + + thread_resume(port); + + return rv ? -1 : 0; +#else // not __APPLE__ + Thread* t = static_cast(st); + ACQUIRE_MONITOR(t, visitLock); while (threadVisitor) visitLock->wait(t, 0); @@ -674,6 +708,7 @@ class MySystem: public System { system->visitLock->notifyAll(t); return result; +#endif // not __APPLE__ } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, diff --git a/src/powerpc.h b/src/powerpc.h index b109c9dc5a..b519ac8064 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,20 +14,37 @@ #include "types.h" #include "common.h" -#define VA_LIST(x) (&x) +#define VA_LIST(x) (&(x)) #ifdef __APPLE__ +# include "mach/mach_types.h" +# include "mach/ppc/thread_act.h" +# include "mach/ppc/thread_status.h" + +# define THREAD_STATE PPC_THREAD_STATE +# define THREAD_STATE_TYPE ppc_thread_state_t +# define THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT + # if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r13) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__lr) +# define FIELD(x) __##x # else -# define IP_REGISTER(context) (context->uc_mcontext->ss.srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.r13) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.lr) +# define FIELD(x) x # endif + +# define THREAD_STATE_IP(state) ((state).FIELD(srr0)) +# define THREAD_STATE_STACK(state) ((state).FIELD(r1)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(r13)) +# define THREAD_STATE_LINK(state) ((state).FIELD(lr)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) + #else # error "non-Apple PowerPC-based platforms not yet supported" #endif diff --git a/src/x86.h b/src/x86.h index f393ad8727..9a0b60cccd 100644 --- a/src/x86.h +++ b/src/x86.h @@ -23,27 +23,47 @@ #endif #if (defined ARCH_x86_32) || (defined PLATFORM_WINDOWS) -# define VA_LIST(x) (&x) +# define VA_LIST(x) (&(x)) #else # define VA_LIST(x) (x) #endif +#ifdef __APPLE__ +# include "mach/mach_types.h" +# include "mach/i386/thread_act.h" +# include "mach/i386/thread_status.h" + +# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# define FIELD(x) __##x +# else +# define FIELD(x) x +# endif +#endif + #ifdef ARCH_x86_32 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__ecx) -# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__ebp) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.eip) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.ecx) -# define FRAME_REGISTER(context) (context->uc_mcontext->ss.ebp) -# endif +# define THREAD_STATE x86_THREAD_STATE32 +# define THREAD_STATE_TYPE x86_thread_state32_t +# define THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(eip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(esp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(ebx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(ecx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(ebp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) @@ -70,19 +90,27 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, #elif defined ARCH_x86_64 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__rip) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__rcx) -# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__rbp) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.rip) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.rcx) -# define FRAME_REGISTER(context) (context->uc_mcontext->ss.rbp) -# endif +# define THREAD_STATE x86_THREAD_STATE64 +# define THREAD_STATE_TYPE x86_thread_state64_t +# define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(rip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(rsp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(rbx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(rcx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(rbp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP]) From 5524b9a5a39e6babe5cbe2e2fea76e1ad1175b24 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Feb 2011 14:36:48 -0700 Subject: [PATCH 274/274] fix OS X 10.4 build pthread_mach_thread_np is not declared in pthread.h on OS X unless _XOPEN_SOURCE and _POSIX_C_SOURCE are undefined. --- src/posix.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 4187a8e4b6..b885e422fc 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -13,8 +13,6 @@ #ifdef __APPLE__ # include "CoreFoundation/CoreFoundation.h" # undef assert -# define _XOPEN_SOURCE -# define _DARWIN_C_SOURCE #endif #include "sys/mman.h"