Revision: 2653 Author: [email protected] Date: Fri Aug 7 06:32:39 2009 Log: Added support for property loads to the CFG builder and fast-mode compiler.
Review URL: http://codereview.chromium.org/165129 http://code.google.com/p/v8/source/detail?r=2653 Modified: /branches/bleeding_edge/src/arm/cfg-arm.cc /branches/bleeding_edge/src/cfg.cc /branches/bleeding_edge/src/cfg.h /branches/bleeding_edge/src/ia32/cfg-ia32.cc /branches/bleeding_edge/src/x64/cfg-x64.cc ======================================= --- /branches/bleeding_edge/src/arm/cfg-arm.cc Fri Aug 7 03:55:19 2009 +++ /branches/bleeding_edge/src/arm/cfg-arm.cc Fri Aug 7 06:32:39 2009 @@ -98,25 +98,62 @@ __ add(sp, sp, Operand((count + 1) * kPointerSize)); __ Jump(lr); } + + +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 @@ // 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); } ======================================= --- /branches/bleeding_edge/src/cfg.cc Fri Aug 7 03:55:19 2009 +++ /branches/bleeding_edge/src/cfg.cc Fri Aug 7 06:32:39 2009 @@ -208,11 +208,21 @@ temp->set_where(TempLocation::STACK); } } + + +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 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::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_; } @@ -638,15 +677,26 @@ value_->Print(); PrintF(")\n"); } + + +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"); } ======================================= --- /branches/bleeding_edge/src/cfg.h Fri Aug 7 03:35:48 2009 +++ /branches/bleeding_edge/src/cfg.h Fri Aug 7 06:32:39 2009 @@ -43,10 +43,11 @@ // 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: // @@ -130,16 +131,14 @@ virtual ~Value() {} // 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: @@ -163,7 +162,17 @@ 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 @@ }; +// 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 @@ private: Token::Value op_; - Value* value0_; - Value* value1_; + Value* left_; + Value* right_; }; @@ -448,6 +482,9 @@ explicit ReturnInstr(Value* value) : value_(value) {} virtual ~ReturnInstr() {} + + // Accessors. + Value* value() { return value_; } // Support for fast-compilation mode. void Compile(MacroAssembler* masm); ======================================= --- /branches/bleeding_edge/src/ia32/cfg-ia32.cc Fri Aug 7 03:55:19 2009 +++ /branches/bleeding_edge/src/ia32/cfg-ia32.cc Fri Aug 7 06:32:39 2009 @@ -111,27 +111,62 @@ int count = CfgGlobals::current()->fun()->scope()->num_parameters(); __ ret((count + 1) * kPointerSize); } + + +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); ======================================= --- /branches/bleeding_edge/src/x64/cfg-x64.cc Fri Aug 7 03:55:19 2009 +++ /branches/bleeding_edge/src/x64/cfg-x64.cc Fri Aug 7 06:32:39 2009 @@ -120,27 +120,62 @@ __ int3(); } } + + +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 @@ // 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); } --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
