diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc index a5b494c8d2..89a3c368b3 100644 --- a/src/codegen-arm.cc +++ b/src/codegen-arm.cc @@ -51,6 +51,7 @@ class ArmCodeGenerator; // on the execution stack to represent the reference. enum InitState { CONST_INIT, NOT_CONST_INIT }; +enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; class Reference BASE_EMBEDDED { public: @@ -72,6 +73,18 @@ class Reference BASE_EMBEDDED { bool is_slot() const { return type_ == SLOT; } bool is_property() const { return type_ == NAMED || type_ == KEYED; } + // Return the name. Only valid for named property references. + Handle GetName(); + + // Generate code to push the value of the reference on top of the + // expression stack. The reference is expected to be already on top of + // the expression stack, and it is left in place with its value above it. + void GetValue(TypeofState typeof_state); + + // Generate code to store the value on top of the expression stack in the + // reference. The reference is expected to be immediately below the value + // on the expression stack. The stored value is left in place (with the + // reference intact below it) to support chained assignments. void SetValue(InitState init_state); private: @@ -91,42 +104,29 @@ class Reference BASE_EMBEDDED { class CodeGenState BASE_EMBEDDED { public: - enum AccessType { - UNDEFINED, - LOAD, - LOAD_TYPEOF_EXPR - }; - // Create an initial code generator state. Destroying the initial state // leaves the code generator with a NULL state. explicit CodeGenState(ArmCodeGenerator* owner); // Create a code generator state based on a code generator's current - // state. The new state has its own access type and pair of branch - // labels, and no reference. + // state. The new state has its own typeof state and pair of branch + // labels. CodeGenState(ArmCodeGenerator* owner, - AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target); - // Create a code generator state based on a code generator's current - // state. The new state has an access type of LOAD, its own reference, - // and inherits the pair of branch labels of the current state. - CodeGenState(ArmCodeGenerator* owner, Reference* ref); - // Destroy a code generator state and restore the owning code generator's // previous state. ~CodeGenState(); - AccessType access() const { return access_; } - Reference* ref() const { return ref_; } + TypeofState typeof_state() const { return typeof_state_; } Label* true_target() const { return true_target_; } Label* false_target() const { return false_target_; } private: ArmCodeGenerator* owner_; - AccessType access_; - Reference* ref_; + TypeofState typeof_state_; Label* true_target_; Label* false_target_; CodeGenState* previous_; @@ -178,9 +178,7 @@ class ArmCodeGenerator: public CodeGenerator { // State bool has_cc() const { return cc_reg_ != al; } - CodeGenState::AccessType access() const { return state_->access(); } - Reference* ref() const { return state_->ref(); } - bool is_referenced() const { return state_->ref() != NULL; } + TypeofState typeof_state() const { return state_->typeof_state(); } Label* true_target() const { return state_->true_target(); } Label* false_target() const { return state_->false_target(); } @@ -209,12 +207,17 @@ class ArmCodeGenerator: public CodeGenerator { MemOperand SlotOperand(Slot* slot, Register tmp); - void LoadCondition(Expression* x, CodeGenState::AccessType access, - Label* true_target, Label* false_target, bool force_cc); - void Load(Expression* x, - CodeGenState::AccessType access = CodeGenState::LOAD); + void LoadCondition(Expression* x, + TypeofState typeof_state, + Label* true_target, + Label* false_target, + bool force_cc); + void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); void LoadGlobal(); + // Read a value from a slot and leave it on top of the expression stack. + void LoadFromSlot(Slot* slot, TypeofState typeof_state); + // Special code for typeof expressions: Unfortunately, we must // be careful when loading the expression in 'typeof' // expressions. We are not allowed to throw reference errors for @@ -223,24 +226,6 @@ class ArmCodeGenerator: public CodeGenerator { // through the context chain. void LoadTypeofExpression(Expression* x); - - // References - - // Generate code to fetch the value of a reference. The reference is - // expected to be on top of the expression stack. It is left in place and - // its value is pushed on top of it. - void GetValue(Reference* ref) { - ASSERT(!has_cc()); - ASSERT(!ref->is_illegal()); - CodeGenState new_state(this, ref); - Visit(ref->expression()); - } - - // Generate code to fetch a value from a property of a reference. The - // reference is expected on top of the expression stack. It is left in - // place and its value is pushed on top of it. - void GetReferenceProperty(Expression* key); - void ToBoolean(Label* true_target, Label* false_target); void GenericBinaryOperation(Token::Value op); @@ -309,8 +294,7 @@ class ArmCodeGenerator: public CodeGenerator { CodeGenState::CodeGenState(ArmCodeGenerator* owner) : owner_(owner), - access_(UNDEFINED), - ref_(NULL), + typeof_state_(NOT_INSIDE_TYPEOF), true_target_(NULL), false_target_(NULL), previous_(NULL) { @@ -319,12 +303,11 @@ CodeGenState::CodeGenState(ArmCodeGenerator* owner) CodeGenState::CodeGenState(ArmCodeGenerator* owner, - AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target) : owner_(owner), - access_(access), - ref_(NULL), + typeof_state_(typeof_state), true_target_(true_target), false_target_(false_target), previous_(owner->state()) { @@ -332,17 +315,6 @@ CodeGenState::CodeGenState(ArmCodeGenerator* owner, } -CodeGenState::CodeGenState(ArmCodeGenerator* owner, Reference* ref) - : owner_(owner), - access_(LOAD), - ref_(ref), - true_target_(owner->state()->true_target_), - false_target_(owner->state()->false_target_), - previous_(owner->state()) { - owner_->set_state(this); -} - - CodeGenState::~CodeGenState() { ASSERT(owner_->state() == this); owner_->set_state(previous_); @@ -708,15 +680,13 @@ MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) { // code register and no value is pushed. If the condition code register was set, // has_cc() is true and cc_reg_ contains the condition to test for 'true'. void ArmCodeGenerator::LoadCondition(Expression* x, - CodeGenState::AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target, bool force_cc) { - ASSERT(access == CodeGenState::LOAD || - access == CodeGenState::LOAD_TYPEOF_EXPR); - ASSERT(!has_cc() && !is_referenced()); + ASSERT(!has_cc()); - { CodeGenState new_state(this, access, true_target, false_target); + { CodeGenState new_state(this, typeof_state, true_target, false_target); Visit(x); } if (force_cc && !has_cc()) { @@ -727,13 +697,10 @@ void ArmCodeGenerator::LoadCondition(Expression* x, } -void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { - ASSERT(access == CodeGenState::LOAD || - access == CodeGenState::LOAD_TYPEOF_EXPR); - +void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) { Label true_target; Label false_target; - LoadCondition(x, access, &true_target, &false_target, false); + LoadCondition(x, typeof_state, &true_target, &false_target, false); if (has_cc()) { // convert cc_reg_ into a bool @@ -786,8 +753,8 @@ void ArmCodeGenerator::LoadGlobal() { // TODO(1241834): Get rid of this function in favor of just using Load, now -// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle -// global variables w/o reference errors elsewhere. +// that we have the INSIDE_TYPEOF typeof state. => Need to handle global +// variables w/o reference errors elsewhere. void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { Variable* variable = x->AsVariableProxy()->AsVariable(); if (variable != NULL && !variable->is_this() && variable->is_global()) { @@ -801,7 +768,7 @@ void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { Property property(&global, &key, RelocInfo::kNoPosition); Load(&property); } else { - Load(x, CodeGenState::LOAD_TYPEOF_EXPR); + Load(x, INSIDE_TYPEOF); } } @@ -818,6 +785,7 @@ Reference::~Reference() { void ArmCodeGenerator::LoadReference(Reference* ref) { + Comment cmnt(masm_, "[ LoadReference"); Expression* e = ref->expression(); Property* property = e->AsProperty(); Variable* var = e->AsVariableProxy()->AsVariable(); @@ -859,6 +827,7 @@ void ArmCodeGenerator::LoadReference(Reference* ref) { void ArmCodeGenerator::UnloadReference(Reference* ref) { + Comment cmnt(masm_, "[ UnloadReference"); int size = ref->size(); if (size <= 0) { // Do nothing. No popping is necessary. @@ -994,43 +963,6 @@ class InvokeBuiltinStub : public CodeStub { }; -void ArmCodeGenerator::GetReferenceProperty(Expression* key) { - ASSERT(!ref()->is_illegal()); - - // TODO(1241834): Make sure that this it is safe to ignore the distinction - // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance - // that reference errors can be thrown below, we must distinguish between - // the two kinds of loads (typeof expression loads must not throw a - // reference error). - if (ref()->type() == Reference::NAMED) { - // Compute the name of the property. - Literal* literal = key->AsLiteral(); - Handle name(String::cast(*literal->handle())); - - // Call the appropriate IC code. - // Setup the name register. - __ mov(r2, Operand(name)); - Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); - if (var != NULL) { - ASSERT(var->is_global()); - __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); - } else { - __ Call(ic, RelocInfo::CODE_TARGET); - } - - } else { - // Access keyed property. - ASSERT(ref()->type() == Reference::KEYED); - - // TODO(1224671): Implement inline caching for keyed loads as on ia32. - GetPropertyStub stub; - __ CallStub(&stub); - } - __ push(r0); -} - - void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { // sp[0] : y // sp[1] : x @@ -1527,7 +1459,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) { Label then; Label else_; // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); Branch(false, &else_); // then __ bind(&then); @@ -1542,7 +1474,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) { ASSERT(!has_else_stm); Label then; // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); Branch(false, &exit); // then __ bind(&then); @@ -1553,7 +1485,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) { ASSERT(!has_then_stm); Label else_; // if (!cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); Branch(true, &exit); // else __ bind(&else_); @@ -1563,7 +1495,7 @@ void ArmCodeGenerator::VisitIfStatement(IfStatement* node) { Comment cmnt(masm_, "[ If"); ASSERT(!has_then_stm && !has_else_stm); // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); if (has_cc()) { cc_reg_ = al; } else { @@ -1806,7 +1738,7 @@ void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) { case DONT_KNOW: CheckStack(); // TODO(1222600): ignore if body contains calls. LoadCondition(node->cond(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, &loop, node->break_target(), true); @@ -1972,7 +1904,6 @@ void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) { { Reference each(this, node->each()); if (!each.is_illegal()) { if (each.size() > 0) { - // Reference's size is positive. __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); __ push(r0); } @@ -2273,46 +2204,42 @@ void ArmCodeGenerator::VisitFunctionBoilerplateLiteral( void ArmCodeGenerator::VisitConditional(Conditional* node) { Comment cmnt(masm_, "[ Conditional"); Label then, else_, exit; - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); Branch(false, &else_); __ bind(&then); - Load(node->then_expression(), access()); + Load(node->then_expression(), typeof_state()); __ b(&exit); __ bind(&else_); - Load(node->else_expression(), access()); + Load(node->else_expression(), typeof_state()); __ bind(&exit); } -void ArmCodeGenerator::VisitSlot(Slot* node) { - ASSERT(access() != CodeGenState::UNDEFINED); - Comment cmnt(masm_, "[ Slot"); - - if (node->type() == Slot::LOOKUP) { - ASSERT(node->var()->mode() == Variable::DYNAMIC); +void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { + if (slot->type() == Slot::LOOKUP) { + ASSERT(slot->var()->mode() == Variable::DYNAMIC); // For now, just do a runtime call. __ push(cp); - __ mov(r0, Operand(node->var()->name())); + __ mov(r0, Operand(slot->var()->name())); __ push(r0); - if (access() == CodeGenState::LOAD) { - __ CallRuntime(Runtime::kLoadContextSlot, 2); - } else { - ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR); + if (typeof_state == INSIDE_TYPEOF) { __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); + } else { + __ CallRuntime(Runtime::kLoadContextSlot, 2); } __ push(r0); } else { // Note: We would like to keep the assert below, but it fires because of // some nasty code in LoadTypeofExpression() which should be removed... - // ASSERT(node->var()->mode() != Variable::DYNAMIC); + // ASSERT(slot->var()->mode() != Variable::DYNAMIC); // Special handling for locals allocated in registers. - __ ldr(r0, SlotOperand(node, r2)); + __ ldr(r0, SlotOperand(slot, r2)); __ push(r0); - if (node->var()->mode() == Variable::CONST) { + if (slot->var()->mode() == Variable::CONST) { // Const slots may contain 'the hole' value (the constant hasn't been // initialized yet) which needs to be converted into the 'undefined' // value. @@ -2326,24 +2253,22 @@ void ArmCodeGenerator::VisitSlot(Slot* node) { } +void ArmCodeGenerator::VisitSlot(Slot* node) { + Comment cmnt(masm_, "[ Slot"); + LoadFromSlot(node, typeof_state()); +} + + void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) { Comment cmnt(masm_, "[ VariableProxy"); - Variable* var_node = node->var(); - - Expression* expr = var_node->rewrite(); + Variable* var = node->var(); + Expression* expr = var->rewrite(); if (expr != NULL) { Visit(expr); } else { - ASSERT(var_node->is_global()); - if (is_referenced()) { - if (var_node->AsProperty() != NULL) { - __ RecordPosition(var_node->AsProperty()->position()); - } - GetReferenceProperty(new Literal(var_node->name())); - } else { - Reference property(this, node); - GetValue(&property); - } + ASSERT(var->is_global()); + Reference ref(this, node); + ref.GetValue(typeof_state()); } } @@ -2556,7 +2481,7 @@ void ArmCodeGenerator::VisitAssignment(Assignment* node) { Load(node->value()); } else { - GetValue(&target); + target.GetValue(NOT_INSIDE_TYPEOF); Literal* literal = node->value()->AsLiteral(); if (literal != NULL && literal->handle()->IsSmi()) { SmiOperation(node->binary_op(), literal->handle(), false); @@ -2601,15 +2526,8 @@ void ArmCodeGenerator::VisitThrow(Throw* node) { void ArmCodeGenerator::VisitProperty(Property* node) { Comment cmnt(masm_, "[ Property"); - - if (is_referenced()) { - __ RecordPosition(node->position()); - GetReferenceProperty(node->key()); - } else { - Reference property(this, node); - __ RecordPosition(node->position()); - GetValue(&property); - } + Reference property(this, node); + property.GetValue(typeof_state()); } @@ -2713,7 +2631,7 @@ void ArmCodeGenerator::VisitCall(Call* node) { // Load the function to call from the property through a reference. Reference ref(this, property); - GetValue(&ref); // receiver + ref.GetValue(NOT_INSIDE_TYPEOF); // receiver // Pass receiver to called function. __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); @@ -2957,7 +2875,7 @@ void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) { if (op == Token::NOT) { LoadCondition(node->expression(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, false_target(), true_target(), true); @@ -3092,7 +3010,7 @@ void ArmCodeGenerator::VisitCountOperation(CountOperation* node) { { Reference target(this, node->expression()); if (target.is_illegal()) return; - GetValue(&target); + target.GetValue(NOT_INSIDE_TYPEOF); __ pop(r0); Label slow, exit; @@ -3174,7 +3092,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) { if (op == Token::AND) { Label is_true; LoadCondition(node->left(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, &is_true, false_target(), false); @@ -3184,7 +3102,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) { // Evaluate right side expression. __ bind(&is_true); LoadCondition(node->right(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, true_target(), false_target(), false); @@ -3215,7 +3133,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) { } else if (op == Token::OR) { Label is_false; LoadCondition(node->left(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, true_target(), &is_false, false); @@ -3225,7 +3143,7 @@ void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) { // Evaluate right side expression. __ bind(&is_false); LoadCondition(node->right(), - CodeGenState::LOAD, + NOT_INSIDE_TYPEOF, true_target(), false_target(), false); @@ -3517,10 +3435,91 @@ void ArmCodeGenerator::ExitJSFrame() { #undef __ #define __ masm-> +Handle Reference::GetName() { + ASSERT(type_ == NAMED); + Property* property = expression_->AsProperty(); + if (property == NULL) { + // Global variable reference treated as a named property reference. + VariableProxy* proxy = expression_->AsVariableProxy(); + ASSERT(proxy->AsVariable() != NULL); + ASSERT(proxy->AsVariable()->is_global()); + return proxy->name(); + } else { + Literal* raw_name = property->key()->AsLiteral(); + ASSERT(raw_name != NULL); + return Handle(String::cast(*raw_name->handle())); + } +} + + +void Reference::GetValue(TypeofState typeof_state) { + ASSERT(!is_illegal()); + ASSERT(!cgen_->has_cc()); + MacroAssembler* masm = cgen_->masm(); + Property* property = expression_->AsProperty(); + if (property != NULL) { + __ RecordPosition(property->position()); + } + + switch (type_) { + case SLOT: { + Comment cmnt(masm, "[ Load from Slot"); + Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); + ASSERT(slot != NULL); + cgen_->LoadFromSlot(slot, typeof_state); + break; + } + + case NAMED: { + // TODO(1241834): Make sure that this it is safe to ignore the + // distinction between expressions in a typeof and not in a typeof. If + // there is a chance that reference errors can be thrown below, we + // must distinguish between the two kinds of loads (typeof expression + // loads must not throw a reference error). + Comment cmnt(masm, "[ Load from named Property"); + // Setup the name register. + Handle name(GetName()); + __ mov(r2, Operand(name)); + Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + + Variable* var = expression_->AsVariableProxy()->AsVariable(); + if (var != NULL) { + ASSERT(var->is_global()); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + } else { + __ Call(ic, RelocInfo::CODE_TARGET); + } + __ push(r0); + break; + } + + case KEYED: { + // TODO(1241834): Make sure that this it is safe to ignore the + // distinction between expressions in a typeof and not in a typeof. + Comment cmnt(masm, "[ Load from keyed Property"); + ASSERT(property != NULL); + // TODO(1224671): Implement inline caching for keyed loads as on ia32. + GetPropertyStub stub; + __ CallStub(&stub); + __ push(r0); + break; + } + + default: + UNREACHABLE(); + } +} + + void Reference::SetValue(InitState init_state) { ASSERT(!is_illegal()); ASSERT(!cgen_->has_cc()); MacroAssembler* masm = cgen_->masm(); + Property* property = expression_->AsProperty(); + if (property != NULL) { + __ RecordPosition(property->position()); + } + switch (type_) { case SLOT: { Comment cmnt(masm, "[ Store to Slot"); @@ -3606,24 +3605,10 @@ void Reference::SetValue(InitState init_state) { case NAMED: { Comment cmnt(masm, "[ Store to named Property"); - Property* property = expression_->AsProperty(); - Handle name; - if (property == NULL) { - // Global variable reference treated as named property access. - VariableProxy* proxy = expression_->AsVariableProxy(); - ASSERT(proxy->AsVariable() != NULL); - ASSERT(proxy->AsVariable()->is_global()); - name = proxy->name(); - } else { - Literal* raw_name = property->key()->AsLiteral(); - ASSERT(raw_name != NULL); - name = Handle(String::cast(*raw_name->handle())); - __ RecordPosition(property->position()); - } - // Call the appropriate IC code. __ pop(r0); // value // Setup the name register. + Handle name(GetName()); __ mov(r2, Operand(name)); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); __ Call(ic, RelocInfo::CODE_TARGET); diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc index 3f047fee48..10c6dd35b8 100644 --- a/src/codegen-ia32.cc +++ b/src/codegen-ia32.cc @@ -57,6 +57,7 @@ enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; // on the execution stack to represent the reference. enum InitState { CONST_INIT, NOT_CONST_INIT }; +enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; class Reference BASE_EMBEDDED { public: @@ -79,6 +80,18 @@ class Reference BASE_EMBEDDED { bool is_slot() const { return type_ == SLOT; } bool is_property() const { return type_ == NAMED || type_ == KEYED; } + // Return the name. Only valid for named property references. + Handle GetName(); + + // Generate code to push the value of the reference on top of the + // expression stack. The reference is expected to be already on top of + // the expression stack, and it is left in place with its value above it. + void GetValue(TypeofState typeof_state); + + // Generate code to store the value on top of the expression stack in the + // reference. The reference is expected to be immediately below the value + // on the expression stack. The stored value is left in place (with the + // reference intact below it) to support chained assignments. void SetValue(InitState init_state); private: @@ -98,42 +111,29 @@ class Reference BASE_EMBEDDED { class CodeGenState BASE_EMBEDDED { public: - enum AccessType { - UNDEFINED, - LOAD, - LOAD_TYPEOF_EXPR - }; - // Create an initial code generator state. Destroying the initial state // leaves the code generator with a NULL state. explicit CodeGenState(Ia32CodeGenerator* owner); // Create a code generator state based on a code generator's current - // state. The new state has its own access type and pair of branch - // labels, and no reference. + // state. The new state has its own typeof state and pair of branch + // labels. CodeGenState(Ia32CodeGenerator* owner, - AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target); - // Create a code generator state based on a code generator's current - // state. The new state has an access type of LOAD, its own reference, - // and inherits the pair of branch labels of the current state. - CodeGenState(Ia32CodeGenerator* owner, Reference* ref); - // Destroy a code generator state and restore the owning code generator's // previous state. ~CodeGenState(); - AccessType access() const { return access_; } - Reference* ref() const { return ref_; } + TypeofState typeof_state() const { return typeof_state_; } Label* true_target() const { return true_target_; } Label* false_target() const { return false_target_; } private: Ia32CodeGenerator* owner_; - AccessType access_; - Reference* ref_; + TypeofState typeof_state_; Label* true_target_; Label* false_target_; CodeGenState* previous_; @@ -185,9 +185,7 @@ class Ia32CodeGenerator: public CodeGenerator { // State bool has_cc() const { return cc_reg_ >= 0; } - CodeGenState::AccessType access() const { return state_->access(); } - Reference* ref() const { return state_->ref(); } - bool is_referenced() const { return state_->ref() != NULL; } + TypeofState typeof_state() const { return state_->typeof_state(); } Label* true_target() const { return state_->true_target(); } Label* false_target() const { return state_->false_target(); } @@ -216,14 +214,16 @@ class Ia32CodeGenerator: public CodeGenerator { Operand SlotOperand(Slot* slot, Register tmp); void LoadCondition(Expression* x, - CodeGenState::AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target, bool force_cc); - void Load(Expression* x, - CodeGenState::AccessType access = CodeGenState::LOAD); + void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); void LoadGlobal(); + // Read a value from a slot and leave it on top of the expression stack. + void LoadFromSlot(Slot* slot, TypeofState typeof_state); + // Special code for typeof expressions: Unfortunately, we must // be careful when loading the expression in 'typeof' // expressions. We are not allowed to throw reference errors for @@ -232,23 +232,6 @@ class Ia32CodeGenerator: public CodeGenerator { // through the context chain. void LoadTypeofExpression(Expression* x); - // References - - // Generate code to fetch the value of a reference. The reference is - // expected to be on top of the expression stack. It is left in place and - // its value is pushed on top of it. - void GetValue(Reference* ref) { - ASSERT(!has_cc()); - ASSERT(!ref->is_illegal()); - CodeGenState new_state(this, ref); - Visit(ref->expression()); - } - - // Generate code to fetch a value from a property of a reference. The - // reference is expected on top of the expression stack. It is left in - // place and its value is pushed on top of it. - void GetReferenceProperty(Expression* key); - void ToBoolean(Label* true_target, Label* false_target); void GenericBinaryOperation( @@ -340,8 +323,7 @@ class Ia32CodeGenerator: public CodeGenerator { CodeGenState::CodeGenState(Ia32CodeGenerator* owner) : owner_(owner), - access_(UNDEFINED), - ref_(NULL), + typeof_state_(NOT_INSIDE_TYPEOF), true_target_(NULL), false_target_(NULL), previous_(NULL) { @@ -350,12 +332,11 @@ CodeGenState::CodeGenState(Ia32CodeGenerator* owner) CodeGenState::CodeGenState(Ia32CodeGenerator* owner, - AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target) : owner_(owner), - access_(access), - ref_(NULL), + typeof_state_(typeof_state), true_target_(true_target), false_target_(false_target), previous_(owner->state()) { @@ -363,17 +344,6 @@ CodeGenState::CodeGenState(Ia32CodeGenerator* owner, } -CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref) - : owner_(owner), - access_(LOAD), - ref_(ref), - true_target_(owner->state()->true_target_), - false_target_(owner->state()->false_target_), - previous_(owner->state()) { - owner_->set_state(this); -} - - CodeGenState::~CodeGenState() { ASSERT(owner_->state() == this); owner_->set_state(previous_); @@ -759,15 +729,13 @@ Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { // register and no value is pushed. If the condition code register was set, // has_cc() is true and cc_reg_ contains the condition to test for 'true'. void Ia32CodeGenerator::LoadCondition(Expression* x, - CodeGenState::AccessType access, + TypeofState typeof_state, Label* true_target, Label* false_target, bool force_cc) { - ASSERT(access == CodeGenState::LOAD || - access == CodeGenState::LOAD_TYPEOF_EXPR); - ASSERT(!has_cc() && !is_referenced()); + ASSERT(!has_cc()); - { CodeGenState new_state(this, access, true_target, false_target); + { CodeGenState new_state(this, typeof_state, true_target, false_target); Visit(x); } if (force_cc && !has_cc()) { @@ -777,13 +745,10 @@ void Ia32CodeGenerator::LoadCondition(Expression* x, } -void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { - ASSERT(access == CodeGenState::LOAD || - access == CodeGenState::LOAD_TYPEOF_EXPR); - +void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) { Label true_target; Label false_target; - LoadCondition(x, access, &true_target, &false_target, false); + LoadCondition(x, typeof_state, &true_target, &false_target, false); if (has_cc()) { // convert cc_reg_ into a bool @@ -832,8 +797,8 @@ void Ia32CodeGenerator::LoadGlobal() { // TODO(1241834): Get rid of this function in favor of just using Load, now -// that we have the LOAD_TYPEOF_EXPR access type. => Need to handle -// global variables w/o reference errors elsewhere. +// that we have the INSIDE_TYPEOF typeof state. => Need to handle global +// variables w/o reference errors elsewhere. void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { Variable* variable = x->AsVariableProxy()->AsVariable(); if (variable != NULL && !variable->is_this() && variable->is_global()) { @@ -847,7 +812,7 @@ void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { Property property(&global, &key, RelocInfo::kNoPosition); Load(&property); } else { - Load(x, CodeGenState::LOAD_TYPEOF_EXPR); + Load(x, INSIDE_TYPEOF); } } @@ -864,6 +829,7 @@ Reference::~Reference() { void Ia32CodeGenerator::LoadReference(Reference* ref) { + Comment cmnt(masm_, "[ LoadReference"); Expression* e = ref->expression(); Property* property = e->AsProperty(); Variable* var = e->AsVariableProxy()->AsVariable(); @@ -905,7 +871,7 @@ void Ia32CodeGenerator::LoadReference(Reference* ref) { void Ia32CodeGenerator::UnloadReference(Reference* ref) { - // Pop n references on the stack while preserving TOS + // Pop a reference from the stack while preserving TOS. Comment cmnt(masm_, "[ UnloadReference"); int size = ref->size(); if (size <= 0) { @@ -985,47 +951,6 @@ void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { } -void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { - ASSERT(!ref()->is_illegal()); - - // TODO(1241834): Make sure that this it is safe to ignore the distinction - // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance - // that reference errors can be thrown below, we must distinguish between - // the two kinds of loads (typeof expression loads must not throw a - // reference error). - if (ref()->type() == Reference::NAMED) { - // Compute the name of the property. - Literal* literal = key->AsLiteral(); - Handle name(String::cast(*literal->handle())); - - Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); - Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); - // Setup the name register. - __ Set(ecx, Immediate(name)); - if (var != NULL) { - ASSERT(var->is_global()); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - } else { - __ call(ic, RelocInfo::CODE_TARGET); - } - } else { - // Access keyed property. - ASSERT(ref()->type() == Reference::KEYED); - - // Call IC code. - Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); - Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); - if (var != NULL) { - ASSERT(var->is_global()); - __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); - } else { - __ call(ic, RelocInfo::CODE_TARGET); - } - } - __ push(eax); // IC call leaves result in eax, push it out -} - - class FloatingPointHelper : public AllStatic { public: // Code pattern for loading floating point values. Input values must @@ -1676,7 +1601,9 @@ class CallFunctionStub: public CodeStub { void Ia32CodeGenerator::CallWithArguments(ZoneList* args, int position) { // Push the arguments ("left-to-right") on the stack. - for (int i = 0; i < args->length(); i++) Load(args->at(i)); + for (int i = 0; i < args->length(); i++) { + Load(args->at(i)); + } // Record the position for debugging purposes. __ RecordPosition(position); @@ -1821,7 +1748,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { Label then; Label else_; // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); Branch(false, &else_); // then __ bind(&then); @@ -1835,7 +1762,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { ASSERT(!has_else_stm); Label then; // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); Branch(false, &exit); // then __ bind(&then); @@ -1845,7 +1772,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { ASSERT(!has_then_stm); Label else_; // if (!cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); Branch(true, &exit); // else __ bind(&else_); @@ -1854,7 +1781,7 @@ void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { } else { ASSERT(!has_then_stm && !has_else_stm); // if (cond) - LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); if (has_cc()) { cc_reg_ = no_condition; } else { @@ -2139,7 +2066,7 @@ void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) { case ALWAYS_FALSE: break; case DONT_KNOW: - LoadCondition(node->cond(), CodeGenState::LOAD, &loop, + LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, node->break_target(), true); Branch(true, &loop); break; @@ -2608,78 +2535,71 @@ void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral( void Ia32CodeGenerator::VisitConditional(Conditional* node) { Comment cmnt(masm_, "[ Conditional"); Label then, else_, exit; - LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); + LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); Branch(false, &else_); __ bind(&then); - Load(node->then_expression(), access()); + Load(node->then_expression(), typeof_state()); __ jmp(&exit); __ bind(&else_); - Load(node->else_expression(), access()); + Load(node->else_expression(), typeof_state()); __ bind(&exit); } -void Ia32CodeGenerator::VisitSlot(Slot* node) { - ASSERT(access() != CodeGenState::UNDEFINED); - Comment cmnt(masm_, "[ Slot"); - - if (node->type() == Slot::LOOKUP) { - ASSERT(node->var()->mode() == Variable::DYNAMIC); +void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { + if (slot->type() == Slot::LOOKUP) { + ASSERT(slot->var()->mode() == Variable::DYNAMIC); // For now, just do a runtime call. - __ push(Operand(esi)); - __ push(Immediate(node->var()->name())); + __ push(esi); + __ push(Immediate(slot->var()->name())); - if (access() == CodeGenState::LOAD) { - __ CallRuntime(Runtime::kLoadContextSlot, 2); - } else { - ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR); + if (typeof_state == INSIDE_TYPEOF) { __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); + } else { + __ CallRuntime(Runtime::kLoadContextSlot, 2); } __ push(eax); } else { // Note: We would like to keep the assert below, but it fires because of // some nasty code in LoadTypeofExpression() which should be removed... - // ASSERT(node->var()->mode() != Variable::DYNAMIC); - - if (node->var()->mode() == Variable::CONST) { + // ASSERT(slot->var()->mode() != Variable::DYNAMIC); + if (slot->var()->mode() == Variable::CONST) { // Const slots may contain 'the hole' value (the constant hasn't been // initialized yet) which needs to be converted into the 'undefined' // value. Comment cmnt(masm_, "[ Load const"); - Label L; - __ mov(eax, SlotOperand(node, ecx)); + Label exit; + __ mov(eax, SlotOperand(slot, ecx)); __ cmp(eax, Factory::the_hole_value()); - __ j(not_equal, &L); + __ j(not_equal, &exit); __ mov(eax, Factory::undefined_value()); - __ bind(&L); + __ bind(&exit); __ push(eax); } else { - __ push(SlotOperand(node, ecx)); + __ push(SlotOperand(slot, ecx)); } } } +void Ia32CodeGenerator::VisitSlot(Slot* node) { + Comment cmnt(masm_, "[ Slot"); + LoadFromSlot(node, typeof_state()); +} + + void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { Comment cmnt(masm_, "[ VariableProxy"); - Variable* var_node = node->var(); - - Expression* expr = var_node->rewrite(); + Variable* var = node->var(); + Expression* expr = var->rewrite(); if (expr != NULL) { Visit(expr); } else { - ASSERT(var_node->is_global()); - if (is_referenced()) { - if (var_node->AsProperty() != NULL) { - __ RecordPosition(var_node->AsProperty()->position()); - } - GetReferenceProperty(new Literal(var_node->name())); - } else { - Reference property(this, node); - GetValue(&property); - } + ASSERT(var->is_global()); + Reference ref(this, node); + ref.GetValue(typeof_state()); } } @@ -2942,7 +2862,7 @@ void Ia32CodeGenerator::VisitAssignment(Assignment* node) { Load(node->value()); } else { - GetValue(&target); + target.GetValue(NOT_INSIDE_TYPEOF); Literal* literal = node->value()->AsLiteral(); if (IsInlineSmi(literal)) { SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE); @@ -2983,15 +2903,8 @@ void Ia32CodeGenerator::VisitThrow(Throw* node) { void Ia32CodeGenerator::VisitProperty(Property* node) { Comment cmnt(masm_, "[ Property"); - - if (is_referenced()) { - __ RecordPosition(node->position()); - GetReferenceProperty(node->key()); - } else { - Reference property(this, node); - __ RecordPosition(node->position()); - GetValue(&property); - } + Reference property(this, node); + property.GetValue(typeof_state()); } @@ -3090,7 +3003,7 @@ void Ia32CodeGenerator::VisitCall(Call* node) { // Load the function to call from the property through a reference. Reference ref(this, property); - GetValue(&ref); + ref.GetValue(NOT_INSIDE_TYPEOF); // Pass receiver to called function. // The reference's size is non-negative. @@ -3456,7 +3369,7 @@ void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { Token::Value op = node->op(); if (op == Token::NOT) { - LoadCondition(node->expression(), CodeGenState::LOAD, + LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, false_target(), true_target(), true); cc_reg_ = NegateCondition(cc_reg_); @@ -3677,7 +3590,7 @@ void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) { { Reference target(this, node->expression()); if (target.is_illegal()) return; - GetValue(&target); + target.GetValue(NOT_INSIDE_TYPEOF); int result_offset = target.size() * kPointerSize; CountOperationDeferred* deferred = @@ -3732,14 +3645,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { if (op == Token::AND) { Label is_true; - LoadCondition(node->left(), CodeGenState::LOAD, &is_true, + LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, false_target(), false); if (has_cc()) { Branch(false, false_target()); // Evaluate right side expression. __ bind(&is_true); - LoadCondition(node->right(), CodeGenState::LOAD, true_target(), + LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), false_target(), false); } else { @@ -3768,14 +3681,14 @@ void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { } else if (op == Token::OR) { Label is_false; - LoadCondition(node->left(), CodeGenState::LOAD, true_target(), + LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), &is_false, false); if (has_cc()) { Branch(true, true_target()); // Evaluate right side expression. __ bind(&is_false); - LoadCondition(node->right(), CodeGenState::LOAD, true_target(), + LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), false_target(), false); } else { @@ -4090,6 +4003,87 @@ void Ia32CodeGenerator::ExitJSFrame() { #undef __ #define __ masm-> +Handle Reference::GetName() { + ASSERT(type_ == NAMED); + Property* property = expression_->AsProperty(); + if (property == NULL) { + // Global variable reference treated as a named property reference. + VariableProxy* proxy = expression_->AsVariableProxy(); + ASSERT(proxy->AsVariable() != NULL); + ASSERT(proxy->AsVariable()->is_global()); + return proxy->name(); + } else { + MacroAssembler* masm = cgen_->masm(); + __ RecordPosition(property->position()); + Literal* raw_name = property->key()->AsLiteral(); + ASSERT(raw_name != NULL); + return Handle(String::cast(*raw_name->handle())); + } +} + + +void Reference::GetValue(TypeofState typeof_state) { + ASSERT(!is_illegal()); + ASSERT(!cgen_->has_cc()); + MacroAssembler* masm = cgen_->masm(); + switch (type_) { + case SLOT: { + Comment cmnt(masm, "[ Load from Slot"); + Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); + ASSERT(slot != NULL); + cgen_->LoadFromSlot(slot, typeof_state); + break; + } + + case NAMED: { + // TODO(1241834): Make sure that this it is safe to ignore the + // distinction between expressions in a typeof and not in a typeof. If + // there is a chance that reference errors can be thrown below, we + // must distinguish between the two kinds of loads (typeof expression + // loads must not throw a reference error). + Comment cmnt(masm, "[ Load from named Property"); + Handle name(GetName()); + Handle ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + // Setup the name register. + __ mov(ecx, name); + + Variable* var = expression_->AsVariableProxy()->AsVariable(); + if (var != NULL) { + ASSERT(var->is_global()); + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + } else { + __ call(ic, RelocInfo::CODE_TARGET); + } + __ push(eax); // IC call leaves result in eax, push it out + break; + } + + case KEYED: { + // TODO(1241834): Make sure that this it is safe to ignore the + // distinction between expressions in a typeof and not in a typeof. + Comment cmnt(masm, "[ Load from keyed Property"); + Property* property = expression_->AsProperty(); + ASSERT(property != NULL); + __ RecordPosition(property->position()); + Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); + + Variable* var = expression_->AsVariableProxy()->AsVariable(); + if (var != NULL) { + ASSERT(var->is_global()); + __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); + } else { + __ call(ic, RelocInfo::CODE_TARGET); + } + __ push(eax); // IC call leaves result in eax, push it out + break; + } + + default: + UNREACHABLE(); + } +} + + void Reference::SetValue(InitState init_state) { ASSERT(!is_illegal()); ASSERT(!cgen_->has_cc()); @@ -4172,22 +4166,8 @@ void Reference::SetValue(InitState init_state) { case NAMED: { Comment cmnt(masm, "[ Store to named Property"); - Property* property = expression_->AsProperty(); - Handle name; - if (property == NULL) { - // Global variable reference treated as named property access. - VariableProxy* proxy = expression_->AsVariableProxy(); - ASSERT(proxy->AsVariable() != NULL); - ASSERT(proxy->AsVariable()->is_global()); - name = proxy->name(); - } else { - Literal* raw_name = property->key()->AsLiteral(); - ASSERT(raw_name != NULL); - name = Handle(String::cast(*raw_name->handle())); - __ RecordPosition(property->position()); - } - // Call the appropriate IC code. + Handle name(GetName()); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); // TODO(1222589): Make the IC grab the values from the stack. __ pop(eax);