diff options
Diffstat (limited to 'deps/v8/src/ia32/fast-codegen-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/fast-codegen-ia32.cc | 671 |
1 files changed, 333 insertions, 338 deletions
diff --git a/deps/v8/src/ia32/fast-codegen-ia32.cc b/deps/v8/src/ia32/fast-codegen-ia32.cc index 46524d7dce..fdab585797 100644 --- a/deps/v8/src/ia32/fast-codegen-ia32.cc +++ b/deps/v8/src/ia32/fast-codegen-ia32.cc @@ -194,182 +194,118 @@ void FastCodeGenerator::EmitReturnSequence(int position) { } -void FastCodeGenerator::Move(Expression::Context context, Register source) { +void FastCodeGenerator::Apply(Expression::Context context, + Slot* slot, + Register scratch) { switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: break; - case Expression::kValue: - __ push(source); + case Expression::kValue: { + MemOperand location = EmitSlotSearch(slot, scratch); + __ push(location); break; + } case Expression::kTest: - TestAndBranch(source, true_label_, false_label_); - break; - case Expression::kValueTest: { - Label discard; - __ push(source); - TestAndBranch(source, true_label_, &discard); - __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); - __ jmp(false_label_); + case Expression::kValueTest: + case Expression::kTestValue: + Move(scratch, slot); + Apply(context, scratch); break; - } - case Expression::kTestValue: { - Label discard; - __ push(source); - TestAndBranch(source, &discard, false_label_); - __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); - __ jmp(true_label_); - } } } -template <> -Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, - Register scratch) { - switch (source->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - return Operand(ebp, SlotOffset(source)); - case Slot::CONTEXT: { - int context_chain_length = - function_->scope()->ContextChainLength(source->var()->scope()); - __ LoadContext(scratch, context_chain_length); - return CodeGenerator::ContextOperand(scratch, source->index()); - break; - } - case Slot::LOOKUP: - UNIMPLEMENTED(); - // Fall-through. - default: - UNREACHABLE(); - return Operand(eax, 0); // Dead code to make the compiler happy. - } -} - - -void FastCodeGenerator::Move(Register dst, Slot* source) { - Operand location = CreateSlotOperand<Operand>(source, dst); - __ mov(dst, location); -} - - -void FastCodeGenerator::Move(Expression::Context context, - Slot* source, - Register scratch) { +void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) { switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: break; - case Expression::kValue: { - Operand location = CreateSlotOperand<Operand>(source, scratch); - __ push(location); + case Expression::kValue: + __ push(Immediate(lit->handle())); break; - } - case Expression::kTest: // Fall through. - case Expression::kValueTest: // Fall through. + case Expression::kTest: + case Expression::kValueTest: case Expression::kTestValue: - Move(scratch, source); - Move(context, scratch); + __ mov(eax, lit->handle()); + Apply(context, eax); break; } } -void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { +void FastCodeGenerator::ApplyTOS(Expression::Context context) { switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: + __ Drop(1); break; case Expression::kValue: - __ push(Immediate(expr->handle())); break; - case Expression::kTest: // Fall through. - case Expression::kValueTest: // Fall through. - case Expression::kTestValue: - __ mov(eax, expr->handle()); - Move(context, eax); - break; - } -} - - -void FastCodeGenerator::Move(Slot* dst, - Register src, - Register scratch1, - Register scratch2) { - switch (dst->type()) { - case Slot::PARAMETER: - case Slot::LOCAL: - __ mov(Operand(ebp, SlotOffset(dst)), src); + case Expression::kTest: + __ pop(eax); + TestAndBranch(eax, true_label_, false_label_); break; - case Slot::CONTEXT: { - ASSERT(!src.is(scratch1)); - ASSERT(!src.is(scratch2)); - ASSERT(!scratch1.is(scratch2)); - int context_chain_length = - function_->scope()->ContextChainLength(dst->var()->scope()); - __ LoadContext(scratch1, context_chain_length); - __ mov(Operand(scratch1, Context::SlotOffset(dst->index())), src); - int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; - __ RecordWrite(scratch1, offset, src, scratch2); + case Expression::kValueTest: { + Label discard; + __ mov(eax, Operand(esp, 0)); + TestAndBranch(eax, true_label_, &discard); + __ bind(&discard); + __ Drop(1); + __ jmp(false_label_); break; } - case Slot::LOOKUP: - UNIMPLEMENTED(); - default: - UNREACHABLE(); + case Expression::kTestValue: { + Label discard; + __ mov(eax, Operand(esp, 0)); + TestAndBranch(eax, &discard, false_label_); + __ bind(&discard); + __ Drop(1); + __ jmp(true_label_); + } } } -void FastCodeGenerator::DropAndMove(Expression::Context context, - Register source, - int count) { +void FastCodeGenerator::DropAndApply(int count, + Expression::Context context, + Register reg) { ASSERT(count > 0); + ASSERT(!reg.is(esp)); switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: - __ add(Operand(esp), Immediate(count * kPointerSize)); + __ Drop(count); break; case Expression::kValue: - if (count > 1) { - __ add(Operand(esp), Immediate((count - 1) * kPointerSize)); - } - __ mov(Operand(esp, 0), source); + if (count > 1) __ Drop(count - 1); + __ mov(Operand(esp, 0), reg); break; case Expression::kTest: - ASSERT(!source.is(esp)); - __ add(Operand(esp), Immediate(count * kPointerSize)); - TestAndBranch(source, true_label_, false_label_); + __ Drop(count); + TestAndBranch(reg, true_label_, false_label_); break; case Expression::kValueTest: { Label discard; - if (count > 1) { - __ add(Operand(esp), Immediate((count - 1) * kPointerSize)); - } - __ mov(Operand(esp, 0), source); - TestAndBranch(source, true_label_, &discard); + if (count > 1) __ Drop(count - 1); + __ mov(Operand(esp, 0), reg); + TestAndBranch(reg, true_label_, &discard); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(false_label_); break; } case Expression::kTestValue: { Label discard; - if (count > 1) { - __ add(Operand(esp), Immediate((count - 1) * kPointerSize)); - } - __ mov(Operand(esp, 0), source); - TestAndBranch(source, &discard, false_label_); + if (count > 1) __ Drop(count - 1); + __ mov(Operand(esp, 0), reg); + TestAndBranch(reg, &discard, false_label_); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(true_label_); break; } @@ -377,6 +313,47 @@ void FastCodeGenerator::DropAndMove(Expression::Context context, } +MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) { + switch (slot->type()) { + case Slot::PARAMETER: + case Slot::LOCAL: + return Operand(ebp, SlotOffset(slot)); + case Slot::CONTEXT: { + int context_chain_length = + function_->scope()->ContextChainLength(slot->var()->scope()); + __ LoadContext(scratch, context_chain_length); + return CodeGenerator::ContextOperand(scratch, slot->index()); + } + case Slot::LOOKUP: + UNREACHABLE(); + } + UNREACHABLE(); + return Operand(eax, 0); +} + + +void FastCodeGenerator::Move(Register destination, Slot* source) { + MemOperand location = EmitSlotSearch(source, destination); + __ mov(destination, location); +} + + +void FastCodeGenerator::Move(Slot* dst, + Register src, + Register scratch1, + Register scratch2) { + ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented. + ASSERT(!scratch1.is(src) && !scratch2.is(src)); + MemOperand location = EmitSlotSearch(dst, scratch1); + __ mov(location, src); + // Emit the write barrier code if the location is in the heap. + if (dst->type() == Slot::CONTEXT) { + int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; + __ RecordWrite(scratch1, offset, src, scratch2); + } +} + + void FastCodeGenerator::TestAndBranch(Register source, Label* true_label, Label* false_label) { @@ -416,18 +393,21 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) { if (slot != NULL) { switch (slot->type()) { - case Slot::PARAMETER: // Fall through. + case Slot::PARAMETER: case Slot::LOCAL: if (decl->mode() == Variable::CONST) { - __ mov(Operand(ebp, SlotOffset(var->slot())), + __ mov(Operand(ebp, SlotOffset(slot)), Immediate(Factory::the_hole_value())); } else if (decl->fun() != NULL) { Visit(decl->fun()); - __ pop(Operand(ebp, SlotOffset(var->slot()))); + __ pop(Operand(ebp, SlotOffset(slot))); } break; case Slot::CONTEXT: + // We bypass the general EmitSlotSearch because we know more about + // this specific context. + // The variable in the decl always resides in the current context. ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); if (FLAG_debug_code) { @@ -499,7 +479,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) { // Value in eax is ignored (declarations are statements). Receiver // and key on stack are discarded. - __ add(Operand(esp), Immediate(2 * kPointerSize)); + __ Drop(2); } } } @@ -529,7 +509,7 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { __ push(esi); __ push(Immediate(boilerplate)); __ CallRuntime(Runtime::kNewClosure, 2); - Move(expr->context(), eax); + Apply(expr->context(), eax); } @@ -556,13 +536,13 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var, // Remember that the assembler may choose to do peephole optimization // (eg, push/pop elimination). __ nop(); - DropAndMove(context, eax); + DropAndApply(1, context, eax); } else if (rewrite->AsSlot() != NULL) { Slot* slot = rewrite->AsSlot(); if (FLAG_debug_code) { switch (slot->type()) { - case Slot::LOCAL: - case Slot::PARAMETER: { + case Slot::PARAMETER: + case Slot::LOCAL: { Comment cmnt(masm_, "Stack slot"); break; } @@ -573,46 +553,45 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var, case Slot::LOOKUP: UNIMPLEMENTED(); break; - default: - UNREACHABLE(); } } - Move(context, slot, eax); + Apply(context, slot, eax); } else { - Comment cmnt(masm_, "Variable rewritten to Property"); - // A variable has been rewritten into an explicit access to - // an object property. + Comment cmnt(masm_, "Variable rewritten to property"); + // A variable has been rewritten into an explicit access to an object + // property. Property* property = rewrite->AsProperty(); ASSERT_NOT_NULL(property); - // Currently the only parameter expressions that can occur are - // on the form "slot[literal]". + // The only property expressions that can occur are of the form + // "slot[literal]". - // Check that the object is in a slot. + // Assert that the object is in a slot. Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); ASSERT_NOT_NULL(object_var); Slot* object_slot = object_var->slot(); ASSERT_NOT_NULL(object_slot); // Load the object. - Move(Expression::kValue, object_slot, eax); + MemOperand object_loc = EmitSlotSearch(object_slot, eax); + __ push(object_loc); - // Check that the key is a smi. + // Assert that the key is a smi. Literal* key_literal = property->key()->AsLiteral(); ASSERT_NOT_NULL(key_literal); ASSERT(key_literal->handle()->IsSmi()); // Load the key. - Move(Expression::kValue, key_literal); + __ push(Immediate(key_literal->handle())); - // Do a KEYED property load. + // Do a keyed property load. Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); - // Notice: We must not have a "test eax, ..." instruction after - // the call. It is treated specially by the LoadIC code. + // Notice: We must not have a "test eax, ..." instruction after the + // call. It is treated specially by the LoadIC code. __ nop(); // Drop key and object left on the stack by IC. - DropAndMove(context, eax, 2); + DropAndApply(2, context, eax); } } @@ -640,7 +619,7 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); // Label done: __ bind(&done); - Move(expr->context(), eax); + Apply(expr->context(), eax); } @@ -672,7 +651,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { result_saved = true; } switch (property->kind()) { - case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through + case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through. ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); case ObjectLiteral::Property::COMPUTED: if (key->handle()->IsSymbol()) { @@ -686,7 +665,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ mov(eax, Operand(esp, 0)); // Restore result into eax. break; } - // fall through + // Fall through. case ObjectLiteral::Property::PROTOTYPE: __ push(eax); Visit(key); @@ -696,7 +675,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ CallRuntime(Runtime::kSetProperty, 3); __ mov(eax, Operand(esp, 0)); // Restore result into eax. break; - case ObjectLiteral::Property::SETTER: // fall through + case ObjectLiteral::Property::SETTER: case ObjectLiteral::Property::GETTER: __ push(eax); Visit(key); @@ -716,7 +695,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: - if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); + if (result_saved) __ Drop(1); break; case Expression::kValue: if (!result_saved) __ push(eax); @@ -730,7 +709,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { if (!result_saved) __ push(eax); TestAndBranch(eax, true_label_, &discard); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(false_label_); break; } @@ -739,7 +718,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { if (!result_saved) __ push(eax); TestAndBranch(eax, &discard, false_label_); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(true_label_); break; } @@ -752,7 +731,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(expr->literal_index()))); - __ push(Immediate(expr->literals())); + __ push(Immediate(expr->constant_elements())); if (expr->depth() > 1) { __ CallRuntime(Runtime::kCreateArrayLiteral, 3); } else { @@ -795,7 +774,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: - if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); + if (result_saved) __ Drop(1); break; case Expression::kValue: if (!result_saved) __ push(eax); @@ -809,7 +788,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { if (!result_saved) __ push(eax); TestAndBranch(eax, true_label_, &discard); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(false_label_); break; } @@ -818,7 +797,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { if (!result_saved) __ push(eax); TestAndBranch(eax, &discard, false_label_); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(true_label_); break; } @@ -828,18 +807,21 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, Expression::Context context) { + SetSourcePosition(prop->position()); Literal* key = prop->key()->AsLiteral(); __ mov(ecx, Immediate(key->handle())); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); - Move(context, eax); + Apply(context, eax); } -void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { +void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop, + Expression::Context context) { + SetSourcePosition(prop->position()); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); - Move(context, eax); + Apply(context, eax); } @@ -849,12 +831,12 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, NO_OVERWRITE, NO_GENERIC_BINARY_FLAGS); __ CallStub(&stub); - Move(context, eax); + Apply(context, eax); } -void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { - Variable* var = expr->target()->AsVariableProxy()->AsVariable(); +void FastCodeGenerator::EmitVariableAssignment(Variable* var, + Expression::Context context) { ASSERT(var != NULL); ASSERT(var->is_global() || var->slot() != NULL); if (var->is_global()) { @@ -867,15 +849,15 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); // Overwrite the receiver on the stack with the result if needed. - DropAndMove(expr->context(), eax); + DropAndApply(1, context, eax); } else if (var->slot() != NULL) { Slot* slot = var->slot(); switch (slot->type()) { case Slot::LOCAL: case Slot::PARAMETER: { - Operand target = Operand(ebp, SlotOffset(var->slot())); - switch (expr->context()) { + Operand target = Operand(ebp, SlotOffset(slot)); + switch (context) { case Expression::kUninitialized: UNREACHABLE(); case Expression::kEffect: @@ -899,7 +881,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { __ mov(target, eax); TestAndBranch(eax, true_label_, &discard); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(false_label_); break; } @@ -909,7 +891,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { __ mov(target, eax); TestAndBranch(eax, &discard, false_label_); __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); __ jmp(true_label_); break; } @@ -918,41 +900,20 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { } case Slot::CONTEXT: { - int chain_length = - function_->scope()->ContextChainLength(slot->var()->scope()); - if (chain_length > 0) { - // Move up the context chain to the context containing the slot. - __ mov(eax, - Operand(esi, Context::SlotOffset(Context::CLOSURE_INDEX))); - // Load the function context (which is the incoming, outer context). - __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset)); - for (int i = 1; i < chain_length; i++) { - __ mov(eax, - Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX))); - __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset)); - } - } else { // Slot is in the current context. Generate optimized code. - __ mov(eax, esi); // RecordWrite destroys the object register. - } - if (FLAG_debug_code) { - __ cmp(eax, - Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX))); - __ Check(equal, "Context Slot chain length wrong."); - } - __ pop(ecx); - __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx); + MemOperand target = EmitSlotSearch(slot, ecx); + __ pop(eax); + __ mov(target, eax); // RecordWrite may destroy all its register arguments. - if (expr->context() == Expression::kValue) { - __ push(ecx); - } else if (expr->context() != Expression::kEffect) { - __ mov(edx, ecx); + if (context == Expression::kValue) { + __ push(eax); + } else if (context != Expression::kEffect) { + __ mov(edx, eax); } int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; - __ RecordWrite(eax, offset, ecx, ebx); - if (expr->context() != Expression::kEffect && - expr->context() != Expression::kValue) { - Move(expr->context(), edx); + __ RecordWrite(ecx, offset, eax, ebx); + if (context != Expression::kEffect && context != Expression::kValue) { + Apply(context, edx); } break; } @@ -961,6 +922,10 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { UNREACHABLE(); break; } + } else { + // Variables rewritten as properties are not treated as variables in + // assignments. + UNREACHABLE(); } } @@ -992,7 +957,7 @@ void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { __ pop(eax); } - DropAndMove(expr->context(), eax); + DropAndApply(1, expr->context(), eax); } @@ -1025,34 +990,32 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { } // Receiver and key are still on stack. - __ add(Operand(esp), Immediate(2 * kPointerSize)); - Move(expr->context(), eax); + DropAndApply(2, expr->context(), eax); } void FastCodeGenerator::VisitProperty(Property* expr) { Comment cmnt(masm_, "[ Property"); Expression* key = expr->key(); - uint32_t dummy; // Record the source position for the property load. SetSourcePosition(expr->position()); - // Evaluate receiver. + // Evaluate the receiver. Visit(expr->obj()); - if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() && - !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) { - // Do a NAMED property load. - // The IC expects the property name in ecx and the receiver on the stack. + if (key->IsPropertyName()) { + // Do a named property load. The IC expects the property name in ecx + // and the receiver on the stack. __ mov(ecx, Immediate(key->AsLiteral()->handle())); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); // By emitting a nop we make sure that we do not have a test eax // instruction after the call it is treated specially by the LoadIC code. __ nop(); + DropAndApply(1, expr->context(), eax); } else { - // Do a KEYED property load. + // Do a keyed property load. Visit(expr->key()); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); __ call(ic, RelocInfo::CODE_TARGET); @@ -1060,9 +1023,8 @@ void FastCodeGenerator::VisitProperty(Property* expr) { // instruction after the call it is treated specially by the LoadIC code. __ nop(); // Drop key left on the stack by IC. - __ add(Operand(esp), Immediate(kPointerSize)); + DropAndApply(2, expr->context(), eax); } - DropAndMove(expr->context(), eax); } @@ -1084,7 +1046,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, __ call(ic, mode); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - Move(expr->context(), eax); + Apply(expr->context(), eax); } @@ -1101,7 +1063,7 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) { __ CallStub(&stub); // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); - DropAndMove(expr->context(), eax); + DropAndApply(1, expr->context(), eax); } @@ -1142,14 +1104,15 @@ void FastCodeGenerator::VisitCall(Call* expr) { // instruction after the call it is treated specially by the LoadIC code. __ nop(); // Drop key left on the stack by IC. - __ add(Operand(esp), Immediate(kPointerSize)); + __ Drop(1); // Pop receiver. __ pop(ebx); // Push result (function). __ push(eax); // Push receiver object on stack. if (prop->is_synthetic()) { - __ push(CodeGenerator::GlobalObject()); + __ mov(ecx, CodeGenerator::GlobalObject()); + __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); } else { __ push(ebx); } @@ -1210,7 +1173,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) { __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); // Replace function on TOS with result in eax, or pop it. - DropAndMove(expr->context(), eax); + DropAndApply(1, expr->context(), eax); } @@ -1243,7 +1206,7 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { // Call the C runtime function. __ CallRuntime(expr->function(), arg_count); } - Move(expr->context(), eax); + Apply(expr->context(), eax); } @@ -1266,7 +1229,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // Value is false so it's needed. __ push(Immediate(Factory::undefined_value())); // Fall through. - case Expression::kTest: // Fall through. + case Expression::kTest: case Expression::kValueTest: __ jmp(false_label_); break; @@ -1278,20 +1241,19 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { Comment cmnt(masm_, "[ UnaryOperation (NOT)"); ASSERT_EQ(Expression::kTest, expr->expression()->context()); - Label push_true; - Label push_false; - Label done; - Label* saved_true = true_label_; - Label* saved_false = false_label_; + Label push_true, push_false, done; switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); break; + case Expression::kEffect: + VisitForControl(expr->expression(), &done, &done); + __ bind(&done); + break; + case Expression::kValue: - true_label_ = &push_false; - false_label_ = &push_true; - Visit(expr->expression()); + VisitForControl(expr->expression(), &push_false, &push_true); __ bind(&push_true); __ push(Immediate(Factory::true_value())); __ jmp(&done); @@ -1300,39 +1262,24 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { __ bind(&done); break; - case Expression::kEffect: - true_label_ = &done; - false_label_ = &done; - Visit(expr->expression()); - __ bind(&done); - break; - case Expression::kTest: - true_label_ = saved_false; - false_label_ = saved_true; - Visit(expr->expression()); + VisitForControl(expr->expression(), false_label_, true_label_); break; case Expression::kValueTest: - true_label_ = saved_false; - false_label_ = &push_true; - Visit(expr->expression()); + VisitForControl(expr->expression(), false_label_, &push_true); __ bind(&push_true); __ push(Immediate(Factory::true_value())); - __ jmp(saved_true); + __ jmp(true_label_); break; case Expression::kTestValue: - true_label_ = &push_false; - false_label_ = saved_true; - Visit(expr->expression()); + VisitForControl(expr->expression(), &push_false, true_label_); __ bind(&push_false); __ push(Immediate(Factory::false_value())); - __ jmp(saved_false); + __ jmp(false_label_); break; } - true_label_ = saved_true; - false_label_ = saved_false; break; } @@ -1365,7 +1312,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { } __ CallRuntime(Runtime::kTypeof, 1); - Move(expr->context(), eax); + Apply(expr->context(), eax); break; } @@ -1377,27 +1324,75 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { Comment cmnt(masm_, "[ CountOperation"); - VariableProxy* proxy = expr->expression()->AsVariableProxy(); - ASSERT(proxy->AsVariable() != NULL); - ASSERT(proxy->AsVariable()->is_global()); - Visit(proxy); + // Expression can only be a property, a global or a (parameter or local) + // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. + enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; + LhsKind assign_type = VARIABLE; + Property* prop = expr->expression()->AsProperty(); + // In case of a property we use the uninitialized expression context + // of the key to detect a named property. + if (prop != NULL) { + assign_type = (prop->key()->context() == Expression::kUninitialized) + ? NAMED_PROPERTY + : KEYED_PROPERTY; + } + + // Evaluate expression and get value. + if (assign_type == VARIABLE) { + ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); + EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), + Expression::kValue); + } else { + // Reserve space for result of postfix operation. + if (expr->is_postfix() && expr->context() != Expression::kEffect) { + ASSERT(expr->context() != Expression::kUninitialized); + __ push(Immediate(Smi::FromInt(0))); + } + Visit(prop->obj()); + ASSERT_EQ(Expression::kValue, prop->obj()->context()); + if (assign_type == NAMED_PROPERTY) { + EmitNamedPropertyLoad(prop, Expression::kValue); + } else { + Visit(prop->key()); + ASSERT_EQ(Expression::kValue, prop->key()->context()); + EmitKeyedPropertyLoad(prop, Expression::kValue); + } + } + + // Convert to number. __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); - switch (expr->context()) { - case Expression::kUninitialized: - UNREACHABLE(); - case Expression::kValue: // Fall through - case Expression::kTest: // Fall through - case Expression::kTestValue: // Fall through - case Expression::kValueTest: - // Duplicate the result on the stack. - __ push(eax); - break; - case Expression::kEffect: - // Do not save result. - break; + // Save result for postfix expressions. + if (expr->is_postfix()) { + switch (expr->context()) { + case Expression::kUninitialized: + UNREACHABLE(); + case Expression::kEffect: + // Do not save result. + break; + case Expression::kValue: + case Expression::kTest: + case Expression::kTestValue: + case Expression::kValueTest: + // Save the result on the stack. If we have a named or keyed property + // we store the result under the receiver that is currently on top + // of the stack. + switch (assign_type) { + case VARIABLE: + __ push(eax); + break; + case NAMED_PROPERTY: + __ mov(Operand(esp, kPointerSize), eax); + break; + case KEYED_PROPERTY: + __ mov(Operand(esp, 2 * kPointerSize), eax); + break; + } + break; + } } + // Call runtime for +1/-1. __ push(eax); __ push(Immediate(Smi::FromInt(1))); @@ -1406,42 +1401,55 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { } else { __ CallRuntime(Runtime::kNumberSub, 2); } - // Call Store IC. - __ mov(ecx, proxy->AsVariable()->name()); - __ push(CodeGenerator::GlobalObject()); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - // Restore up stack after store IC. - __ add(Operand(esp), Immediate(kPointerSize)); - switch (expr->context()) { - case Expression::kUninitialized: - UNREACHABLE(); - case Expression::kEffect: // Fall through - case Expression::kValue: - // Do nothing. Result in either on the stack for value context - // or discarded for effect context. - break; - case Expression::kTest: - __ pop(eax); - TestAndBranch(eax, true_label_, false_label_); + // Store the value returned in eax. + switch (assign_type) { + case VARIABLE: + __ push(eax); + if (expr->is_postfix()) { + EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), + Expression::kEffect); + // For all contexts except kEffect: We have the result on + // top of the stack. + if (expr->context() != Expression::kEffect) { + ApplyTOS(expr->context()); + } + } else { + EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), + expr->context()); + } break; - case Expression::kValueTest: { - Label discard; - __ mov(eax, Operand(esp, 0)); - TestAndBranch(eax, true_label_, &discard); - __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); - __ jmp(false_label_); + case NAMED_PROPERTY: { + __ mov(ecx, prop->key()->AsLiteral()->handle()); + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + // This nop signals to the IC that there is no inlined code at the call + // site for it to patch. + __ nop(); + if (expr->is_postfix()) { + __ Drop(1); // Result is on the stack under the receiver. + if (expr->context() != Expression::kEffect) { + ApplyTOS(expr->context()); + } + } else { + DropAndApply(1, expr->context(), eax); + } break; } - case Expression::kTestValue: { - Label discard; - __ mov(eax, Operand(esp, 0)); - TestAndBranch(eax, &discard, false_label_); - __ bind(&discard); - __ add(Operand(esp), Immediate(kPointerSize)); - __ jmp(true_label_); + case KEYED_PROPERTY: { + Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + // This nop signals to the IC that there is no inlined code at the call + // site for it to patch. + __ nop(); + if (expr->is_postfix()) { + __ Drop(2); // Result is on the stack under the key and the receiver. + if (expr->context() != Expression::kEffect) { + ApplyTOS(expr->context()); + } + } else { + DropAndApply(2, expr->context(), eax); + } break; } } @@ -1483,7 +1491,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { NO_OVERWRITE, NO_GENERIC_BINARY_FLAGS); __ CallStub(&stub); - Move(expr->context(), eax); + Apply(expr->context(), eax); break; } @@ -1500,46 +1508,40 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { Visit(expr->left()); Visit(expr->right()); - // Convert current context to test context: Pre-test code. - Label push_true; - Label push_false; - Label done; - Label* saved_true = true_label_; - Label* saved_false = false_label_; + // Always perform the comparison for its control flow. Pack the result + // into the expression's context after the comparison is performed. + Label push_true, push_false, done; + // Initially assume we are in a test context. + Label* if_true = true_label_; + Label* if_false = false_label_; switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); break; - - case Expression::kValue: - true_label_ = &push_true; - false_label_ = &push_false; - break; - case Expression::kEffect: - true_label_ = &done; - false_label_ = &done; + if_true = &done; + if_false = &done; + break; + case Expression::kValue: + if_true = &push_true; + if_false = &push_false; break; - case Expression::kTest: break; - case Expression::kValueTest: - true_label_ = &push_true; + if_true = &push_true; break; - case Expression::kTestValue: - false_label_ = &push_false; + if_false = &push_false; break; } - // Convert current context to test context: End pre-test code. switch (expr->op()) { case Token::IN: { __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); __ cmp(eax, Factory::true_value()); - __ j(equal, true_label_); - __ jmp(false_label_); + __ j(equal, if_true); + __ jmp(if_false); break; } @@ -1547,8 +1549,8 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { InstanceofStub stub; __ CallStub(&stub); __ test(eax, Operand(eax)); - __ j(zero, true_label_); // The stub returns 0 for true. - __ jmp(false_label_); + __ j(zero, if_true); // The stub returns 0 for true. + __ jmp(if_false); break; } @@ -1600,24 +1602,29 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { __ test(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &slow_case, not_taken); __ cmp(edx, Operand(eax)); - __ j(cc, true_label_); - __ jmp(false_label_); + __ j(cc, if_true); + __ jmp(if_false); __ bind(&slow_case); CompareStub stub(cc, strict); __ CallStub(&stub); __ test(eax, Operand(eax)); - __ j(cc, true_label_); - __ jmp(false_label_); + __ j(cc, if_true); + __ jmp(if_false); } } - // Convert current context to test context: Post-test code. + // Convert the result of the comparison into one expected for this + // expression's context. switch (expr->context()) { case Expression::kUninitialized: UNREACHABLE(); break; + case Expression::kEffect: + __ bind(&done); + break; + case Expression::kValue: __ bind(&push_true); __ push(Immediate(Factory::true_value())); @@ -1627,34 +1634,27 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { __ bind(&done); break; - case Expression::kEffect: - __ bind(&done); - break; - case Expression::kTest: break; case Expression::kValueTest: __ bind(&push_true); __ push(Immediate(Factory::true_value())); - __ jmp(saved_true); + __ jmp(true_label_); break; case Expression::kTestValue: __ bind(&push_false); __ push(Immediate(Factory::false_value())); - __ jmp(saved_false); + __ jmp(false_label_); break; } - true_label_ = saved_true; - false_label_ = saved_false; - // Convert current context to test context: End post-test code. } void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); - Move(expr->context(), eax); + Apply(expr->context(), eax); } @@ -1706,11 +1706,6 @@ void FastCodeGenerator::ExitFinallyBlock() { } -void FastCodeGenerator::ThrowException() { - __ push(result_register()); - __ CallRuntime(Runtime::kThrow, 1); -} - #undef __ } } // namespace v8::internal |