handle constant array lengths and indexes properly; various bugfixes

This commit is contained in:
Joel Dice 2008-03-13 14:50:56 -06:00
parent 7cd79736c2
commit 406f173982
4 changed files with 349 additions and 124 deletions

View File

@ -948,6 +948,8 @@ class Frame {
(context->zone.allocate(sizeof(TraceElement) + (mapSize * BytesPerWord)))
TraceElement(context, target, virtualCall, context->traceLog);
fprintf(stderr, "make element %p at ip %d\n", e, ip);
context->eventLog.append(TraceEvent);
context->eventLog.appendAddress(e);
@ -1573,6 +1575,10 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
frame->startLogicalIp(ip);
if (ip == 0) {
handleEntrance(t, frame);
}
// fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map));
unsigned instruction = codeBody(t, code, ip++);
@ -1591,17 +1597,24 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
if (CheckArrayBounds) {
Compiler::Operand* load = c->label();
Compiler::Operand* throw_ = c->label();
Compiler::Operand* throw_ = 0;
c->cmp(4, c->constant(0), index);
c->jl(throw_);
if (c->isConstant(index)) {
expect(t, c->constantValue(index) >= 0);
} else {
throw_ = c->label();
c->cmp(4, c->constant(0), index);
c->jl(throw_);
}
c->cmp(BytesPerWord,
c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
index);
c->jl(load);
index,
c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)));
c->jge(load);
c->mark(throw_);
if (not c->isConstant(index)) {
c->mark(throw_);
}
c->call
(c->constant(reinterpret_cast<intptr_t>(throwArrayIndexOutOfBounds)),
@ -1614,34 +1627,67 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
c->mark(load);
}
switch (instruction) {
case aaload:
frame->pushObject
(c->load
(BytesPerWord, c->memory(array, ArrayBody, index, BytesPerWord)));
break;
if (c->isConstant(index)) {
unsigned i = c->constantValue(index);
switch (instruction) {
case aaload:
frame->pushObject
(c->load
(BytesPerWord, c->memory(array, ArrayBody + (i * BytesPerWord))));
break;
case faload:
case iaload:
frame->pushInt(c->load(4, c->memory(array, ArrayBody, index, 4)));
break;
case faload:
case iaload:
frame->pushInt(c->load(4, c->memory(array, ArrayBody + (i * 4))));
break;
case baload:
frame->pushInt(c->load(1, c->memory(array, ArrayBody, index, 1)));
break;
case baload:
frame->pushInt(c->load(1, c->memory(array, ArrayBody + i)));
break;
case caload:
frame->pushInt(c->loadz(2, c->memory(array, ArrayBody, index, 2)));
break;
case caload:
frame->pushInt(c->loadz(2, c->memory(array, ArrayBody + (i * 2))));
break;
case daload:
case laload:
frame->pushLong(c->load(8, c->memory(array, ArrayBody, index, 8)));
break;
case daload:
case laload:
frame->pushInt(c->load(8, c->memory(array, ArrayBody + (i * 8))));
break;
case saload:
frame->pushInt(c->load(2, c->memory(array, ArrayBody, index, 2)));
break;
case saload:
frame->pushInt(c->load(2, c->memory(array, ArrayBody + (i * 2))));
break;
}
} else {
switch (instruction) {
case aaload:
frame->pushObject
(c->load
(BytesPerWord, c->memory(array, ArrayBody, index, BytesPerWord)));
break;
case faload:
case iaload:
frame->pushInt(c->load(4, c->memory(array, ArrayBody, index, 4)));
break;
case baload:
frame->pushInt(c->load(1, c->memory(array, ArrayBody, index, 1)));
break;
case caload:
frame->pushInt(c->loadz(2, c->memory(array, ArrayBody, index, 2)));
break;
case daload:
case laload:
frame->pushLong(c->load(8, c->memory(array, ArrayBody, index, 8)));
break;
case saload:
frame->pushInt(c->load(2, c->memory(array, ArrayBody, index, 2)));
break;
}
}
} break;
@ -1667,17 +1713,24 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
if (CheckArrayBounds) {
Compiler::Operand* store = c->label();
Compiler::Operand* throw_ = c->label();
Compiler::Operand* throw_ = 0;
c->cmp(4, c->constant(0), index);
c->jl(throw_);
if (c->isConstant(index)) {
expect(t, c->constantValue(index) >= 0);
} else {
throw_ = c->label();
c->cmp(4, c->constant(0), index);
c->jl(throw_);
}
c->cmp(BytesPerWord,
c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
index);
c->jl(store);
index,
c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)));
c->jge(store);
c->mark(throw_);
if (not c->isConstant(index)) {
c->mark(throw_);
}
c->call
(c->constant(reinterpret_cast<intptr_t>(throwArrayIndexOutOfBounds)),
@ -1690,38 +1743,74 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
c->mark(store);
}
switch (instruction) {
case aastore: {
c->call
(c->constant(reinterpret_cast<intptr_t>(setMaybeNull)),
context->indirection,
0,
frame->trace(0, false),
0,
4, c->thread(), array,
c->add(4, c->constant(ArrayBody),
c->shl(4, c->constant(log(BytesPerWord)), index)),
value);
} break;
if (c->isConstant(index)) {
unsigned i = c->constantValue(index);
switch (instruction) {
case aastore: {
c->call
(c->constant(reinterpret_cast<intptr_t>(setMaybeNull)),
context->indirection,
0,
frame->trace(0, false),
0,
4, c->thread(), array,
c->constant(ArrayBody + (i * BytesPerWord)),
value);
} break;
case fastore:
case iastore:
c->store(4, value, c->memory(array, ArrayBody, index, 4));
break;
case fastore:
case iastore:
c->store(4, value, c->memory(array, ArrayBody + (i * 4)));
break;
case bastore:
c->store(1, value, c->memory(array, ArrayBody, index, 1));
break;
case bastore:
c->store(1, value, c->memory(array, ArrayBody + i));
break;
case castore:
case sastore:
c->store(2, value, c->memory(array, ArrayBody, index, 2));
break;
case castore:
case sastore:
c->store(2, value, c->memory(array, ArrayBody + (i * 2)));
break;
case dastore:
case lastore:
c->store(8, value, c->memory(array, ArrayBody, index, 8));
break;
case dastore:
case lastore:
c->store(8, value, c->memory(array, ArrayBody + (i * 8)));
break;
}
} else {
switch (instruction) {
case aastore: {
c->call
(c->constant(reinterpret_cast<intptr_t>(setMaybeNull)),
context->indirection,
0,
frame->trace(0, false),
0,
4, c->thread(), array,
c->add(4, c->constant(ArrayBody),
c->shl(4, c->constant(log(BytesPerWord)), index)),
value);
} break;
case fastore:
case iastore:
c->store(4, value, c->memory(array, ArrayBody, index, 4));
break;
case bastore:
c->store(1, value, c->memory(array, ArrayBody, index, 1));
break;
case castore:
case sastore:
c->store(2, value, c->memory(array, ArrayBody, index, 2));
break;
case dastore:
case lastore:
c->store(8, value, c->memory(array, ArrayBody, index, 8));
break;
}
}
} break;
@ -1755,21 +1844,26 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
Compiler::Operand* nonnegative = c->label();
Compiler::Operand* length = frame->popInt();
c->cmp(4, c->constant(0), length);
c->jge(nonnegative);
c->call
(c->constant(reinterpret_cast<intptr_t>(throwNegativeArraySize)),
context->indirection,
Compiler::NoReturn,
frame->trace(0, false),
0,
2, c->thread(), length);
if (c->isConstant(length)) {
expect(t, c->constantValue(length) >= 0);
} else{
Compiler::Operand* nonnegative = c->label();
c->mark(nonnegative);
c->cmp(4, c->constant(0), length);
c->jge(nonnegative);
c->call
(c->constant(reinterpret_cast<intptr_t>(throwNegativeArraySize)),
context->indirection,
Compiler::NoReturn,
frame->trace(0, false),
0,
2, c->thread(), length);
c->mark(nonnegative);
}
frame->pushObject
(c->call
@ -2924,22 +3018,26 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
case newarray: {
uint8_t type = codeBody(t, code, ip++);
Compiler::Operand* nonnegative = c->label();
Compiler::Operand* length = frame->popInt();
c->cmp(4, c->constant(0), length);
c->jge(nonnegative);
if (c->isConstant(length)) {
expect(t, c->constantValue(length) >= 0);
} else{
Compiler::Operand* nonnegative = c->label();
c->call
(c->constant(reinterpret_cast<intptr_t>(throwNegativeArraySize)),
context->indirection,
Compiler::NoReturn,
frame->trace(0, false),
0,
2, c->thread(), length);
c->cmp(4, c->constant(0), length);
c->jge(nonnegative);
c->mark(nonnegative);
c->call
(c->constant(reinterpret_cast<intptr_t>(throwNegativeArraySize)),
context->indirection,
Compiler::NoReturn,
frame->trace(0, false),
0,
2, c->thread(), length);
c->mark(nonnegative);
}
object (*constructor)(Thread*, uintptr_t, bool);
switch (type) {
@ -2985,7 +3083,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
0,
frame->trace(0, false),
BytesPerWord,
2, c->thread(), c->constant(reinterpret_cast<intptr_t>(constructor)),
3, c->thread(), c->constant(reinterpret_cast<intptr_t>(constructor)),
length));
} break;
@ -3463,6 +3561,7 @@ finish(MyThread* t, Context* context)
unsigned mapSize = frameMapSizeInWords(t, context->method);
for (TraceElement* p = context->traceLog; p; p = p->next) {
fprintf(stderr, "make node for %p\n", p);
object node = makeTraceNode
(t, p->address->value(), 0, context->method, p->target,
p->virtualCall, mapSize, false);
@ -3562,8 +3661,6 @@ compile(MyThread* t, Context* context)
}
}
handleEntrance(t, &frame);
compile(t, &frame, 0);
if (UNLIKELY(t->exception)) return 0;

