| Index: src/ia32/full-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/full-codegen-ia32.cc (revision 5450)
|
| +++ src/ia32/full-codegen-ia32.cc (working copy)
|
| @@ -239,226 +239,165 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| +void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
|
| + // Nothing to do.
|
| +}
|
|
|
| - case Expression::kEffect:
|
| - // Nothing to do.
|
| - break;
|
|
|
| - case Expression::kValue:
|
| - // Move value into place.
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| - break;
|
| - case kStack:
|
| - __ push(reg);
|
| - break;
|
| - }
|
| - break;
|
| +void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
|
| + MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
|
| + __ mov(result_register(), slot_operand);
|
| +}
|
|
|
| - case Expression::kTest:
|
| - // For simplicity we always test the accumulator register.
|
| - if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| - DoTest(true_label_, false_label_, fall_through_);
|
| - break;
|
| - }
|
| +
|
| +void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
|
| + MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register());
|
| + // Memory operands can be pushed directly.
|
| + __ push(slot_operand);
|
| }
|
|
|
|
|
| -void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - // Nothing to do.
|
| - break;
|
| - case Expression::kValue: {
|
| - MemOperand slot_operand = EmitSlotSearch(slot, result_register());
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ mov(result_register(), slot_operand);
|
| - break;
|
| - case kStack:
|
| - // Memory operands can be pushed directly.
|
| - __ push(slot_operand);
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| +void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
|
| + // For simplicity we always test the accumulator register.
|
| + codegen()->Move(result_register(), slot);
|
| + codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| +}
|
|
|
| - case Expression::kTest:
|
| - // For simplicity we always test the accumulator register.
|
| - Move(result_register(), slot);
|
| - DoTest(true_label_, false_label_, fall_through_);
|
| - break;
|
| - }
|
| +
|
| +void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
|
| + UNREACHABLE(); // Not used on IA32.
|
| }
|
|
|
|
|
| -void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - // Nothing to do.
|
| - break;
|
| - case Expression::kValue:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ mov(result_register(), lit->handle());
|
| - break;
|
| - case kStack:
|
| - // Immediates can be pushed directly.
|
| - __ push(Immediate(lit->handle()));
|
| - break;
|
| - }
|
| - break;
|
| +void FullCodeGenerator::AccumulatorValueContext::Plug(
|
| + Heap::RootListIndex index) const {
|
| + UNREACHABLE(); // Not used on IA32.
|
| +}
|
|
|
| - case Expression::kTest:
|
| - // For simplicity we always test the accumulator register.
|
| - __ mov(result_register(), lit->handle());
|
| - DoTest(true_label_, false_label_, fall_through_);
|
| - break;
|
| - }
|
| +
|
| +void FullCodeGenerator::StackValueContext::Plug(
|
| + Heap::RootListIndex index) const {
|
| + UNREACHABLE(); // Not used on IA32.
|
| }
|
|
|
|
|
| -void FullCodeGenerator::ApplyTOS(Expression::Context context) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| +void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
|
| + UNREACHABLE(); // Not used on IA32.
|
| +}
|
|
|
| - case Expression::kEffect:
|
| - __ Drop(1);
|
| - break;
|
|
|
| - case Expression::kValue:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ pop(result_register());
|
| - break;
|
| - case kStack:
|
| - break;
|
| - }
|
| - break;
|
| +void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
|
| + // Nothing to do.
|
| +}
|
|
|
| - case Expression::kTest:
|
| - // For simplicity we always test the accumulator register.
|
| - __ pop(result_register());
|
| - DoTest(true_label_, false_label_, fall_through_);
|
| - break;
|
| +
|
| +void FullCodeGenerator::AccumulatorValueContext::Plug(
|
| + Handle<Object> lit) const {
|
| + __ mov(result_register(), lit);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
|
| + // Immediates can be pushed directly.
|
| + __ push(Immediate(lit));
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
|
| + ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
|
| + if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
|
| + __ jmp(false_label_);
|
| + } else if (lit->IsTrue() || lit->IsJSObject()) {
|
| + __ jmp(true_label_);
|
| + } else if (lit->IsString()) {
|
| + if (String::cast(*lit)->length() == 0) {
|
| + __ jmp(false_label_);
|
| + } else {
|
| + __ jmp(true_label_);
|
| + }
|
| + } else if (lit->IsSmi()) {
|
| + if (Smi::cast(*lit)->value() == 0) {
|
| + __ jmp(false_label_);
|
| + } else {
|
| + __ jmp(true_label_);
|
| + }
|
| + } else {
|
| + // For simplicity we always test the accumulator register.
|
| + __ mov(result_register(), lit);
|
| + codegen()->DoTest(true_label_, false_label_, fall_through_);
|
| }
|
| }
|
|
|
|
|
| -void FullCodeGenerator::DropAndApply(int count,
|
| - Expression::Context context,
|
| - Register reg) {
|
| +void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
|
| + Register reg) const {
|
| ASSERT(count > 0);
|
| - ASSERT(!reg.is(esp));
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| + if (count > 1) __ Drop(count - 1);
|
| + __ mov(Operand(esp, 0), reg);
|
| +}
|
|
|
| - case Expression::kEffect:
|
| - __ Drop(count);
|
| - break;
|
|
|
| - case Expression::kValue:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ Drop(count);
|
| - if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| - break;
|
| - case kStack:
|
| - if (count > 1) __ Drop(count - 1);
|
| - __ mov(Operand(esp, 0), reg);
|
| - break;
|
| - }
|
| - break;
|
| +void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
|
| + Label* materialize_false) const {
|
| + ASSERT_EQ(materialize_true, materialize_false);
|
| + __ bind(materialize_true);
|
| +}
|
|
|
| - case Expression::kTest:
|
| - // For simplicity we always test the accumulator register.
|
| - __ Drop(count);
|
| - if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| - DoTest(true_label_, false_label_, fall_through_);
|
| - break;
|
| - }
|
| +
|
| +void FullCodeGenerator::AccumulatorValueContext::Plug(
|
| + Label* materialize_true,
|
| + Label* materialize_false) const {
|
| + Label done;
|
| + __ bind(materialize_true);
|
| + __ mov(result_register(), Factory::true_value());
|
| + __ jmp(&done);
|
| + __ bind(materialize_false);
|
| + __ mov(result_register(), Factory::false_value());
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| -void FullCodeGenerator::Apply(Expression::Context context,
|
| - Label* materialize_true,
|
| - Label* materialize_false) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| +void FullCodeGenerator::StackValueContext::Plug(
|
| + Label* materialize_true,
|
| + Label* materialize_false) const {
|
| + Label done;
|
| + __ bind(materialize_true);
|
| + __ push(Immediate(Factory::true_value()));
|
| + __ jmp(&done);
|
| + __ bind(materialize_false);
|
| + __ push(Immediate(Factory::false_value()));
|
| + __ bind(&done);
|
| +}
|
|
|
| - case Expression::kEffect:
|
| - ASSERT_EQ(materialize_true, materialize_false);
|
| - __ bind(materialize_true);
|
| - break;
|
|
|
| - case Expression::kValue: {
|
| - Label done;
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ bind(materialize_true);
|
| - __ mov(result_register(), Factory::true_value());
|
| - __ jmp(&done);
|
| - __ bind(materialize_false);
|
| - __ mov(result_register(), Factory::false_value());
|
| - break;
|
| - case kStack:
|
| - __ bind(materialize_true);
|
| - __ push(Immediate(Factory::true_value()));
|
| - __ jmp(&done);
|
| - __ bind(materialize_false);
|
| - __ push(Immediate(Factory::false_value()));
|
| - break;
|
| - }
|
| - __ bind(&done);
|
| - break;
|
| - }
|
| +void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
|
| + Label* materialize_false) const {
|
| +}
|
|
|
| - case Expression::kTest:
|
| - break;
|
| - }
|
| +
|
| +void FullCodeGenerator::EffectContext::Plug(bool flag) const {
|
| }
|
|
|
|
|
| -// Convert constant control flow (true or false) to the result expected for
|
| -// a given expression context.
|
| -void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - break;
|
| - case Expression::kEffect:
|
| - break;
|
| - case Expression::kValue: {
|
| - Handle<Object> value =
|
| - flag ? Factory::true_value() : Factory::false_value();
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ mov(result_register(), value);
|
| - break;
|
| - case kStack:
|
| - __ push(Immediate(value));
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case Expression::kTest:
|
| - if (flag) {
|
| - if (true_label_ != fall_through_) __ jmp(true_label_);
|
| - } else {
|
| - if (false_label_ != fall_through_) __ jmp(false_label_);
|
| - }
|
| - break;
|
| +void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
|
| + Handle<Object> value =
|
| + flag ? Factory::true_value() : Factory::false_value();
|
| + __ mov(result_register(), value);
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
|
| + Handle<Object> value =
|
| + flag ? Factory::true_value() : Factory::false_value();
|
| + __ push(Immediate(value));
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::TestContext::Plug(bool flag) const {
|
| + if (flag) {
|
| + if (true_label_ != fall_through_) __ jmp(true_label_);
|
| + } else {
|
| + if (false_label_ != fall_through_) __ jmp(false_label_);
|
| }
|
| }
|
|
|
| @@ -561,7 +500,7 @@
|
| __ mov(Operand(ebp, SlotOffset(slot)),
|
| Immediate(Factory::the_hole_value()));
|
| } else if (function != NULL) {
|
| - VisitForValue(function, kAccumulator);
|
| + VisitForAccumulatorValue(function);
|
| __ mov(Operand(ebp, SlotOffset(slot)), result_register());
|
| }
|
| break;
|
| @@ -583,7 +522,7 @@
|
| Immediate(Factory::the_hole_value()));
|
| // No write barrier since the hole value is in old space.
|
| } else if (function != NULL) {
|
| - VisitForValue(function, kAccumulator);
|
| + VisitForAccumulatorValue(function);
|
| __ mov(ContextOperand(esi, slot->index()), result_register());
|
| int offset = Context::SlotOffset(slot->index());
|
| __ mov(ebx, esi);
|
| @@ -605,7 +544,7 @@
|
| if (mode == Variable::CONST) {
|
| __ push(Immediate(Factory::the_hole_value()));
|
| } else if (function != NULL) {
|
| - VisitForValue(function, kStack);
|
| + VisitForStackValue(function);
|
| } else {
|
| __ push(Immediate(Smi::FromInt(0))); // No initial value!
|
| }
|
| @@ -618,13 +557,13 @@
|
| if (function != NULL || mode == Variable::CONST) {
|
| // We are declaring a function or constant that rewrites to a
|
| // property. Use (keyed) IC to set the initial value.
|
| - VisitForValue(prop->obj(), kStack);
|
| + VisitForStackValue(prop->obj());
|
| if (function != NULL) {
|
| - VisitForValue(prop->key(), kStack);
|
| - VisitForValue(function, kAccumulator);
|
| + VisitForStackValue(prop->key());
|
| + VisitForAccumulatorValue(function);
|
| __ pop(ecx);
|
| } else {
|
| - VisitForValue(prop->key(), kAccumulator);
|
| + VisitForAccumulatorValue(prop->key());
|
| __ mov(ecx, result_register());
|
| __ mov(result_register(), Factory::the_hole_value());
|
| }
|
| @@ -660,7 +599,7 @@
|
| Breakable nested_statement(this, stmt);
|
| SetStatementPosition(stmt);
|
| // Keep the switch value on the stack until a case matches.
|
| - VisitForValue(stmt->tag(), kStack);
|
| + VisitForStackValue(stmt->tag());
|
|
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| CaseClause* default_clause = NULL; // Can occur anywhere in the list.
|
| @@ -680,7 +619,7 @@
|
| next_test.Unuse();
|
|
|
| // Compile the label expression.
|
| - VisitForValue(clause->label(), kAccumulator);
|
| + VisitForAccumulatorValue(clause->label());
|
|
|
| // Perform the comparison as if via '==='.
|
| __ mov(edx, Operand(esp, 0)); // Switch value.
|
| @@ -738,7 +677,7 @@
|
| // Get the object to enumerate over. Both SpiderMonkey and JSC
|
| // ignore null and undefined in contrast to the specification; see
|
| // ECMA-262 section 12.6.4.
|
| - VisitForValue(stmt->enumerable(), kAccumulator);
|
| + VisitForAccumulatorValue(stmt->enumerable());
|
| __ cmp(eax, Factory::undefined_value());
|
| __ j(equal, &exit);
|
| __ cmp(eax, Factory::null_value());
|
| @@ -918,13 +857,13 @@
|
| __ push(Immediate(info));
|
| __ CallRuntime(Runtime::kNewClosure, 2);
|
| }
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
| Comment cmnt(masm_, "[ VariableProxy");
|
| - EmitVariableLoad(expr->var(), context_);
|
| + EmitVariableLoad(expr->var());
|
| }
|
|
|
|
|
| @@ -1073,8 +1012,7 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
| - Expression::Context context) {
|
| +void FullCodeGenerator::EmitVariableLoad(Variable* var) {
|
| // Four cases: non-this global variables, lookup slots, all other
|
| // types of slots, and parameters that rewrite to explicit property
|
| // accesses on the arguments object.
|
| @@ -1094,7 +1032,7 @@
|
| // Remember that the assembler may choose to do peephole optimization
|
| // (eg, push/pop elimination).
|
| __ nop();
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
|
|
| } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
| Label done, slow;
|
| @@ -1110,7 +1048,7 @@
|
| __ CallRuntime(Runtime::kLoadContextSlot, 2);
|
| __ bind(&done);
|
|
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
|
|
| } else if (slot != NULL) {
|
| Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
|
| @@ -1126,9 +1064,9 @@
|
| __ j(not_equal, &done);
|
| __ mov(eax, Factory::undefined_value());
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| } else {
|
| - Apply(context, slot);
|
| + context()->Plug(slot);
|
| }
|
|
|
| } else {
|
| @@ -1161,7 +1099,7 @@
|
| // call. It is treated specially by the LoadIC code.
|
| __ nop();
|
| // Drop key and object left on the stack by IC.
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -1216,7 +1154,7 @@
|
| __ mov(edx, FieldOperand(ebx, size - kPointerSize));
|
| __ mov(FieldOperand(eax, size - kPointerSize), edx);
|
| }
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -1253,7 +1191,7 @@
|
| // Fall through.
|
| case ObjectLiteral::Property::COMPUTED:
|
| if (key->handle()->IsSymbol()) {
|
| - VisitForValue(value, kAccumulator);
|
| + VisitForAccumulatorValue(value);
|
| __ mov(ecx, Immediate(key->handle()));
|
| __ mov(edx, Operand(esp, 0));
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| @@ -1264,18 +1202,18 @@
|
| // Fall through.
|
| case ObjectLiteral::Property::PROTOTYPE:
|
| __ push(Operand(esp, 0)); // Duplicate receiver.
|
| - VisitForValue(key, kStack);
|
| - VisitForValue(value, kStack);
|
| + VisitForStackValue(key);
|
| + VisitForStackValue(value);
|
| __ CallRuntime(Runtime::kSetProperty, 3);
|
| break;
|
| case ObjectLiteral::Property::SETTER:
|
| case ObjectLiteral::Property::GETTER:
|
| __ push(Operand(esp, 0)); // Duplicate receiver.
|
| - VisitForValue(key, kStack);
|
| + VisitForStackValue(key);
|
| __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
|
| Smi::FromInt(1) :
|
| Smi::FromInt(0)));
|
| - VisitForValue(value, kStack);
|
| + VisitForStackValue(value);
|
| __ CallRuntime(Runtime::kDefineAccessor, 4);
|
| break;
|
| default: UNREACHABLE();
|
| @@ -1283,9 +1221,9 @@
|
| }
|
|
|
| if (result_saved) {
|
| - ApplyTOS(context_);
|
| + context()->PlugTOS();
|
| } else {
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -1332,7 +1270,7 @@
|
| __ push(eax);
|
| result_saved = true;
|
| }
|
| - VisitForValue(subexpr, kAccumulator);
|
| + VisitForAccumulatorValue(subexpr);
|
|
|
| // Store the subexpression value in the array's elements.
|
| __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
|
| @@ -1345,9 +1283,9 @@
|
| }
|
|
|
| if (result_saved) {
|
| - ApplyTOS(context_);
|
| + context()->PlugTOS();
|
| } else {
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -1380,39 +1318,38 @@
|
| case NAMED_PROPERTY:
|
| if (expr->is_compound()) {
|
| // We need the receiver both on the stack and in the accumulator.
|
| - VisitForValue(property->obj(), kAccumulator);
|
| + VisitForAccumulatorValue(property->obj());
|
| __ push(result_register());
|
| } else {
|
| - VisitForValue(property->obj(), kStack);
|
| + VisitForStackValue(property->obj());
|
| }
|
| break;
|
| case KEYED_PROPERTY:
|
| if (expr->is_compound()) {
|
| - VisitForValue(property->obj(), kStack);
|
| - VisitForValue(property->key(), kAccumulator);
|
| + VisitForStackValue(property->obj());
|
| + VisitForAccumulatorValue(property->key());
|
| __ mov(edx, Operand(esp, 0));
|
| __ push(eax);
|
| } else {
|
| - VisitForValue(property->obj(), kStack);
|
| - VisitForValue(property->key(), kStack);
|
| + VisitForStackValue(property->obj());
|
| + VisitForStackValue(property->key());
|
| }
|
| break;
|
| }
|
|
|
| if (expr->is_compound()) {
|
| - Location saved_location = location_;
|
| - location_ = kAccumulator;
|
| - switch (assign_type) {
|
| - case VARIABLE:
|
| - EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
|
| - Expression::kValue);
|
| - break;
|
| - case NAMED_PROPERTY:
|
| - EmitNamedPropertyLoad(property);
|
| - break;
|
| - case KEYED_PROPERTY:
|
| - EmitKeyedPropertyLoad(property);
|
| - break;
|
| + { AccumulatorValueContext context(this);
|
| + switch (assign_type) {
|
| + case VARIABLE:
|
| + EmitVariableLoad(expr->target()->AsVariableProxy()->var());
|
| + break;
|
| + case NAMED_PROPERTY:
|
| + EmitNamedPropertyLoad(property);
|
| + break;
|
| + case KEYED_PROPERTY:
|
| + EmitKeyedPropertyLoad(property);
|
| + break;
|
| + }
|
| }
|
|
|
| Token::Value op = expr->binary_op();
|
| @@ -1422,28 +1359,26 @@
|
| ASSERT(constant == kRightConstant || constant == kNoConstants);
|
| if (constant == kNoConstants) {
|
| __ push(eax); // Left operand goes on the stack.
|
| - VisitForValue(expr->value(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->value());
|
| }
|
|
|
| OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
|
| ? OVERWRITE_RIGHT
|
| : NO_OVERWRITE;
|
| SetSourcePosition(expr->position() + 1);
|
| + AccumulatorValueContext context(this);
|
| if (ShouldInlineSmiCase(op)) {
|
| EmitInlineSmiBinaryOp(expr,
|
| op,
|
| - Expression::kValue,
|
| mode,
|
| expr->target(),
|
| expr->value(),
|
| constant);
|
| } else {
|
| - EmitBinaryOp(op, Expression::kValue, mode);
|
| + EmitBinaryOp(op, mode);
|
| }
|
| - location_ = saved_location;
|
| -
|
| } else {
|
| - VisitForValue(expr->value(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->value());
|
| }
|
|
|
| // Record source position before possible IC call.
|
| @@ -1453,8 +1388,7 @@
|
| switch (assign_type) {
|
| case VARIABLE:
|
| EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
|
| - expr->op(),
|
| - context_);
|
| + expr->op());
|
| break;
|
| case NAMED_PROPERTY:
|
| EmitNamedPropertyAssignment(expr);
|
| @@ -1485,7 +1419,6 @@
|
|
|
|
|
| void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| bool left_is_constant_smi,
|
| Smi* value) {
|
| @@ -1509,12 +1442,11 @@
|
| }
|
| __ CallStub(&stub);
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitConstantSmiSub(Expression* expr,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| bool left_is_constant_smi,
|
| Smi* value) {
|
| @@ -1546,13 +1478,12 @@
|
| GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
|
| __ CallStub(&stub);
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr,
|
| Token::Value op,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| Smi* value) {
|
| Label call_stub, smi_case, done;
|
| @@ -1609,13 +1540,12 @@
|
| }
|
|
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr,
|
| Token::Value op,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| Smi* value) {
|
| Label smi_case, done;
|
| @@ -1646,13 +1576,12 @@
|
| }
|
|
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr,
|
| Token::Value op,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| bool left_is_constant_smi,
|
| Smi* value) {
|
| @@ -1660,19 +1589,19 @@
|
| case Token::BIT_OR:
|
| case Token::BIT_XOR:
|
| case Token::BIT_AND:
|
| - EmitConstantSmiBitOp(expr, op, context, mode, value);
|
| + EmitConstantSmiBitOp(expr, op, mode, value);
|
| break;
|
| case Token::SHL:
|
| case Token::SAR:
|
| case Token::SHR:
|
| ASSERT(!left_is_constant_smi);
|
| - EmitConstantSmiShiftOp(expr, op, context, mode, value);
|
| + EmitConstantSmiShiftOp(expr, op, mode, value);
|
| break;
|
| case Token::ADD:
|
| - EmitConstantSmiAdd(expr, context, mode, left_is_constant_smi, value);
|
| + EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value);
|
| break;
|
| case Token::SUB:
|
| - EmitConstantSmiSub(expr, context, mode, left_is_constant_smi, value);
|
| + EmitConstantSmiSub(expr, mode, left_is_constant_smi, value);
|
| break;
|
| default:
|
| UNREACHABLE();
|
| @@ -1682,18 +1611,17 @@
|
|
|
| void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
|
| Token::Value op,
|
| - Expression::Context context,
|
| OverwriteMode mode,
|
| Expression* left,
|
| Expression* right,
|
| ConstantOperand constant) {
|
| if (constant == kRightConstant) {
|
| Smi* value = Smi::cast(*right->AsLiteral()->handle());
|
| - EmitConstantSmiBinaryOp(expr, op, context, mode, false, value);
|
| + EmitConstantSmiBinaryOp(expr, op, mode, false, value);
|
| return;
|
| } else if (constant == kLeftConstant) {
|
| Smi* value = Smi::cast(*left->AsLiteral()->handle());
|
| - EmitConstantSmiBinaryOp(expr, op, context, mode, true, value);
|
| + EmitConstantSmiBinaryOp(expr, op, mode, true, value);
|
| return;
|
| }
|
|
|
| @@ -1787,12 +1715,11 @@
|
| }
|
|
|
| __ bind(&done);
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitBinaryOp(Token::Value op,
|
| - Expression::Context context,
|
| OverwriteMode mode) {
|
| TypeInfo type = TypeInfo::Unknown();
|
| GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS, type);
|
| @@ -1803,7 +1730,7 @@
|
| __ push(result_register());
|
| __ CallStub(&stub);
|
| }
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -1829,12 +1756,13 @@
|
| switch (assign_type) {
|
| case VARIABLE: {
|
| Variable* var = expr->AsVariableProxy()->var();
|
| - EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
|
| + EffectContext context(this);
|
| + EmitVariableAssignment(var, Token::ASSIGN);
|
| break;
|
| }
|
| case NAMED_PROPERTY: {
|
| __ push(eax); // Preserve value.
|
| - VisitForValue(prop->obj(), kAccumulator);
|
| + VisitForAccumulatorValue(prop->obj());
|
| __ mov(edx, eax);
|
| __ pop(eax); // Restore value.
|
| __ mov(ecx, prop->key()->AsLiteral()->handle());
|
| @@ -1845,8 +1773,8 @@
|
| }
|
| case KEYED_PROPERTY: {
|
| __ push(eax); // Preserve value.
|
| - VisitForValue(prop->obj(), kStack);
|
| - VisitForValue(prop->key(), kAccumulator);
|
| + VisitForStackValue(prop->obj());
|
| + VisitForAccumulatorValue(prop->key());
|
| __ mov(ecx, eax);
|
| __ pop(edx);
|
| __ pop(eax); // Restore value.
|
| @@ -1860,8 +1788,7 @@
|
|
|
|
|
| void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
| - Token::Value op,
|
| - Expression::Context context) {
|
| + Token::Value op) {
|
| // Left-hand sides that rewrite to explicit property accesses do not reach
|
| // here.
|
| ASSERT(var != NULL);
|
| @@ -1931,7 +1858,7 @@
|
| __ bind(&done);
|
| }
|
|
|
| - Apply(context, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -1969,9 +1896,9 @@
|
| __ push(Operand(esp, kPointerSize)); // Receiver is under value.
|
| __ CallRuntime(Runtime::kToFastProperties, 1);
|
| __ pop(eax);
|
| - DropAndApply(1, context_, eax);
|
| + context()->DropAndPlug(1, eax);
|
| } else {
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -2013,7 +1940,7 @@
|
| __ pop(eax);
|
| }
|
|
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2022,15 +1949,15 @@
|
| Expression* key = expr->key();
|
|
|
| if (key->IsPropertyName()) {
|
| - VisitForValue(expr->obj(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->obj());
|
| EmitNamedPropertyLoad(expr);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| } else {
|
| - VisitForValue(expr->obj(), kStack);
|
| - VisitForValue(expr->key(), kAccumulator);
|
| + VisitForStackValue(expr->obj());
|
| + VisitForAccumulatorValue(expr->key());
|
| __ pop(edx);
|
| EmitKeyedPropertyLoad(expr);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| }
|
|
|
| @@ -2042,7 +1969,7 @@
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
| __ Set(ecx, Immediate(name));
|
| // Record source position of the IC call.
|
| @@ -2052,7 +1979,7 @@
|
| __ call(ic, mode);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2063,9 +1990,9 @@
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
| - VisitForValue(key, kAccumulator);
|
| + VisitForAccumulatorValue(key);
|
| __ mov(ecx, eax);
|
| // Record source position of the IC call.
|
| SetSourcePosition(expr->position());
|
| @@ -2075,7 +2002,7 @@
|
| __ call(ic, mode);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2084,7 +2011,7 @@
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
| // Record source position for debugger.
|
| SetSourcePosition(expr->position());
|
| @@ -2093,7 +2020,7 @@
|
| __ CallStub(&stub);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - DropAndApply(1, context_, eax);
|
| + context()->DropAndPlug(1, eax);
|
| }
|
|
|
|
|
| @@ -2107,14 +2034,14 @@
|
| // resolve the function we need to call and the receiver of the
|
| // call. Then we call the resolved function using the given
|
| // arguments.
|
| - VisitForValue(fun, kStack);
|
| + VisitForStackValue(fun);
|
| __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
|
|
|
| // Push the arguments.
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
|
|
| // Push copy of the function - found below the arguments.
|
| @@ -2143,7 +2070,7 @@
|
| __ CallStub(&stub);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - DropAndApply(1, context_, eax);
|
| + context()->DropAndPlug(1, eax);
|
| } else if (var != NULL && !var->is_this() && var->is_global()) {
|
| // Push global object as receiver for the call IC.
|
| __ push(CodeGenerator::GlobalObject());
|
| @@ -2191,15 +2118,15 @@
|
| Literal* key = prop->key()->AsLiteral();
|
| if (key != NULL && key->handle()->IsSymbol()) {
|
| // Call to a named property, use call IC.
|
| - VisitForValue(prop->obj(), kStack);
|
| + VisitForStackValue(prop->obj());
|
| EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
| } else {
|
| // Call to a keyed property.
|
| // For a synthetic property use keyed load IC followed by function call,
|
| // for a regular property use keyed CallIC.
|
| - VisitForValue(prop->obj(), kStack);
|
| + VisitForStackValue(prop->obj());
|
| if (prop->is_synthetic()) {
|
| - VisitForValue(prop->key(), kAccumulator);
|
| + VisitForAccumulatorValue(prop->key());
|
| // Record source code position for IC call.
|
| SetSourcePosition(prop->position());
|
| __ pop(edx); // We do not need to keep the receiver.
|
| @@ -2230,7 +2157,7 @@
|
| loop_depth() == 0) {
|
| lit->set_try_full_codegen(true);
|
| }
|
| - VisitForValue(fun, kStack);
|
| + VisitForStackValue(fun);
|
| // Load global receiver object.
|
| __ mov(ebx, CodeGenerator::GlobalObject());
|
| __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
| @@ -2249,13 +2176,13 @@
|
| // Push constructor on the stack. If it's not a function it's used as
|
| // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
|
| // ignored.
|
| - VisitForValue(expr->expression(), kStack);
|
| + VisitForStackValue(expr->expression());
|
|
|
| // Push the arguments ("left-to-right") on the stack.
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
|
|
| // Call the construct call builtin that handles allocation and
|
| @@ -2268,59 +2195,59 @@
|
|
|
| Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
|
| __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| Split(zero, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask | 0x80000000));
|
| Split(zero, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(zero, if_false);
|
| @@ -2337,42 +2264,42 @@
|
| __ cmp(ecx, LAST_JS_OBJECT_TYPE);
|
| Split(below_equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(equal, if_false);
|
| __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
|
| Split(above_equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(zero, if_false);
|
| @@ -2381,7 +2308,7 @@
|
| __ test(ebx, Immediate(1 << Map::kIsUndetectable));
|
| Split(not_zero, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| @@ -2389,83 +2316,83 @@
|
| ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
|
| // used in a few functions in runtime.js which should not normally be hit by
|
| // this compiler.
|
| __ jmp(if_false);
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(zero, if_false);
|
| __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(equal, if_false);
|
| __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(equal, if_false);
|
| __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| @@ -2477,8 +2404,8 @@
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| // Get the frame pointer for the calling frame.
|
| __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
| @@ -2496,7 +2423,7 @@
|
| Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| @@ -2504,21 +2431,21 @@
|
| ASSERT(args->length() == 2);
|
|
|
| // Load the two objects into registers and perform the comparison.
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kAccumulator);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForAccumulatorValue(args->at(1));
|
|
|
| Label materialize_true, materialize_false;
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ pop(ebx);
|
| __ cmp(eax, Operand(ebx));
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| @@ -2527,12 +2454,12 @@
|
|
|
| // ArgumentsAccessStub expects the key in edx and the formal
|
| // parameter count in eax.
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
| __ mov(edx, eax);
|
| __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
|
| ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2555,7 +2482,7 @@
|
|
|
| __ bind(&exit);
|
| if (FLAG_debug_code) __ AbortIfNotSmi(eax);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2563,7 +2490,7 @@
|
| ASSERT(args->length() == 1);
|
| Label done, null, function, non_function_constructor;
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| // If the object is a smi, we return null.
|
| __ test(eax, Immediate(kSmiTagMask));
|
| @@ -2610,7 +2537,7 @@
|
| // All done.
|
| __ bind(&done);
|
|
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2625,14 +2552,14 @@
|
| ASSERT_EQ(args->length(), 3);
|
| #ifdef ENABLE_LOGGING_AND_PROFILING
|
| if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
|
| - VisitForValue(args->at(1), kStack);
|
| - VisitForValue(args->at(2), kStack);
|
| + VisitForStackValue(args->at(1));
|
| + VisitForStackValue(args->at(2));
|
| __ CallRuntime(Runtime::kLog, 2);
|
| }
|
| #endif
|
| // Finally, we're expected to leave a value on the top of the stack.
|
| __ mov(eax, Factory::undefined_value());
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2680,7 +2607,7 @@
|
| __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
|
| }
|
| __ mov(eax, edi);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2688,11 +2615,11 @@
|
| // Load the arguments on the stack and call the stub.
|
| SubStringStub stub;
|
| ASSERT(args->length() == 3);
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| - VisitForValue(args->at(2), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
| + VisitForStackValue(args->at(2));
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2700,19 +2627,19 @@
|
| // Load the arguments on the stack and call the stub.
|
| RegExpExecStub stub;
|
| ASSERT(args->length() == 4);
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| - VisitForValue(args->at(2), kStack);
|
| - VisitForValue(args->at(3), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
| + VisitForStackValue(args->at(2));
|
| + VisitForStackValue(args->at(3));
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator); // Load the object.
|
| + VisitForAccumulatorValue(args->at(0)); // Load the object.
|
|
|
| Label done;
|
| // If the object is a smi return the object.
|
| @@ -2724,25 +2651,25 @@
|
| __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
|
|
|
| __ bind(&done);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
|
| // Load the arguments on the stack and call the runtime function.
|
| ASSERT(args->length() == 2);
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
| __ CallRuntime(Runtime::kMath_pow, 2);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 2);
|
|
|
| - VisitForValue(args->at(0), kStack); // Load the object.
|
| - VisitForValue(args->at(1), kAccumulator); // Load the value.
|
| + VisitForStackValue(args->at(0)); // Load the object.
|
| + VisitForAccumulatorValue(args->at(1)); // Load the value.
|
| __ pop(ebx); // eax = value. ebx = object.
|
|
|
| Label done;
|
| @@ -2762,7 +2689,7 @@
|
| __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
|
|
|
| __ bind(&done);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2770,18 +2697,18 @@
|
| ASSERT_EQ(args->length(), 1);
|
|
|
| // Load the argument on the stack and call the stub.
|
| - VisitForValue(args->at(0), kStack);
|
| + VisitForStackValue(args->at(0));
|
|
|
| NumberToStringStub stub;
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| Label done;
|
| StringCharFromCodeGenerator generator(eax, ebx);
|
| @@ -2792,15 +2719,15 @@
|
| generator.GenerateSlow(masm_, call_helper);
|
|
|
| __ bind(&done);
|
| - Apply(context_, ebx);
|
| + context()->Plug(ebx);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 2);
|
|
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kAccumulator);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForAccumulatorValue(args->at(1));
|
|
|
| Register object = ebx;
|
| Register index = eax;
|
| @@ -2839,15 +2766,15 @@
|
| generator.GenerateSlow(masm_, call_helper);
|
|
|
| __ bind(&done);
|
| - Apply(context_, result);
|
| + context()->Plug(result);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 2);
|
|
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kAccumulator);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForAccumulatorValue(args->at(1));
|
|
|
| Register object = ebx;
|
| Register index = eax;
|
| @@ -2888,31 +2815,31 @@
|
| generator.GenerateSlow(masm_, call_helper);
|
|
|
| __ bind(&done);
|
| - Apply(context_, result);
|
| + context()->Plug(result);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
|
| ASSERT_EQ(2, args->length());
|
|
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
|
|
| StringAddStub stub(NO_STRING_ADD_FLAGS);
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
|
| ASSERT_EQ(2, args->length());
|
|
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
|
|
| StringCompareStub stub;
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2920,9 +2847,9 @@
|
| // Load the argument on the stack and call the stub.
|
| TranscendentalCacheStub stub(TranscendentalCache::SIN);
|
| ASSERT(args->length() == 1);
|
| - VisitForValue(args->at(0), kStack);
|
| + VisitForStackValue(args->at(0));
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2930,18 +2857,18 @@
|
| // Load the argument on the stack and call the stub.
|
| TranscendentalCacheStub stub(TranscendentalCache::COS);
|
| ASSERT(args->length() == 1);
|
| - VisitForValue(args->at(0), kStack);
|
| + VisitForStackValue(args->at(0));
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
|
| // Load the argument on the stack and call the runtime function.
|
| ASSERT(args->length() == 1);
|
| - VisitForValue(args->at(0), kStack);
|
| + VisitForStackValue(args->at(0));
|
| __ CallRuntime(Runtime::kMath_sqrt, 1);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2949,38 +2876,38 @@
|
| ASSERT(args->length() >= 2);
|
|
|
| int arg_count = args->length() - 2; // For receiver and function.
|
| - VisitForValue(args->at(0), kStack); // Receiver.
|
| + VisitForStackValue(args->at(0)); // Receiver.
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i + 1), kStack);
|
| + VisitForStackValue(args->at(i + 1));
|
| }
|
| - VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
|
| + VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
|
|
|
| // InvokeFunction requires function in edi. Move it in there.
|
| if (!result_register().is(edi)) __ mov(edi, result_register());
|
| ParameterCount count(arg_count);
|
| __ InvokeFunction(edi, count, CALL_FUNCTION);
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 3);
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| - VisitForValue(args->at(2), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
| + VisitForStackValue(args->at(2));
|
| __ CallRuntime(Runtime::kRegExpConstructResult, 3);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 3);
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kStack);
|
| - VisitForValue(args->at(2), kStack);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForStackValue(args->at(1));
|
| + VisitForStackValue(args->at(2));
|
| __ CallRuntime(Runtime::kSwapElements, 3);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -2995,11 +2922,11 @@
|
| if (jsfunction_result_caches->length() <= cache_id) {
|
| __ Abort("Attempt to use undefined cache.");
|
| __ mov(eax, Factory::undefined_value());
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| return;
|
| }
|
|
|
| - VisitForValue(args->at(1), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(1));
|
|
|
| Register key = eax;
|
| Register cache = ebx;
|
| @@ -3028,7 +2955,7 @@
|
| __ CallRuntime(Runtime::kGetFromCache, 2);
|
|
|
| __ bind(&done);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -3039,8 +2966,8 @@
|
| Register left = ebx;
|
| Register tmp = ecx;
|
|
|
| - VisitForValue(args->at(0), kStack);
|
| - VisitForValue(args->at(1), kAccumulator);
|
| + VisitForStackValue(args->at(0));
|
| + VisitForAccumulatorValue(args->at(1));
|
| __ pop(left);
|
|
|
| Label done, fail, ok;
|
| @@ -3065,14 +2992,14 @@
|
| __ mov(eax, Immediate(Factory::true_value()));
|
| __ bind(&done);
|
|
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| if (FLAG_debug_code) {
|
| __ AbortIfNotString(eax);
|
| @@ -3082,21 +3009,21 @@
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| __ test(FieldOperand(eax, String::kHashFieldOffset),
|
| Immediate(String::kContainsCachedArrayIndexMask));
|
| Split(zero, if_true, if_false, fall_through);
|
|
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
|
| ASSERT(args->length() == 1);
|
|
|
| - VisitForValue(args->at(0), kAccumulator);
|
| + VisitForAccumulatorValue(args->at(0));
|
|
|
| if (FLAG_debug_code) {
|
| __ AbortIfNotString(eax);
|
| @@ -3105,7 +3032,7 @@
|
| __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
|
| __ IndexFromHash(eax, eax);
|
|
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -3129,7 +3056,7 @@
|
| // Push the arguments ("left-to-right").
|
| int arg_count = args->length();
|
| for (int i = 0; i < arg_count; i++) {
|
| - VisitForValue(args->at(i), kStack);
|
| + VisitForStackValue(args->at(i));
|
| }
|
|
|
| if (expr->is_jsruntime()) {
|
| @@ -3144,7 +3071,7 @@
|
| // Call the C runtime function.
|
| __ CallRuntime(expr->function(), arg_count);
|
| }
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
| @@ -3158,20 +3085,20 @@
|
| // Result of deleting non-property, non-variable reference is true.
|
| // The subexpression may have side effects.
|
| VisitForEffect(expr->expression());
|
| - Apply(context_, true);
|
| + context()->Plug(true);
|
| } else if (var != NULL &&
|
| !var->is_global() &&
|
| var->slot() != NULL &&
|
| var->slot()->type() != Slot::LOOKUP) {
|
| // Result of deleting non-global, non-dynamic variables is false.
|
| // The subexpression does not have side effects.
|
| - Apply(context_, false);
|
| + context()->Plug(false);
|
| } else {
|
| // Property or variable reference. Call the delete builtin with
|
| // object and property name as arguments.
|
| if (prop != NULL) {
|
| - VisitForValue(prop->obj(), kStack);
|
| - VisitForValue(prop->key(), kStack);
|
| + VisitForStackValue(prop->obj());
|
| + VisitForStackValue(prop->key());
|
| } else if (var->is_global()) {
|
| __ push(CodeGenerator::GlobalObject());
|
| __ push(Immediate(var->name()));
|
| @@ -3185,7 +3112,7 @@
|
| __ push(Immediate(var->name()));
|
| }
|
| __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| break;
|
| }
|
| @@ -3193,26 +3120,7 @@
|
| case Token::VOID: {
|
| Comment cmnt(masm_, "[ UnaryOperation (VOID)");
|
| VisitForEffect(expr->expression());
|
| - switch (context_) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - break;
|
| - case Expression::kEffect:
|
| - break;
|
| - case Expression::kValue:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ mov(result_register(), Factory::undefined_value());
|
| - break;
|
| - case kStack:
|
| - __ push(Immediate(Factory::undefined_value()));
|
| - break;
|
| - }
|
| - break;
|
| - case Expression::kTest:
|
| - __ jmp(false_label_);
|
| - break;
|
| - }
|
| + context()->Plug(Factory::undefined_value());
|
| break;
|
| }
|
|
|
| @@ -3224,31 +3132,33 @@
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| // Notice that the labels are swapped.
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_false, &if_true, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_false, &if_true, &fall_through);
|
| VisitForControl(expr->expression(), if_true, if_false, fall_through);
|
| - Apply(context_, if_false, if_true); // Labels swapped.
|
| + context()->Plug(if_false, if_true); // Labels swapped.
|
| break;
|
| }
|
|
|
| case Token::TYPEOF: {
|
| Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
|
| - VisitForTypeofValue(expr->expression(), kStack);
|
| + { StackValueContext context(this);
|
| + VisitForTypeofValue(expr->expression());
|
| + }
|
| __ CallRuntime(Runtime::kTypeof, 1);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| break;
|
| }
|
|
|
| case Token::ADD: {
|
| Comment cmt(masm_, "[ UnaryOperation (ADD)");
|
| - VisitForValue(expr->expression(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->expression());
|
| Label no_conversion;
|
| __ test(result_register(), Immediate(kSmiTagMask));
|
| __ j(zero, &no_conversion);
|
| __ push(result_register());
|
| __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
|
| __ bind(&no_conversion);
|
| - Apply(context_, result_register());
|
| + context()->Plug(result_register());
|
| break;
|
| }
|
|
|
| @@ -3260,9 +3170,9 @@
|
| GenericUnaryOpStub stub(Token::SUB, overwrite);
|
| // GenericUnaryOpStub expects the argument to be in the
|
| // accumulator register eax.
|
| - VisitForValue(expr->expression(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->expression());
|
| __ CallStub(&stub);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| break;
|
| }
|
|
|
| @@ -3270,7 +3180,7 @@
|
| Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
|
| // The generic unary operation stub expects the argument to be
|
| // in the accumulator register eax.
|
| - VisitForValue(expr->expression(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->expression());
|
| Label done;
|
| if (ShouldInlineSmiCase(expr->op())) {
|
| Label call_stub;
|
| @@ -3287,7 +3197,7 @@
|
| GenericUnaryOpStub stub(Token::BIT_NOT, mode);
|
| __ CallStub(&stub);
|
| __ bind(&done);
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| break;
|
| }
|
|
|
| @@ -3323,24 +3233,21 @@
|
| // Evaluate expression and get value.
|
| if (assign_type == VARIABLE) {
|
| ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
|
| - Location saved_location = location_;
|
| - location_ = kAccumulator;
|
| - EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
|
| - Expression::kValue);
|
| - location_ = saved_location;
|
| + AccumulatorValueContext context(this);
|
| + EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
|
| } else {
|
| // Reserve space for result of postfix operation.
|
| - if (expr->is_postfix() && context_ != Expression::kEffect) {
|
| + if (expr->is_postfix() && !context()->IsEffect()) {
|
| __ push(Immediate(Smi::FromInt(0)));
|
| }
|
| if (assign_type == NAMED_PROPERTY) {
|
| // Put the object both on the stack and in the accumulator.
|
| - VisitForValue(prop->obj(), kAccumulator);
|
| + VisitForAccumulatorValue(prop->obj());
|
| __ push(eax);
|
| EmitNamedPropertyLoad(prop);
|
| } else {
|
| - VisitForValue(prop->obj(), kStack);
|
| - VisitForValue(prop->key(), kAccumulator);
|
| + VisitForStackValue(prop->obj());
|
| + VisitForAccumulatorValue(prop->key());
|
| __ mov(edx, Operand(esp, 0));
|
| __ push(eax);
|
| EmitKeyedPropertyLoad(prop);
|
| @@ -3359,29 +3266,21 @@
|
|
|
| // Save result for postfix expressions.
|
| if (expr->is_postfix()) {
|
| - switch (context_) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - // Do not save result.
|
| - break;
|
| - case Expression::kValue:
|
| - case Expression::kTest:
|
| - // 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;
|
| + if (!context()->IsEffect()) {
|
| + // 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;
|
| + }
|
| }
|
| }
|
|
|
| @@ -3419,19 +3318,20 @@
|
| case VARIABLE:
|
| if (expr->is_postfix()) {
|
| // Perform the assignment as if via '='.
|
| - EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| - Token::ASSIGN,
|
| - Expression::kEffect);
|
| - // For all contexts except kEffect: We have the result on
|
| + {
|
| + EffectContext context(this);
|
| + EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| + Token::ASSIGN);
|
| + }
|
| + // For all contexts except EffectContext We have the result on
|
| // top of the stack.
|
| - if (context_ != Expression::kEffect) {
|
| - ApplyTOS(context_);
|
| + if (!context()->IsEffect()) {
|
| + context()->PlugTOS();
|
| }
|
| } else {
|
| // Perform the assignment as if via '='.
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| - Token::ASSIGN,
|
| - context_);
|
| + Token::ASSIGN);
|
| }
|
| break;
|
| case NAMED_PROPERTY: {
|
| @@ -3443,11 +3343,11 @@
|
| // site for it to patch.
|
| __ nop();
|
| if (expr->is_postfix()) {
|
| - if (context_ != Expression::kEffect) {
|
| - ApplyTOS(context_);
|
| + if (!context()->IsEffect()) {
|
| + context()->PlugTOS();
|
| }
|
| } else {
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| break;
|
| }
|
| @@ -3461,11 +3361,11 @@
|
| __ nop();
|
| if (expr->is_postfix()) {
|
| // Result is on the stack
|
| - if (context_ != Expression::kEffect) {
|
| - ApplyTOS(context_);
|
| + if (!context()->IsEffect()) {
|
| + context()->PlugTOS();
|
| }
|
| } else {
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
| break;
|
| }
|
| @@ -3473,8 +3373,11 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
|
| +void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
|
| VariableProxy* proxy = expr->AsVariableProxy();
|
| + ASSERT(!context()->IsEffect());
|
| + ASSERT(!context()->IsTest());
|
| +
|
| if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
|
| Comment cmnt(masm_, "Global variable");
|
| __ mov(eax, CodeGenerator::GlobalObject());
|
| @@ -3483,7 +3386,7 @@
|
| // Use a regular load, not a contextual load, to avoid a reference
|
| // error.
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| - if (where == kStack) __ push(eax);
|
| + context()->Plug(eax);
|
| } else if (proxy != NULL &&
|
| proxy->var()->slot() != NULL &&
|
| proxy->var()->slot()->type() == Slot::LOOKUP) {
|
| @@ -3500,10 +3403,10 @@
|
| __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
| __ bind(&done);
|
|
|
| - if (where == kStack) __ push(eax);
|
| + context()->Plug(eax);
|
| } else {
|
| // This expression cannot throw a reference error at the top level.
|
| - VisitForValue(expr, where);
|
| + Visit(expr);
|
| }
|
| }
|
|
|
| @@ -3525,7 +3428,10 @@
|
| if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
|
| Handle<String> check = Handle<String>::cast(right_literal_value);
|
|
|
| - VisitForTypeofValue(left_unary->expression(), kAccumulator);
|
| + { AccumulatorValueContext context(this);
|
| + VisitForTypeofValue(left_unary->expression());
|
| + }
|
| +
|
| if (check->Equals(Heap::number_symbol())) {
|
| __ test(eax, Immediate(kSmiTagMask));
|
| __ j(zero, if_true);
|
| @@ -3602,8 +3508,8 @@
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| // First we try a fast inlined version of the compare when one of
|
| // the operands is a literal.
|
| @@ -3611,21 +3517,21 @@
|
| Expression* left = expr->left();
|
| Expression* right = expr->right();
|
| if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| return;
|
| }
|
|
|
| - VisitForValue(expr->left(), kStack);
|
| + VisitForStackValue(expr->left());
|
| switch (expr->op()) {
|
| case Token::IN:
|
| - VisitForValue(expr->right(), kStack);
|
| + VisitForStackValue(expr->right());
|
| __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
|
| __ cmp(eax, Factory::true_value());
|
| Split(equal, if_true, if_false, fall_through);
|
| break;
|
|
|
| case Token::INSTANCEOF: {
|
| - VisitForValue(expr->right(), kStack);
|
| + VisitForStackValue(expr->right());
|
| InstanceofStub stub;
|
| __ CallStub(&stub);
|
| __ test(eax, Operand(eax));
|
| @@ -3635,7 +3541,7 @@
|
| }
|
|
|
| default: {
|
| - VisitForValue(expr->right(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->right());
|
| Condition cc = no_condition;
|
| bool strict = false;
|
| switch (op) {
|
| @@ -3692,7 +3598,7 @@
|
|
|
| // Convert the result of the comparison into one expected for this
|
| // expression's context.
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| @@ -3701,10 +3607,10 @@
|
| Label* if_true = NULL;
|
| Label* if_false = NULL;
|
| Label* fall_through = NULL;
|
| - PrepareTest(&materialize_true, &materialize_false,
|
| - &if_true, &if_false, &fall_through);
|
| + context()->PrepareTest(&materialize_true, &materialize_false,
|
| + &if_true, &if_false, &fall_through);
|
|
|
| - VisitForValue(expr->expression(), kAccumulator);
|
| + VisitForAccumulatorValue(expr->expression());
|
| __ cmp(eax, Factory::null_value());
|
| if (expr->is_strict()) {
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -3720,13 +3626,13 @@
|
| __ test(edx, Immediate(1 << Map::kIsUndetectable));
|
| Split(not_zero, if_true, if_false, fall_through);
|
| }
|
| - Apply(context_, if_true, if_false);
|
| + context()->Plug(if_true, if_false);
|
| }
|
|
|
|
|
| void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
|
| __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| - Apply(context_, eax);
|
| + context()->Plug(eax);
|
| }
|
|
|
|
|
|
|