Added support for property loads to the CFG builder and fast-mode

compiler.

Review URL: http://codereview.chromium.org/165129

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2653 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2009-08-07 13:32:39 +00:00
parent e73bfe98a4
commit e8f54a6073
5 changed files with 237 additions and 43 deletions

View File

@ -100,23 +100,60 @@ void ExitNode::Compile(MacroAssembler* masm) {
}
void PropLoadInstr::Compile(MacroAssembler* masm) {
// The key should not be on the stack---if it is a compiler-generated
// temporary it is in the accumulator.
ASSERT(!key()->is_on_stack());
Comment cmnt(masm, "[ Load from Property");
// If the key is known at compile-time we may be able to use a load IC.
bool is_keyed_load = true;
if (key()->is_constant()) {
// Still use the keyed load IC if the key can be parsed as an integer so
// we will get into the case that handles [] on string objects.
Handle<Object> key_val = Constant::cast(key())->handle();
uint32_t ignored;
if (key_val->IsSymbol() &&
!String::cast(*key_val)->AsArrayIndex(&ignored)) {
is_keyed_load = false;
}
}
if (!object()->is_on_stack()) object()->Push(masm);
if (is_keyed_load) {
key()->Push(masm);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Discard key and receiver.
__ add(sp, sp, Operand(2 * kPointerSize));
} else {
key()->Get(masm, r2);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
__ pop(); // Discard receiver.
}
location()->Set(masm, r0);
}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
ASSERT(!value1()->is_on_stack());
ASSERT(!right()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
if (value0()->is_temporary()) {
if (left()->is_temporary()) {
mode = OVERWRITE_LEFT;
} else if (value1()->is_temporary()) {
} else if (right()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Move left to r1 and right to r0.
value0()->Get(masm, r1);
value1()->Get(masm, r0);
left()->Get(masm, r1);
right()->Get(masm, r0);
GenericBinaryOpStub stub(op(), mode);
__ CallStub(&stub);
location()->Set(masm, r0);
@ -127,7 +164,7 @@ void ReturnInstr::Compile(MacroAssembler* masm) {
// The location should be 'Effect'. As a side effect, move the value to
// the accumulator.
Comment cmnt(masm, "[ ReturnInstr");
value_->Get(masm, r0);
value()->Get(masm, r0);
}

View File

@ -210,9 +210,19 @@ void MoveInstr::FastAllocate(TempLocation* temp) {
}
void PropLoadInstr::FastAllocate(TempLocation* temp) {
ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
if (temp == object() || temp == key()) {
temp->set_where(TempLocation::ACCUMULATOR);
} else {
temp->set_where(TempLocation::STACK);
}
}
void BinaryOpInstr::FastAllocate(TempLocation* temp) {
ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
if (temp == value0() || temp == value1()) {
if (temp == left() || temp == right()) {
temp->set_where(TempLocation::ACCUMULATOR);
} else {
temp->set_where(TempLocation::STACK);
@ -222,7 +232,7 @@ void BinaryOpInstr::FastAllocate(TempLocation* temp) {
void ReturnInstr::FastAllocate(TempLocation* temp) {
ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
if (temp == value_) {
if (temp == value()) {
temp->set_where(TempLocation::ACCUMULATOR);
} else {
temp->set_where(TempLocation::STACK);
@ -369,7 +379,36 @@ void ExpressionCfgBuilder::VisitThrow(Throw* expr) {
void ExpressionCfgBuilder::VisitProperty(Property* expr) {
BAILOUT("Property");
ExpressionCfgBuilder object, key;
object.Build(expr->obj(), NULL);
if (object.graph() == NULL) {
BAILOUT("unsupported object subexpression in propref");
}
key.Build(expr->key(), NULL);
if (key.graph() == NULL) {
BAILOUT("unsupported key subexpression in propref");
}
if (destination_ == NULL) destination_ = new TempLocation();
graph_ = object.graph();
// Insert a move to a fresh temporary if the object value is in a slot
// that's assigned in the key.
Location* temp = NULL;
if (object.value()->is_slot() &&
key.assigned_vars()->Contains(SlotLocation::cast(object.value()))) {
temp = new TempLocation();
graph()->Append(new MoveInstr(temp, object.value()));
}
graph()->Concatenate(key.graph());
graph()->Append(new PropLoadInstr(destination_,
temp == NULL ? object.value() : temp,
key.value()));
assigned_vars_ = *object.assigned_vars();
assigned_vars()->Union(key.assigned_vars());
value_ = destination_;
}
@ -640,13 +679,24 @@ void MoveInstr::Print() {
}
void PropLoadInstr::Print() {
PrintF("PropLoad(");
location()->Print();
PrintF(", ");
object()->Print();
PrintF(", ");
key()->Print();
PrintF(")\n");
}
void BinaryOpInstr::Print() {
PrintF("BinaryOp(");
location()->Print();
PrintF(", %s, ", Token::Name(op()));
value0()->Print();
left()->Print();
PrintF(", ");
value1()->Print();
right()->Print();
PrintF(")\n");
}

View File

@ -43,10 +43,11 @@ class Location;
// Instructions are described by the following grammar.
//
// <Instruction> ::=
// MoveInstr <Location> <Value>
// | BinaryOpInstr <Location> Token::Value <Value> <Value>
// | ReturnInstr Nowhere <Value>
// | PositionInstr <Int>
// Move <Location> <Value>
// | PropLoad <Location> <Value> <Value>
// | BinaryOp <Location> Token::Value <Value> <Value>
// | Return Nowhere <Value>
// | Position <Int>
//
// Values are trivial expressions:
//
@ -131,16 +132,14 @@ class Value : public ZoneObject {
// Predicates:
virtual bool is_temporary() { return false; }
virtual bool is_slot() { return false; }
virtual bool is_constant() { return false; }
// True if the value is a temporary allocated to the stack in
// fast-compilation mode.
virtual bool is_on_stack() { return false; }
// True if the value is a compiler-generated temporary location.
virtual bool is_temporary() { return false; }
// True if the value is a slot location.
virtual bool is_slot() { return false; }
// Support for fast-compilation mode:
// Move the value into a register.
@ -163,7 +162,17 @@ class Constant : public Value {
public:
explicit Constant(Handle<Object> handle) : handle_(handle) {}
virtual ~Constant() {}
// Cast accessor.
static Constant* cast(Value* value) {
ASSERT(value->is_constant());
return reinterpret_cast<Constant*>(value);
}
// Accessors.
Handle<Object> handle() { return handle_; }
// Predicates.
bool is_constant() { return true; }
// Support for fast-compilation mode.
void Get(MacroAssembler* masm, Register reg);
@ -410,18 +419,43 @@ class MoveInstr : public Instruction {
};
// Load a property from a receiver, leaving the result in a location.
class PropLoadInstr : public Instruction {
public:
PropLoadInstr(Location* loc, Value* object, Value* key)
: Instruction(loc), object_(object), key_(key) {
}
// Accessors.
Value* object() { return object_; }
Value* key() { return key_; }
// Support for fast-compilation mode.
void Compile(MacroAssembler* masm);
void FastAllocate(TempLocation* temp);
#ifdef DEBUG
void Print();
#endif
private:
Value* object_;
Value* key_;
};
// Perform a (non-short-circuited) binary operation on a pair of values,
// leaving the result in a location.
class BinaryOpInstr : public Instruction {
public:
BinaryOpInstr(Location* loc, Token::Value op, Value* value0, Value* value1)
: Instruction(loc), op_(op), value0_(value0), value1_(value1) {
BinaryOpInstr(Location* loc, Token::Value op, Value* left, Value* right)
: Instruction(loc), op_(op), left_(left), right_(right) {
}
// Accessors.
Token::Value op() { return op_; }
Value* value0() { return value0_; }
Value* value1() { return value1_; }
Value* left() { return left_; }
Value* right() { return right_; }
// Support for fast-compilation mode.
void Compile(MacroAssembler* masm);
@ -433,8 +467,8 @@ class BinaryOpInstr : public Instruction {
private:
Token::Value op_;
Value* value0_;
Value* value1_;
Value* left_;
Value* right_;
};
@ -449,6 +483,9 @@ class ReturnInstr : public Instruction {
virtual ~ReturnInstr() {}
// Accessors.
Value* value() { return value_; }
// Support for fast-compilation mode.
void Compile(MacroAssembler* masm);
void FastAllocate(TempLocation* temp);

View File

@ -113,25 +113,60 @@ void ExitNode::Compile(MacroAssembler* masm) {
}
void PropLoadInstr::Compile(MacroAssembler* masm) {
// The key should not be on the stack---if it is a compiler-generated
// temporary it is in the accumulator.
ASSERT(!key()->is_on_stack());
Comment cmnt(masm, "[ Load from Property");
// If the key is known at compile-time we may be able to use a load IC.
bool is_keyed_load = true;
if (key()->is_constant()) {
// Still use the keyed load IC if the key can be parsed as an integer so
// we will get into the case that handles [] on string objects.
Handle<Object> key_val = Constant::cast(key())->handle();
uint32_t ignored;
if (key_val->IsSymbol() &&
!String::cast(*key_val)->AsArrayIndex(&ignored)) {
is_keyed_load = false;
}
}
if (!object()->is_on_stack()) object()->Push(masm);
// A test eax instruction after the call indicates to the IC code that it
// was inlined. Ensure there is not one here.
if (is_keyed_load) {
key()->Push(masm);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
__ pop(ebx); // Discard key.
} else {
key()->Get(masm, ecx);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
}
__ pop(ebx); // Discard receiver.
location()->Set(masm, eax);
}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
ASSERT(!value1()->is_on_stack());
ASSERT(!right()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
if (value0()->is_temporary()) {
if (left()->is_temporary()) {
mode = OVERWRITE_LEFT;
} else if (value1()->is_temporary()) {
} else if (right()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Push both operands and call the specialized stub.
if (!value0()->is_on_stack()) {
value0()->Push(masm);
}
value1()->Push(masm);
if (!left()->is_on_stack()) left()->Push(masm);
right()->Push(masm);
GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
__ CallStub(&stub);
location()->Set(masm, eax);

View File

@ -122,25 +122,60 @@ void ExitNode::Compile(MacroAssembler* masm) {
}
void PropLoadInstr::Compile(MacroAssembler* masm) {
// The key should not be on the stack---if it is a compiler-generated
// temporary it is in the accumulator.
ASSERT(!key()->is_on_stack());
Comment cmnt(masm, "[ Load from Property");
// If the key is known at compile-time we may be able to use a load IC.
bool is_keyed_load = true;
if (key()->is_constant()) {
// Still use the keyed load IC if the key can be parsed as an integer so
// we will get into the case that handles [] on string objects.
Handle<Object> key_val = Constant::cast(key())->handle();
uint32_t ignored;
if (key_val->IsSymbol() &&
!String::cast(*key_val)->AsArrayIndex(&ignored)) {
is_keyed_load = false;
}
}
if (!object()->is_on_stack()) object()->Push(masm);
// A test rax instruction after the call indicates to the IC code that it
// was inlined. Ensure there is not one after the call below.
if (is_keyed_load) {
key()->Push(masm);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
__ pop(rbx); // Discard key.
} else {
key()->Get(masm, rcx);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
}
__ pop(rbx); // Discard receiver.
location()->Set(masm, rax);
}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
ASSERT(!value1()->is_on_stack());
ASSERT(!right()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
if (value0()->is_temporary()) {
if (left()->is_temporary()) {
mode = OVERWRITE_LEFT;
} else if (value1()->is_temporary()) {
} else if (right()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Push both operands and call the specialized stub.
if (!value0()->is_on_stack()) {
value0()->Push(masm);
}
value1()->Push(masm);
if (!left()->is_on_stack()) left()->Push(masm);
right()->Push(masm);
GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
__ CallStub(&stub);
location()->Set(masm, rax);
@ -151,7 +186,7 @@ void ReturnInstr::Compile(MacroAssembler* masm) {
// The location should be 'Effect'. As a side effect, move the value to
// the accumulator.
Comment cmnt(masm, "[ ReturnInstr");
value_->Get(masm, rax);
value()->Get(masm, rax);
}