View File

@ -43,6 +43,8 @@ class Value {
virtual void asAssemblerOperand(Context*,
OperandType* type,
Assembler::Operand** operand) = 0;
virtual int64_t constantValue(Context*) = 0;
};
class MyOperand: public Compiler::Operand {
@ -291,6 +293,10 @@ class ConstantValue: public Value {
*operand = &value;
}
virtual int64_t constantValue(Context*) {
return value.value->value();
}
Assembler::Constant value;
};
@ -300,11 +306,17 @@ constant(Context* c, Promise* value)
return new (c->zone->allocate(sizeof(ConstantValue))) ConstantValue(value);
}
ResolvedPromise*
resolved(Context* c, int64_t value)
{
return new (c->zone->allocate(sizeof(ResolvedPromise)))
ResolvedPromise(value);
}
ConstantValue*
constant(Context* c, int64_t value)
{
return constant(c, new (c->zone->allocate(sizeof(ResolvedPromise)))
ResolvedPromise(value));
return constant(c, resolved(c, value));
}
class AddressValue: public Value {
@ -323,6 +335,10 @@ class AddressValue: public Value {
*operand = &address;
}
virtual int64_t constantValue(Context* c) {
abort(c);
}
Assembler::Address address;
};
@ -385,6 +401,10 @@ class RegisterValue: public Value {
*operand = &register_;
}
virtual int64_t constantValue(Context* c) {
abort(c);
}
Assembler::Register register_;
};
@ -437,6 +457,10 @@ class MemoryValue: public Value {
*operand = &value;
}
virtual int64_t constantValue(Context* c) {
abort(c);
}
Assembler::Memory value;
};
@ -467,7 +491,7 @@ class AbstractMemoryValue: public MemoryValue {
}
virtual int index(Context* c) {
return index_ ? ::toRegister(c, base_) : NoRegister;
return index_ ? ::toRegister(c, index_) : NoRegister;
}
MyOperand* base_;
@ -502,6 +526,10 @@ class StackValue: public Value {
abort(c);
}
virtual int64_t constantValue(Context* c) {
abort(c);
}
Stack* stack;
};
@ -514,6 +542,8 @@ stackValue(Context* c, Stack* stack)
class Event {
public:
Event(Context* c): next(0), stack(c->state->stack), promises(0) {
assert(c, c->logicalIp >= 0);
if (c->event) {
c->event->next = this;
}
@ -538,13 +568,37 @@ class Event {
CodePromise* promises;
};
class NullEvent: public Event {
public:
NullEvent(Context* c):
Event(c)
{ }
virtual Value* target(Context*, MyOperand*) {
return 0;
}
virtual void compile(Context*) {
// ignore
}
};
void
setEvent(Context* c, MyOperand* a, Event* e)
{
if (a->event) {
a->event = new (c->zone->allocate(sizeof(NullEvent))) NullEvent(c);
} else{
a->event = e;
}
}
class ArgumentEvent: public Event {
public:
ArgumentEvent(Context* c, unsigned size, MyOperand* a, unsigned index):
Event(c), size(size), a(a), index(index)
{
assert(c, a->event == 0);
a->event = this;
setEvent(c, a, this);
}
virtual Value* target(Context* c, MyOperand* v UNUSED) {
@ -590,8 +644,7 @@ class ReturnEvent: public Event {
Event(c), size(size), a(a)
{
if (a) {
assert(c, a->event == 0);
a->event = this;
setEvent(c, a, this);
}
}
@ -643,8 +696,7 @@ class CallEvent: public Event {
traceHandler(traceHandler),
result(result)
{
assert(c, address->event == 0);
address->event = this;
setEvent(c, address, this);
}
virtual Value* target(Context* c, MyOperand* v UNUSED) {
@ -855,8 +907,7 @@ class MoveEvent: public Event {
MyOperand* dst):
Event(c), type(type), size(size), src(src), dst(dst)
{
assert(c, src->event == 0);
src->event = this;
setEvent(c, src, this);
}
virtual Value* target(Context* c, MyOperand* v UNUSED) {
@ -983,10 +1034,8 @@ class CompareEvent: public Event {
CompareEvent(Context* c, unsigned size, MyOperand* a, MyOperand* b):
Event(c), size(size), a(a), b(b)
{
assert(c, a->event == 0);
a->event = this;
assert(c, b->event == 0);
b->event = this;
setEvent(c, a, this);
setEvent(c, b, this);
}
virtual Value* target(Context* c UNUSED, MyOperand* v UNUSED) {
@ -1020,8 +1069,7 @@ class BranchEvent: public Event {
BranchEvent(Context* c, UnaryOperation type, MyOperand* address):
Event(c), type(type), address(address)
{
assert(c, address->event == 0);
address->event = this;
setEvent(c, address, this);
}
virtual Value* target(Context* c UNUSED, MyOperand* v UNUSED) {
@ -1054,8 +1102,7 @@ class JumpEvent: public Event {
Event(c),
address(address)
{
assert(c, address->event == 0);
address->event = this;
setEvent(c, address, this);
}
virtual Value* target(Context* c UNUSED, MyOperand* v UNUSED) {
@ -1087,10 +1134,8 @@ class CombineEvent: public Event {
MyOperand* b, MyOperand* result):
Event(c), type(type), size(size), a(a), b(b), result(result)
{
assert(c, a->event == 0);
a->event = this;
assert(c, b->event == 0);
b->event = this;
setEvent(c, a, this);
setEvent(c, b, this);
}
virtual Value* target(Context* c, MyOperand* v) {
@ -1174,8 +1219,7 @@ class TranslateEvent: public Event {
MyOperand* result):
Event(c), type(type), size(size), a(a), result(result)
{
assert(c, a->event == 0);
a->event = this;
setEvent(c, a, this);
}
virtual Value* target(Context* c, MyOperand* v UNUSED) {
@ -1356,12 +1400,21 @@ compile(Context* c)
a->apply(Push, BytesPerWord, Register, &base);
a->apply(Move, BytesPerWord, Register, &stack, Register, &base);
if (c->stackOffset) {
Assembler::Constant offset(resolved(c, c->stackOffset * BytesPerWord));
a->apply(Subtract, BytesPerWord, Constant, &offset, Register, &stack);
}
for (unsigned i = 0; i < c->logicalCodeLength; ++ i) {
fprintf(stderr, "compile ip %d\n", i);
for (Event* e = c->logicalCode[i].firstEvent; e; e = e->next) {
e->compile(c);
if (e == c->logicalCode[i].lastEvent) break;
for (CodePromise* p = e->promises; p; p = p->next) {
p->offset = a->length();
}
}
}
}
@ -1408,8 +1461,7 @@ class MyCompiler: public Compiler {
}
virtual Promise* poolAppend(intptr_t value) {
return poolAppendPromise(new (c.zone->allocate(sizeof(ResolvedPromise)))
ResolvedPromise(value));
return poolAppendPromise(resolved(&c, value));
}
virtual Promise* poolAppendPromise(Promise* value) {
@ -1432,8 +1484,7 @@ class MyCompiler: public Compiler {
}
virtual Operand* constant(int64_t value) {
return promiseConstant(new (c.zone->allocate(sizeof(ResolvedPromise)))
ResolvedPromise(value));
return promiseConstant(resolved(&c, value));
}
virtual Operand* promiseConstant(Promise* value) {
@ -1468,6 +1519,16 @@ class MyCompiler: public Compiler {
return operand(&c, register_(&c, c.assembler->thread()));
}
virtual bool isConstant(Operand* a) {
return static_cast<MyOperand*>(a)->value
and static_cast<MyOperand*>(a)->value->type(&c) == Constant;
}
virtual int64_t constantValue(Operand* a) {
assert(&c, isConstant(a));
return static_cast<MyOperand*>(a)->value->constantValue(&c);
}
virtual Operand* label() {
return operand(&c, ::constant(&c, static_cast<Promise*>(0)));
}

View File

@ -51,6 +51,9 @@ class Compiler {
virtual Operand* base() = 0;
virtual Operand* thread() = 0;
virtual bool isConstant(Operand* value) = 0;
virtual int64_t constantValue(Operand* value) = 0;
virtual Operand* label() = 0;
virtual void mark(Operand* label) = 0;

View File

@ -224,6 +224,7 @@ void
encode(Context* c, uint8_t instruction, int a, Assembler::Memory* b, bool rex)
{
if (b->traceHandler) {
fprintf(stderr, "handle trace %p\n", b->traceHandler);
b->traceHandler->handleTrace(codePromise(c, c->code.length()));
}
@ -239,6 +240,7 @@ encode2(Context* c, uint16_t instruction, int a, Assembler::Memory* b,
bool rex)
{
if (b->traceHandler) {
fprintf(stderr, "handle trace %p\n", b->traceHandler);
b->traceHandler->handleTrace(codePromise(c, c->code.length()));
}
@ -331,6 +333,14 @@ jumpR(Context* c, unsigned size UNUSED, Assembler::Register* a)
c->code.append(0xe0 | a->low);
}
void
jumpIfGreaterOrEqualC(Context* c, unsigned size UNUSED, Assembler::Constant* a)
{
assert(c, size == BytesPerWord);
conditional(c, 0x8d, a);
}
void
pushR(Context* c, unsigned size, Assembler::Register* a)
{
@ -552,6 +562,29 @@ addCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
}
}
void
subtractCR(Context* c, unsigned size UNUSED, Assembler::Constant* a,
Assembler::Register* b)
{
assert(c, BytesPerWord == 8 or size == 4); // todo
int64_t v = a->value->value();
if (v) {
rex(c);
if (isInt8(v)) {
c->code.append(0x83);
c->code.append(0xe8 | b->low);
c->code.append(v);
} else if (isInt32(v)) {
c->code.append(0x81);
c->code.append(0xe8 | b->low);
c->code.append4(v);
} else {
abort(c);
}
}
}
void
addRR(Context* c, unsigned size UNUSED, Assembler::Register* a,
Assembler::Register* b)
@ -598,7 +631,23 @@ andCM(Context* c, unsigned size UNUSED, Assembler::Constant* a,
{
assert(c, BytesPerWord == 8 or size == 4);
encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 4, b, true);
encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 5, b, true);
if (isInt8(a->value->value())) {
c->code.append(a->value->value());
} else if (isInt32(a->value->value())) {
c->code.append4(a->value->value());
} else {
abort(c);
}
}
void
compareCM(Context* c, unsigned size UNUSED, Assembler::Constant* a,
Assembler::Memory* b)
{
assert(c, BytesPerWord == 8 or size == 4);
encode(c, isInt8(a->value->value()) ? 0x83 : 0x81, 7, b, true);
if (isInt8(a->value->value())) {
c->code.append(a->value->value());
} else if (isInt32(a->value->value())) {
@ -614,29 +663,44 @@ populateTables()
Operations[Return] = return_;
UnaryOperations[INDEX1(Call, Constant)] = CAST1(callC);
UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC);
UnaryOperations[INDEX1(Call, Register)] = CAST1(callR);
UnaryOperations[INDEX1(Call, Memory)] = CAST1(callM);
UnaryOperations[INDEX1(AlignedCall, Constant)] = CAST1(alignedCallC);
UnaryOperations[INDEX1(Jump, Register)] = CAST1(jumpR);
UnaryOperations[INDEX1(JumpIfGreaterOrEqual, Constant)]
= CAST1(jumpIfGreaterOrEqualC);
UnaryOperations[INDEX1(Push, Register)] = CAST1(pushR);
UnaryOperations[INDEX1(Push, Memory)] = CAST1(pushM);
UnaryOperations[INDEX1(Pop, Register)] = CAST1(popR);
UnaryOperations[INDEX1(Pop, Memory)] = CAST1(popM);
BinaryOperations[INDEX2(LoadAddress, Memory, Register)] = CAST2(leaMR);
BinaryOperations[INDEX2(Move, Constant, Register)] = CAST2(moveCR);
BinaryOperations[INDEX2(Move, Constant, Memory)] = CAST2(moveCM);
BinaryOperations[INDEX2(Move, Register, Memory)] = CAST2(moveRM);
BinaryOperations[INDEX2(Move, Register, Register)] = CAST2(moveRR);
BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR);
BinaryOperations[INDEX2(Move, Memory, Register)] = CAST2(moveMR);
BinaryOperations[INDEX2(Move, Address, Register)] = CAST2(moveAR);
BinaryOperations[INDEX2(Move4To8, Register, Register)] = CAST2(move4To8RR);
BinaryOperations[INDEX2(Move4To8, Memory, Register)] = CAST2(move4To8MR);
BinaryOperations[INDEX2(Add, Constant, Register)] = CAST2(addCR);
BinaryOperations[INDEX2(Add, Register, Register)] = CAST2(addRR);
BinaryOperations[INDEX2(Add, Register, Memory)] = CAST2(addRM);
BinaryOperations[INDEX2(And, Constant, Register)] = CAST2(andCR);
BinaryOperations[INDEX2(And, Constant, Memory)] = CAST2(andCM);
BinaryOperations[INDEX2(Subtract, Constant, Register)] = CAST2(subtractCR);
BinaryOperations[INDEX2(Compare, Constant, Memory)] = CAST2(compareCM);
}
class MyAssembler: public Assembler {