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:
parent
e73bfe98a4
commit
e8f54a6073
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
60
src/cfg.cc
60
src/cfg.cc
@ -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");
|
||||
}
|
||||
|
||||
|
71
src/cfg.h
71
src/cfg.h
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user