}
-void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+}
- 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 {
+ codegen()->Move(result_register(), slot);
+}
- 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 {
+ codegen()->Move(result_register(), slot);
+ __ push(result_register());
}
-void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- // Nothing to do.
- break;
- case Expression::kValue:
- case Expression::kTest:
- // On ARM we have to move the value into a register to do anything
- // with it.
- Move(result_register(), slot);
- Apply(context, result_register());
- 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_);
}
-void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- // Nothing to do.
- case Expression::kValue:
- case Expression::kTest:
- // On ARM we have to move the value into a register to do anything
- // with it.
- __ mov(result_register(), Operand(lit->handle()));
- Apply(context, result_register());
- break;
+void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Heap::RootListIndex index) const {
+ __ LoadRoot(result_register(), index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+ Heap::RootListIndex index) const {
+ __ LoadRoot(result_register(), index);
+ __ push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
+ if (index == Heap::kUndefinedValueRootIndex ||
+ index == Heap::kNullValueRootIndex ||
+ index == Heap::kFalseValueRootIndex) {
+ __ b(false_label_);
+ } else if (index == Heap::kTrueValueRootIndex) {
+ __ b(true_label_);
+ } else {
+ __ LoadRoot(result_register(), index);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
}
}
-void FullCodeGenerator::ApplyTOS(Expression::Context context) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
+}
- case Expression::kEffect:
- __ Drop(1);
- break;
- case Expression::kValue:
- switch (location_) {
- case kAccumulator:
- __ pop(result_register());
- break;
- case kStack:
- break;
- }
- break;
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Handle<Object> lit) const {
+ __ mov(result_register(), Operand(lit));
+}
- case Expression::kTest:
- __ pop(result_register());
- DoTest(true_label_, false_label_, fall_through_);
- break;
+
+void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
+ // Immediates can be pushed directly.
+ __ mov(result_register(), Operand(lit));
+ __ push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
+ ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
+ if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
+ __ b(false_label_);
+ } else if (lit->IsTrue() || lit->IsJSObject()) {
+ __ b(true_label_);
+ } else if (lit->IsString()) {
+ if (String::cast(*lit)->length() == 0) {
+ __ b(false_label_);
+ } else {
+ __ b(true_label_);
+ }
+ } else if (lit->IsSmi()) {
+ if (Smi::cast(*lit)->value() == 0) {
+ __ b(false_label_);
+ } else {
+ __ b(true_label_);
+ }
+ } else {
+ // For simplicity we always test the accumulator register.
+ __ mov(result_register(), Operand(lit));
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
}
}
-void FullCodeGenerator::DropAndApply(int count,
- Expression::Context context,
- Register reg) {
+void FullCodeGenerator::EffectContext::DropAndPlug(int count,
+ Register reg) const {
ASSERT(count > 0);
- ASSERT(!reg.is(sp));
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+ __ Drop(count);
+}
- 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);
- __ str(reg, MemOperand(sp));
- break;
- }
- break;
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
+ int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ __ Drop(count);
+ __ Move(result_register(), reg);
+}
- case Expression::kTest:
- __ Drop(count);
- if (!reg.is(result_register())) __ mov(result_register(), reg);
- DoTest(true_label_, false_label_, fall_through_);
- break;
- }
+
+void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ if (count > 1) __ Drop(count - 1);
+ __ str(reg, MemOperand(sp, 0));
}
-void FullCodeGenerator::Apply(Expression::Context context,
- Label* materialize_true,
- Label* materialize_false) {
- switch (context) {
- case Expression::kUninitialized:
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ // For simplicity we always test the accumulator register.
+ __ Drop(count);
+ __ Move(result_register(), reg);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
- 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);
- __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
- __ jmp(&done);
- __ bind(materialize_false);
- __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
- break;
- case kStack:
- __ bind(materialize_true);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ push(ip);
- __ jmp(&done);
- __ bind(materialize_false);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ push(ip);
- break;
- }
- __ bind(&done);
- break;
- }
+void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT_EQ(materialize_true, materialize_false);
+ __ bind(materialize_true);
+}
- case Expression::kTest:
- break;
- }
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ Label done;
+ __ bind(materialize_true);
+ __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
+ __ bind(&done);
}
-// 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: {
- Heap::RootListIndex value_root_index =
- flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
- switch (location_) {
- case kAccumulator:
- __ LoadRoot(result_register(), value_root_index);
- break;
- case kStack:
- __ LoadRoot(ip, value_root_index);
- __ push(ip);
- break;
- }
- break;
- }
- case Expression::kTest:
- if (flag) {
- if (true_label_ != fall_through_) __ b(true_label_);
- } else {
- if (false_label_ != fall_through_) __ b(false_label_);
- }
- break;
+void FullCodeGenerator::StackValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ Label done;
+ __ bind(materialize_true);
+ __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+ __ push(ip);
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+ __ push(ip);
+ __ bind(&done);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT(materialize_false == false_label_);
+ ASSERT(materialize_true == true_label_);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
+ Heap::RootListIndex value_root_index =
+ flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+ __ LoadRoot(result_register(), value_root_index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
+ Heap::RootListIndex value_root_index =
+ flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+ __ LoadRoot(ip, value_root_index);
+ __ push(ip);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(bool flag) const {
+ if (flag) {
+ if (true_label_ != fall_through_) __ b(true_label_);
+ } else {
+ if (false_label_ != fall_through_) __ b(false_label_);
}
}
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ str(ip, MemOperand(fp, SlotOffset(slot)));
} else if (function != NULL) {
- VisitForValue(function, kAccumulator);
+ VisitForAccumulatorValue(function);
__ str(result_register(), MemOperand(fp, SlotOffset(slot)));
}
break;
__ str(ip, ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space.
} else if (function != NULL) {
- VisitForValue(function, kAccumulator);
+ VisitForAccumulatorValue(function);
__ str(result_register(), ContextOperand(cp, slot->index()));
int offset = Context::SlotOffset(slot->index());
// We know that we have written a function, which is not a smi.
} else if (function != NULL) {
__ Push(cp, r2, r1);
// Push initial value for function declaration.
- VisitForValue(function, kStack);
+ VisitForStackValue(function);
} else {
__ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
__ Push(cp, r2, r1, r0);
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(r1); // Key.
} else {
- VisitForValue(prop->key(), kAccumulator);
+ VisitForAccumulatorValue(prop->key());
__ mov(r1, result_register()); // Key.
__ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
}
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.
next_test.Unuse();
// Compile the label expression.
- VisitForValue(clause->label(), kAccumulator);
+ VisitForAccumulatorValue(clause->label());
// Perform the comparison as if via '==='.
__ ldr(r1, MemOperand(sp, 0)); // Switch value.
// 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());
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r0, ip);
__ b(eq, &exit);
__ Push(cp, r0);
__ CallRuntime(Runtime::kNewClosure, 2);
}
- Apply(context_, r0);
+ context()->Plug(r0);
}
void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
- EmitVariableLoad(expr->var(), context_);
+ EmitVariableLoad(expr->var());
}
}
-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.
__ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
- Apply(context, r0);
+ context()->Plug(r0);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Label done, slow;
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
- Apply(context, r0);
+ context()->Plug(r0);
} else if (slot != NULL) {
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
? "Context slot"
: "Stack slot");
if (var->mode() == Variable::CONST) {
- // Constants may be the hole value if they have not been initialized.
- // Unhole them.
- MemOperand slot_operand = EmitSlotSearch(slot, r0);
- __ ldr(r0, slot_operand);
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(r0, ip);
- __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
- Apply(context, r0);
- } else {
- Apply(context, slot);
- }
+ // Constants may be the hole value if they have not been initialized.
+ // Unhole them.
+ MemOperand slot_operand = EmitSlotSearch(slot, r0);
+ __ ldr(r0, slot_operand);
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+ __ cmp(r0, ip);
+ __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+ context()->Plug(r0);
+ } else {
+ context()->Plug(slot);
+ }
} else {
Comment cmnt(masm_, "Rewritten parameter");
ASSERT_NOT_NULL(property);
// Call keyed load IC. It has arguments key and receiver in r0 and r1.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
- Apply(context, r0);
+ context()->Plug(r0);
}
}
// r2: temp.
__ pop(r1);
__ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
- Apply(context_, r0);
+ context()->Plug(r0);
}
// Fall through.
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
- VisitForValue(value, kAccumulator);
+ VisitForAccumulatorValue(value);
__ mov(r2, Operand(key->handle()));
__ ldr(r1, MemOperand(sp));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
// Duplicate receiver on stack.
__ ldr(r0, MemOperand(sp));
__ push(r0);
- VisitForValue(key, kStack);
- VisitForValue(value, kStack);
+ VisitForStackValue(key);
+ VisitForStackValue(value);
__ CallRuntime(Runtime::kSetProperty, 3);
break;
case ObjectLiteral::Property::GETTER:
// Duplicate receiver on stack.
__ ldr(r0, MemOperand(sp));
__ push(r0);
- VisitForValue(key, kStack);
+ VisitForStackValue(key);
__ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0)));
__ push(r1);
- VisitForValue(value, kStack);
+ VisitForStackValue(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
break;
}
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
}
__ push(r0);
result_saved = true;
}
- VisitForValue(subexpr, kAccumulator);
+ VisitForAccumulatorValue(subexpr);
// Store the subexpression value in the array's elements.
__ ldr(r1, MemOperand(sp)); // Copy of array literal.
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
}
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());
__ ldr(r1, MemOperand(sp, 0));
__ push(r0);
} 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();
ASSERT(constant == kRightConstant || constant == kNoConstants);
if (constant == kNoConstants) {
__ push(r0); // 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.
switch (assign_type) {
case VARIABLE:
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
- expr->op(),
- context_);
+ expr->op());
break;
case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr);
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
ConstantOperand constant) {
ASSERT(constant == kNoConstants); // Only handled case.
- EmitBinaryOp(op, context, mode);
+ EmitBinaryOp(op, mode);
}
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
- Expression::Context context,
OverwriteMode mode) {
__ pop(r1);
GenericBinaryOpStub stub(op, mode, r1, r0);
__ CallStub(&stub);
- Apply(context, r0);
+ context()->Plug(r0);
}
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(r0); // Preserve value.
- VisitForValue(prop->obj(), kAccumulator);
+ VisitForAccumulatorValue(prop->obj());
__ mov(r1, r0);
__ pop(r0); // Restore value.
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
}
case KEYED_PROPERTY: {
__ push(r0); // Preserve value.
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kAccumulator);
+ VisitForStackValue(prop->obj());
+ VisitForAccumulatorValue(prop->key());
__ mov(r1, r0);
__ pop(r2);
__ pop(r0); // Restore value.
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);
__ bind(&done);
}
- Apply(context, result_register());
+ context()->Plug(result_register());
}
__ push(ip);
__ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(r0);
- DropAndApply(1, context_, r0);
+ context()->DropAndPlug(1, r0);
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
}
__ push(ip);
__ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(r0);
- DropAndApply(1, context_, r0);
+ context()->DropAndPlug(1, r0);
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
}
Expression* key = expr->key();
if (key->IsPropertyName()) {
- VisitForValue(expr->obj(), kAccumulator);
+ VisitForAccumulatorValue(expr->obj());
EmitNamedPropertyLoad(expr);
- Apply(context_, r0);
} else {
- VisitForValue(expr->obj(), kStack);
- VisitForValue(expr->key(), kAccumulator);
+ VisitForStackValue(expr->obj());
+ VisitForAccumulatorValue(expr->key());
__ pop(r1);
EmitKeyedPropertyLoad(expr);
- Apply(context_, r0);
}
+ context()->Plug(r0);
}
void FullCodeGenerator::EmitCallWithIC(Call* expr,
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));
}
__ mov(r2, Operand(name));
// Record source position for debugger.
EmitCallIC(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- Apply(context_, r0);
+ context()->Plug(r0);
}
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(r2, r0);
// Record source position for debugger.
SetSourcePosition(expr->position());
EmitCallIC(ic, mode);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- Apply(context_, r0);
+ context()->Plug(r0);
}
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());
__ CallStub(&stub);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- DropAndApply(1, context_, r0);
+ context()->DropAndPlug(1, r0);
}
// 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);
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ push(r2); // Reserved receiver slot.
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.
__ CallStub(&stub);
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- DropAndApply(1, context_, r0);
+ context()->DropAndPlug(1, r0);
} else if (var != NULL && !var->is_this() && var->is_global()) {
// Push global object as receiver for the call IC.
__ ldr(r0, CodeGenerator::GlobalObject());
&done);
__ bind(&slow);
- // Call the runtime to find the function to call (returned in eax)
+ // Call the runtime to find the function to call (returned in r0)
// and the object holding it (returned in edx).
__ push(context_register());
__ mov(r2, Operand(var->name()));
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(r1); // We do not need to keep the receiver.
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
- VisitForValue(fun, kStack);
+ VisitForStackValue(fun);
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
// 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
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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);
__ BranchOnSmi(r0, if_true);
__ b(if_false);
- 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);
__ tst(r0, Operand(kSmiTagMask | 0x80000000));
Split(eq, 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);
__ BranchOnSmi(r0, if_false);
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
Split(le, 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);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
Split(ge, 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);
__ BranchOnSmi(r0, if_false);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(ne, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
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);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
Split(eq, 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);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
Split(eq, 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);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
Split(eq, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_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);
// Get the frame pointer for the calling frame.
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
Split(eq, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
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(r1);
__ cmp(r0, r1);
Split(eq, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
ASSERT(args->length() == 1);
// ArgumentsAccessStub expects the key in edx and the formal
- // parameter count in eax.
- VisitForValue(args->at(0), kAccumulator);
+ // parameter count in r0.
+ VisitForAccumulatorValue(args->at(0));
__ mov(r1, r0);
__ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub);
- Apply(context_, r0);
+ context()->Plug(r0);
}
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
__ bind(&exit);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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.
__ BranchOnSmi(r0, &null);
// All done.
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
- Apply(context_, r0);
+ context()->Plug(r0);
}
ExternalReference::fill_heap_number_with_random_function(), 1);
}
- Apply(context_, r0);
+ context()->Plug(r0);
}
// 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_, r0);
+ context()->Plug(r0);
}
// 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_, r0);
+ context()->Plug(r0);
}
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.
__ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
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(r1); // r0 = value. r1 = object.
Label done;
__ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
- VisitForValue(args->at(0), kAccumulator);
+ VisitForAccumulatorValue(args->at(0));
Label done;
StringCharFromCodeGenerator generator(r0, r1);
generator.GenerateSlow(masm_, call_helper);
__ bind(&done);
- Apply(context_, r1);
+ context()->Plug(r1);
}
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 = r1;
Register index = r0;
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 = r1;
Register index = r0;
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_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the runtime.
ASSERT(args->length() == 1);
- VisitForValue(args->at(0), kStack);
+ VisitForStackValue(args->at(0));
__ CallRuntime(Runtime::kMath_sin, 1);
- Apply(context_, r0);
+ context()->Plug(r0);
}
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the runtime.
ASSERT(args->length() == 1);
- VisitForValue(args->at(0), kStack);
+ VisitForStackValue(args->at(0));
__ CallRuntime(Runtime::kMath_cos, 1);
- Apply(context_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
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 r1. Move it in there.
if (!result_register().is(r1)) __ mov(r1, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(r1, count, CALL_FUNCTION);
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
- Apply(context_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
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_, r0);
+ context()->Plug(r0);
}
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
- Apply(context_, r0);
+ context()->Plug(r0);
return;
}
- VisitForValue(args->at(1), kAccumulator);
+ VisitForAccumulatorValue(args->at(1));
Register key = r0;
Register cache = r1;
__ CallRuntime(Runtime::kGetFromCache, 2);
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
}
Register tmp = r2;
Register tmp2 = r3;
- VisitForValue(args->at(0), kStack);
- VisitForValue(args->at(1), kAccumulator);
+ VisitForStackValue(args->at(0));
+ VisitForAccumulatorValue(args->at(1));
__ pop(left);
Label done, fail, ok;
__ LoadRoot(r0, Heap::kTrueValueRootIndex);
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
- 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);
__ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
__ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
__ b(eq, if_true);
__ b(if_false);
- 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));
__ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
__ IndexFromHash(r0, r0);
- Apply(context_, r0);
+ context()->Plug(r0);
}
// 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()) {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
}
- Apply(context_, r0);
+ context()->Plug(r0);
}
// 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()) {
__ ldr(r1, CodeGenerator::GlobalObject());
__ mov(r0, Operand(var->name()));
__ push(r2);
}
__ InvokeBuiltin(Builtins::DELETE, CALL_JS);
- Apply(context_, r0);
+ context()->Plug(r0);
}
break;
}
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:
- __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- __ push(result_register());
- break;
- }
- break;
- case Expression::kTest:
- __ jmp(false_label_);
- break;
- }
+ context()->Plug(Heap::kUndefinedValueRootIndex);
break;
}
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_, r0);
+ context()->Plug(r0);
break;
}
case Token::ADD: {
Comment cmt(masm_, "[ UnaryOperation (ADD)");
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
Label no_conversion;
__ tst(result_register(), Operand(kSmiTagMask));
__ b(eq, &no_conversion);
__ push(r0);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
__ bind(&no_conversion);
- Apply(context_, result_register());
+ context()->Plug(result_register());
break;
}
NO_UNARY_FLAGS);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
__ CallStub(&stub);
- Apply(context_, r0);
+ context()->Plug(r0);
break;
}
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
// The generic unary operation stub expects the argument to be
// in the accumulator register r0.
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
Label done;
bool inline_smi_code = ShouldInlineSmiCase(expr->op());
if (inline_smi_code) {
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
- Apply(context_, r0);
+ context()->Plug(r0);
break;
}
// 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()) {
__ mov(ip, Operand(Smi::FromInt(0)));
__ push(ip);
}
if (assign_type == NAMED_PROPERTY) {
// Put the object both on the stack and in the accumulator.
- VisitForValue(prop->obj(), kAccumulator);
+ VisitForAccumulatorValue(prop->obj());
__ push(r0);
EmitNamedPropertyLoad(prop);
} else {
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kAccumulator);
+ VisitForStackValue(prop->obj());
+ VisitForAccumulatorValue(prop->key());
__ ldr(r1, MemOperand(sp, 0));
__ push(r0);
EmitKeyedPropertyLoad(prop);
// 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(r0);
- break;
- case NAMED_PROPERTY:
- __ str(r0, MemOperand(sp, kPointerSize));
- break;
- case KEYED_PROPERTY:
- __ str(r0, MemOperand(sp, 2 * kPointerSize));
- 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(r0);
+ break;
+ case NAMED_PROPERTY:
+ __ str(r0, MemOperand(sp, kPointerSize));
+ break;
+ case KEYED_PROPERTY:
+ __ str(r0, MemOperand(sp, 2 * kPointerSize));
+ break;
+ }
}
}
switch (assign_type) {
case VARIABLE:
if (expr->is_postfix()) {
- 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 EffectConstant We have the result on
// top of the stack.
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
- Token::ASSIGN,
- context_);
+ Token::ASSIGN);
}
break;
case NAMED_PROPERTY: {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
if (expr->is_postfix()) {
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
break;
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
if (expr->is_postfix()) {
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
- Apply(context_, r0);
+ context()->Plug(r0);
}
break;
}
}
-void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
+void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
+ ASSERT(!context()->IsEffect());
+ ASSERT(!context()->IsTest());
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
Comment cmnt(masm_, "Global variable");
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(ic, RelocInfo::CODE_TARGET);
- if (where == kStack) __ push(r0);
+ context()->Plug(r0);
} else if (proxy != NULL &&
proxy->var()->slot() != NULL &&
proxy->var()->slot()->type() == Slot::LOOKUP) {
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
__ bind(&done);
- if (where == kStack) __ push(r0);
+ context()->Plug(r0);
} else {
// This expression cannot throw a reference error at the top level.
- VisitForValue(expr, where);
+ Visit(expr);
}
}
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())) {
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, if_true);
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.
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 (op) {
case Token::IN:
- VisitForValue(expr->right(), kStack);
+ VisitForStackValue(expr->right());
__ InvokeBuiltin(Builtins::IN, CALL_JS);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip);
break;
case Token::INSTANCEOF: {
- VisitForValue(expr->right(), kStack);
+ VisitForStackValue(expr->right());
InstanceofStub stub;
__ CallStub(&stub);
// The stub returns 0 for true.
}
default: {
- VisitForValue(expr->right(), kAccumulator);
+ VisitForAccumulatorValue(expr->right());
Condition cc = eq;
bool strict = false;
switch (op) {
// 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);
}
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());
__ LoadRoot(r1, Heap::kNullValueRootIndex);
__ cmp(r0, r1);
if (expr->is_strict()) {
__ cmp(r1, Operand(1 << Map::kIsUndetectable));
Split(eq, if_true, if_false, fall_through);
}
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
- Apply(context_, r0);
+ context()->Plug(r0);
}
class Expression: public AstNode {
public:
- enum Context {
- // Not assigned a context yet, or else will not be visited during
- // code generation.
- kUninitialized,
- // Evaluated for its side effects.
- kEffect,
- // Evaluated for its value (and side effects).
- kValue,
- // Evaluated for control flow (and side effects).
- kTest
- };
-
Expression() : bitfields_(0) {}
virtual Expression* AsExpression() { return this; }
}
-void FullCodeGenerator::PrepareTest(Label* materialize_true,
- Label* materialize_false,
- Label** if_true,
- Label** if_false,
- Label** fall_through) {
- switch (context_) {
- case Expression::kUninitialized:
- UNREACHABLE();
- break;
- case Expression::kEffect:
- // In an effect context, the true and the false case branch to the
- // same label.
- *if_true = *if_false = *fall_through = materialize_true;
- break;
- case Expression::kValue:
- *if_true = *fall_through = materialize_true;
- *if_false = materialize_false;
- break;
- case Expression::kTest:
- *if_true = true_label_;
- *if_false = false_label_;
- *fall_through = fall_through_;
- break;
- }
+void FullCodeGenerator::EffectContext::Plug(Register reg) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
+ // Move value into place.
+ __ Move(result_register(), reg);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
+ // Move value into place.
+ __ push(reg);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Register reg) const {
+ // For simplicity we always test the accumulator register.
+ __ Move(result_register(), reg);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
+
+
+void FullCodeGenerator::EffectContext::PlugTOS() const {
+ __ Drop(1);
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
+ __ pop(result_register());
+}
+
+
+void FullCodeGenerator::StackValueContext::PlugTOS() const {
+}
+
+
+void FullCodeGenerator::TestContext::PlugTOS() const {
+ // For simplicity we always test the accumulator register.
+ __ pop(result_register());
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
+
+
+void FullCodeGenerator::EffectContext::PrepareTest(
+ Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const {
+ // In an effect context, the true and the false case branch to the
+ // same label.
+ *if_true = *if_false = *fall_through = materialize_true;
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
+ Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const {
+ *if_true = *fall_through = materialize_true;
+ *if_false = materialize_false;
+}
+
+
+void FullCodeGenerator::StackValueContext::PrepareTest(
+ Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const {
+ *if_true = *fall_through = materialize_true;
+ *if_false = materialize_false;
+}
+
+
+void FullCodeGenerator::TestContext::PrepareTest(
+ Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const {
+ *if_true = true_label_;
+ *if_false = false_label_;
+ *fall_through = fall_through_;
}
// Load only the operands that we need to materialize.
if (constant == kNoConstants) {
- VisitForValue(left, kStack);
- VisitForValue(right, kAccumulator);
+ VisitForStackValue(left);
+ VisitForAccumulatorValue(right);
} else if (constant == kRightConstant) {
- VisitForValue(left, kAccumulator);
+ VisitForAccumulatorValue(left);
} else {
ASSERT(constant == kLeftConstant);
- VisitForValue(right, kAccumulator);
+ VisitForAccumulatorValue(right);
}
SetSourcePosition(expr->position());
if (ShouldInlineSmiCase(op)) {
- EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
+ EmitInlineSmiBinaryOp(expr, op, mode, left, right, constant);
} else {
- EmitBinaryOp(op, context_, mode);
+ EmitBinaryOp(op, mode);
}
break;
}
void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
Label eval_right, done;
- // Set up the appropriate context for the left subexpression based
- // on the operation and our own context. Initially assume we can
- // inherit both true and false labels from our context.
- if (expr->op() == Token::OR) {
- switch (context_) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- VisitForControl(expr->left(), &done, &eval_right, &eval_right);
- break;
- case Expression::kValue:
- VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
- break;
- case Expression::kTest:
- VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
- break;
- }
- } else {
- ASSERT_EQ(Token::AND, expr->op());
- switch (context_) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- VisitForControl(expr->left(), &eval_right, &done, &eval_right);
- break;
- case Expression::kValue:
- VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
- break;
- case Expression::kTest:
- VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
- break;
- }
- }
+ context()->EmitLogicalLeft(expr, &eval_right, &done);
__ bind(&eval_right);
Visit(expr->right());
}
-void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
- Token::Value op,
- Location where,
- Label* done) {
- ASSERT(op == Token::AND || op == Token::OR);
- VisitForValue(expr, kAccumulator);
+void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const {
+ if (expr->op() == Token::OR) {
+ codegen()->VisitForControl(expr->left(), done, eval_right, eval_right);
+ } else {
+ ASSERT(expr->op() == Token::AND);
+ codegen()->VisitForControl(expr->left(), eval_right, done, eval_right);
+ }
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft(
+ BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const {
+ codegen()->Visit(expr->left());
+ // We want the value in the accumulator for the test, and on the stack in case
+ // we need it.
__ push(result_register());
+ Label discard, restore;
+ if (expr->op() == Token::OR) {
+ codegen()->DoTest(&restore, &discard, &restore);
+ } else {
+ ASSERT(expr->op() == Token::AND);
+ codegen()->DoTest(&discard, &restore, &restore);
+ }
+ __ bind(&restore);
+ __ pop(result_register());
+ __ jmp(done);
+ __ bind(&discard);
+ __ Drop(1);
+}
+
+void FullCodeGenerator::StackValueContext::EmitLogicalLeft(
+ BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const {
+ codegen()->VisitForAccumulatorValue(expr->left());
+ // We want the value in the accumulator for the test, and on the stack in case
+ // we need it.
+ __ push(result_register());
Label discard;
- switch (where) {
- case kAccumulator: {
- Label restore;
- if (op == Token::OR) {
- DoTest(&restore, &discard, &restore);
- } else {
- DoTest(&discard, &restore, &restore);
- }
- __ bind(&restore);
- __ pop(result_register());
- __ jmp(done);
- break;
- }
- case kStack: {
- if (op == Token::OR) {
- DoTest(done, &discard, &discard);
- } else {
- DoTest(&discard, done, &discard);
- }
- break;
- }
+ if (expr->op() == Token::OR) {
+ codegen()->DoTest(done, &discard, &discard);
+ } else {
+ ASSERT(expr->op() == Token::AND);
+ codegen()->DoTest(&discard, done, &discard);
}
-
__ bind(&discard);
__ Drop(1);
}
+void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const {
+ if (expr->op() == Token::OR) {
+ codegen()->VisitForControl(expr->left(),
+ true_label_, eval_right, eval_right);
+ } else {
+ ASSERT(expr->op() == Token::AND);
+ codegen()->VisitForControl(expr->left(),
+ eval_right, false_label_, eval_right);
+ }
+}
+
+
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
Breakable nested_statement(this, stmt);
Comment cmnt(masm_, "[ ReturnStatement");
SetStatementPosition(stmt);
Expression* expr = stmt->expression();
- VisitForValue(expr, kAccumulator);
+ VisitForAccumulatorValue(expr);
// Exit all nested statements.
NestedStatement* current = nesting_stack_;
Comment cmnt(masm_, "[ WithEnterStatement");
SetStatementPosition(stmt);
- VisitForValue(stmt->expression(), kStack);
+ VisitForStackValue(stmt->expression());
if (stmt->is_catch_block()) {
__ CallRuntime(Runtime::kPushCatchContext, 1);
} else {
expr->then_expression_position());
Visit(expr->then_expression());
// If control flow falls through Visit, jump to done.
- if (context_ == Expression::kEffect || context_ == Expression::kValue) {
+ if (!context()->IsTest()) {
__ jmp(&done);
}
expr->else_expression_position());
Visit(expr->else_expression());
// If control flow falls through Visit, merge it with true case here.
- if (context_ == Expression::kEffect || context_ == Expression::kValue) {
+ if (!context()->IsTest()) {
__ bind(&done);
}
}
void FullCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
- Apply(context_, expr);
+ context()->Plug(expr->handle());
}
// Call runtime routine to allocate the catch extension object and
// assign the exception value to the catch variable.
Comment cmnt(masm_, "[ CatchExtensionObject");
- VisitForValue(expr->key(), kStack);
- VisitForValue(expr->value(), kStack);
+ VisitForStackValue(expr->key());
+ VisitForStackValue(expr->value());
// Create catch extension object.
__ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
- Apply(context_, result_register());
+ context()->Plug(result_register());
}
void FullCodeGenerator::VisitThrow(Throw* expr) {
Comment cmnt(masm_, "[ Throw");
- VisitForValue(expr->exception(), kStack);
+ VisitForStackValue(expr->exception());
__ CallRuntime(Runtime::kThrow, 1);
// Never returns here.
}
void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
- VisitForValue(args->at(0), kStack);
+ VisitForStackValue(args->at(0));
__ CallRuntime(Runtime::kRegExpCloneResult, 1);
- Apply(context_, result_register());
+ context()->Plug(result_register());
}
#undef __
info_(NULL),
nesting_stack_(NULL),
loop_depth_(0),
- location_(kStack),
- true_label_(NULL),
- false_label_(NULL),
- fall_through_(NULL) {
+ context_(NULL) {
}
static Handle<Code> MakeCode(CompilationInfo* info);
DISALLOW_COPY_AND_ASSIGN(ForIn);
};
- enum Location {
- kAccumulator,
- kStack
- };
-
enum ConstantOperand {
kNoConstants,
kLeftConstant,
Expression* left,
Expression* right);
- // Emit code to convert a pure value (in a register, slot, as a literal,
- // or on top of the stack) into the result expected according to an
- // expression context.
- void Apply(Expression::Context context, Register reg);
-
- // Slot cannot have type Slot::LOOKUP.
- void Apply(Expression::Context context, Slot* slot);
-
- void Apply(Expression::Context context, Literal* lit);
- void ApplyTOS(Expression::Context context);
-
- // Emit code to discard count elements from the top of stack, then convert
- // a pure value into the result expected according to an expression
- // context.
- void DropAndApply(int count, Expression::Context context, Register reg);
-
- // Set up branch labels for a test expression.
- void PrepareTest(Label* materialize_true,
- Label* materialize_false,
- Label** if_true,
- Label** if_false,
- Label** fall_through);
-
- // Emit code to convert pure control flow to a pair of labels into the
- // result expected according to an expression context.
- void Apply(Expression::Context context,
- Label* materialize_true,
- Label* materialize_false);
-
- // Emit code to convert constant control flow (true or false) into
- // the result expected according to an expression context.
- void Apply(Expression::Context context, bool flag);
-
// Helper function to convert a pure value into a test context. The value
// is expected on the stack or the accumulator, depending on the platform.
// See the platform-specific implementation for details.
MemOperand EmitSlotSearch(Slot* slot, Register scratch);
void VisitForEffect(Expression* expr) {
- Expression::Context saved_context = context_;
- context_ = Expression::kEffect;
+ EffectContext context(this);
+ Visit(expr);
+ }
+
+ void VisitForAccumulatorValue(Expression* expr) {
+ AccumulatorValueContext context(this);
Visit(expr);
- context_ = saved_context;
}
- void VisitForValue(Expression* expr, Location where) {
- Expression::Context saved_context = context_;
- Location saved_location = location_;
- context_ = Expression::kValue;
- location_ = where;
+ void VisitForStackValue(Expression* expr) {
+ StackValueContext context(this);
Visit(expr);
- context_ = saved_context;
- location_ = saved_location;
}
void VisitForControl(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through) {
- Expression::Context saved_context = context_;
- Label* saved_true = true_label_;
- Label* saved_false = false_label_;
- Label* saved_fall_through = fall_through_;
- context_ = Expression::kTest;
- true_label_ = if_true;
- false_label_ = if_false;
- fall_through_ = fall_through;
+ TestContext context(this, if_true, if_false, fall_through);
Visit(expr);
- context_ = saved_context;
- true_label_ = saved_true;
- false_label_ = saved_false;
- fall_through_ = saved_fall_through;
}
void VisitDeclarations(ZoneList<Declaration*>* declarations);
TypeofState typeof_state,
Label* slow,
Label* done);
- void EmitVariableLoad(Variable* expr, Expression::Context context);
+ void EmitVariableLoad(Variable* expr);
// Platform-specific support for allocating a new closure based on
// the given function info.
// Apply the compound assignment operator. Expects the left operand on top
// of the stack and the right one in the accumulator.
void EmitBinaryOp(Token::Value op,
- Expression::Context context,
OverwriteMode mode);
// Helper functions for generating inlined smi code for certain
// binary operations.
void EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
void EmitConstantSmiBinaryOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
void EmitConstantSmiBitOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
Smi* value);
void EmitConstantSmiShiftOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
Smi* value);
void EmitConstantSmiAdd(Expression* expr,
- Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
void EmitConstantSmiSub(Expression* expr,
- Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value);
// Complete a variable assignment. The right-hand-side value is expected
// in the accumulator.
void EmitVariableAssignment(Variable* var,
- Token::Value op,
- Expression::Context context);
+ Token::Value op);
// Complete a named property assignment. The receiver is expected on top
// of the stack and the right-hand-side value in the accumulator.
MacroAssembler* masm() { return masm_; }
+ class ExpressionContext;
+ const ExpressionContext* context() { return context_; }
+ void set_new_context(const ExpressionContext* context) { context_ = context; }
+
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
FunctionLiteral* function() { return info_->function(); }
// Handles the shortcutted logical binary operations in VisitBinaryOperation.
void EmitLogicalOperation(BinaryOperation* expr);
- void VisitForTypeofValue(Expression* expr, Location where);
-
- void VisitLogicalForValue(Expression* expr,
- Token::Value op,
- Location where,
- Label* done);
-
+ void VisitForTypeofValue(Expression* expr);
MacroAssembler* masm_;
CompilationInfo* info_;
NestedStatement* nesting_stack_;
int loop_depth_;
- Expression::Context context_;
- Location location_;
- Label* true_label_;
- Label* false_label_;
- Label* fall_through_;
+ class ExpressionContext {
+ public:
+ explicit ExpressionContext(FullCodeGenerator* codegen)
+ : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
+ codegen->set_new_context(this);
+ }
+
+ virtual ~ExpressionContext() {
+ codegen_->set_new_context(old_);
+ }
+
+ // Convert constant control flow (true or false) to the result expected for
+ // this expression context.
+ virtual void Plug(bool flag) const = 0;
+
+ // Emit code to convert a pure value (in a register, slot, as a literal,
+ // or on top of the stack) into the result expected according to this
+ // expression context.
+ virtual void Plug(Register reg) const = 0;
+ virtual void Plug(Slot* slot) const = 0;
+ virtual void Plug(Handle<Object> lit) const = 0;
+ virtual void Plug(Heap::RootListIndex index) const = 0;
+ virtual void PlugTOS() const = 0;
+
+ // Emit code to convert pure control flow to a pair of unbound labels into
+ // the result expected according to this expression context. The
+ // implementation may decide to bind either of the labels.
+ virtual void Plug(Label* materialize_true,
+ Label* materialize_false) const = 0;
+
+ // Emit code to discard count elements from the top of stack, then convert
+ // a pure value into the result expected according to this expression
+ // context.
+ virtual void DropAndPlug(int count, Register reg) const = 0;
+
+ // For shortcutting operations || and &&.
+ virtual void EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const = 0;
+
+ // Set up branch labels for a test expression. The three Label** parameters
+ // are output parameters.
+ virtual void PrepareTest(Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const = 0;
+
+ // Returns true if we are evaluating only for side effects (ie if the result
+ // will be discarded.
+ virtual bool IsEffect() const { return false; }
+
+ // Returns true if we are branching on the value rather than materializing
+ // it.
+ virtual bool IsTest() const { return false; }
+
+ protected:
+ FullCodeGenerator* codegen() const { return codegen_; }
+ MacroAssembler* masm() const { return masm_; }
+ MacroAssembler* masm_;
+
+ private:
+ const ExpressionContext* old_;
+ FullCodeGenerator* codegen_;
+ };
+
+ class AccumulatorValueContext : public ExpressionContext {
+ public:
+ explicit AccumulatorValueContext(FullCodeGenerator* codegen)
+ : ExpressionContext(codegen) { }
+
+ virtual void Plug(bool flag) const;
+ virtual void Plug(Register reg) const;
+ virtual void Plug(Label* materialize_true, Label* materialize_false) const;
+ virtual void Plug(Slot* slot) const;
+ virtual void Plug(Handle<Object> lit) const;
+ virtual void Plug(Heap::RootListIndex) const;
+ virtual void PlugTOS() const;
+ virtual void DropAndPlug(int count, Register reg) const;
+ virtual void EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const;
+ virtual void PrepareTest(Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const;
+ };
+
+ class StackValueContext : public ExpressionContext {
+ public:
+ explicit StackValueContext(FullCodeGenerator* codegen)
+ : ExpressionContext(codegen) { }
+
+ virtual void Plug(bool flag) const;
+ virtual void Plug(Register reg) const;
+ virtual void Plug(Label* materialize_true, Label* materialize_false) const;
+ virtual void Plug(Slot* slot) const;
+ virtual void Plug(Handle<Object> lit) const;
+ virtual void Plug(Heap::RootListIndex) const;
+ virtual void PlugTOS() const;
+ virtual void DropAndPlug(int count, Register reg) const;
+ virtual void EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const;
+ virtual void PrepareTest(Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const;
+ };
+
+ class TestContext : public ExpressionContext {
+ public:
+ explicit TestContext(FullCodeGenerator* codegen,
+ Label* true_label,
+ Label* false_label,
+ Label* fall_through)
+ : ExpressionContext(codegen),
+ true_label_(true_label),
+ false_label_(false_label),
+ fall_through_(fall_through) { }
+
+ virtual void Plug(bool flag) const;
+ virtual void Plug(Register reg) const;
+ virtual void Plug(Label* materialize_true, Label* materialize_false) const;
+ virtual void Plug(Slot* slot) const;
+ virtual void Plug(Handle<Object> lit) const;
+ virtual void Plug(Heap::RootListIndex) const;
+ virtual void PlugTOS() const;
+ virtual void DropAndPlug(int count, Register reg) const;
+ virtual void EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const;
+ virtual void PrepareTest(Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const;
+ virtual bool IsTest() const { return true; }
+
+ private:
+ Label* true_label_;
+ Label* false_label_;
+ Label* fall_through_;
+ };
+
+ class EffectContext : public ExpressionContext {
+ public:
+ explicit EffectContext(FullCodeGenerator* codegen)
+ : ExpressionContext(codegen) { }
+
+ virtual void Plug(bool flag) const;
+ virtual void Plug(Register reg) const;
+ virtual void Plug(Label* materialize_true, Label* materialize_false) const;
+ virtual void Plug(Slot* slot) const;
+ virtual void Plug(Handle<Object> lit) const;
+ virtual void Plug(Heap::RootListIndex) const;
+ virtual void PlugTOS() const;
+ virtual void DropAndPlug(int count, Register reg) const;
+ virtual void EmitLogicalLeft(BinaryOperation* expr,
+ Label* eval_right,
+ Label* done) const;
+ virtual void PrepareTest(Label* materialize_true,
+ Label* materialize_false,
+ Label** if_true,
+ Label** if_false,
+ Label** fall_through) const;
+ virtual bool IsEffect() const { return true; }
+ };
+
+ const ExpressionContext* context_;
friend class NestedStatement;
}
-void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+}
- 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 {
+}
- 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::EffectContext::DropAndPlug(int count,
+ Register reg) const {
ASSERT(count > 0);
- ASSERT(!reg.is(esp));
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+ __ Drop(count);
+}
- 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::AccumulatorValueContext::DropAndPlug(
+ int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ __ Drop(count);
+ __ Move(result_register(), reg);
+}
- 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::StackValueContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ if (count > 1) __ Drop(count - 1);
+ __ mov(Operand(esp, 0), reg);
}
-void FullCodeGenerator::Apply(Expression::Context context,
- Label* materialize_true,
- Label* materialize_false) {
- switch (context) {
- case Expression::kUninitialized:
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ // For simplicity we always test the accumulator register.
+ __ Drop(count);
+ __ Move(result_register(), reg);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
- case Expression::kEffect:
- ASSERT_EQ(materialize_true, materialize_false);
- __ bind(materialize_true);
- break;
- case Expression::kValue: {
- NearLabel 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::EffectContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT_EQ(materialize_true, materialize_false);
+ __ bind(materialize_true);
+}
- case Expression::kTest:
- break;
- }
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ NearLabel done;
+ __ bind(materialize_true);
+ __ mov(result_register(), Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ mov(result_register(), Factory::false_value());
+ __ bind(&done);
}
-// 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::StackValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ NearLabel done;
+ __ bind(materialize_true);
+ __ push(Immediate(Factory::true_value()));
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ push(Immediate(Factory::false_value()));
+ __ bind(&done);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT(materialize_false == false_label_);
+ ASSERT(materialize_true == true_label_);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {
+}
+
+
+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_);
}
}
__ 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;
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);
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!
}
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());
}
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.
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.
// 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());
__ 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());
}
}
-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.
__ mov(ecx, var->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
- Apply(context, eax);
+ context()->Plug(eax);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Label done, slow;
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
- Apply(context, eax);
+ context()->Plug(eax);
} else if (slot != NULL) {
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
__ 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 {
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC.
- Apply(context, eax);
+ context()->Plug(eax);
}
}
__ mov(edx, FieldOperand(ebx, size - kPointerSize));
__ mov(FieldOperand(eax, size - kPointerSize), edx);
}
- Apply(context_, eax);
+ context()->Plug(eax);
}
// 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));
// 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();
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, eax);
+ context()->Plug(eax);
}
}
__ 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.
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, eax);
+ context()->Plug(eax);
}
}
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();
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.
switch (assign_type) {
case VARIABLE:
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
- expr->op(),
- context_);
+ expr->op());
break;
case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr);
void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr,
- Expression::Context context,
OverwriteMode mode,
bool left_is_constant_smi,
Smi* value) {
}
__ 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) {
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;
}
__ 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;
}
__ 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) {
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();
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;
}
}
__ 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);
__ push(result_register());
__ CallStub(&stub);
}
- Apply(context, eax);
+ context()->Plug(eax);
}
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());
}
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.
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);
__ bind(&done);
}
- Apply(context, eax);
+ context()->Plug(eax);
}
__ 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);
}
}
__ pop(eax);
}
- Apply(context_, eax);
+ context()->Plug(eax);
}
Expression* key = expr->key();
if (key->IsPropertyName()) {
- VisitForValue(expr->obj(), kAccumulator);
+ VisitForAccumulatorValue(expr->obj());
EmitNamedPropertyLoad(expr);
- Apply(context_, 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);
}
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.
EmitCallIC(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- Apply(context_, eax);
+ context()->Plug(eax);
}
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());
EmitCallIC(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- Apply(context_, eax);
+ context()->Plug(eax);
}
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());
__ CallStub(&stub);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- DropAndApply(1, context_, eax);
+ context()->DropAndPlug(1, eax);
}
// 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.
__ 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());
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 EmitCallIC.
- 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.
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));
// 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
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);
__ 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);
__ 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);
}
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);
}
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));
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);
}
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);
}
// 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);
}
__ bind(&exit);
if (FLAG_debug_code) __ AbortIfNotSmi(eax);
- Apply(context_, eax);
+ context()->Plug(eax);
}
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));
// All done.
__ bind(&done);
- Apply(context_, eax);
+ context()->Plug(eax);
}
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);
}
__ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
}
__ mov(eax, edi);
- Apply(context_, eax);
+ context()->Plug(eax);
}
// 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);
}
// 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.
NearLabel done;
// If the object is a smi return the object.
__ 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.
NearLabel done;
__ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
__ bind(&done);
- Apply(context_, eax);
+ context()->Plug(eax);
}
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);
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;
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;
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);
}
// 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);
}
// 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);
}
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);
}
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;
__ CallRuntime(Runtime::kGetFromCache, 2);
__ bind(&done);
- Apply(context_, eax);
+ context()->Plug(eax);
}
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;
__ 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);
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);
__ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
__ IndexFromHash(eax, eax);
- Apply(context_, eax);
+ context()->Plug(eax);
}
// 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()) {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
}
- Apply(context_, eax);
+ context()->Plug(eax);
}
// 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()));
__ push(Immediate(var->name()));
}
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
- Apply(context_, eax);
+ context()->Plug(eax);
}
break;
}
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;
}
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;
}
GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
// 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;
}
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;
bool inline_smi_case = ShouldInlineSmiCase(expr->op());
if (inline_smi_case) {
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
- Apply(context_, eax);
+ context()->Plug(eax);
break;
}
// 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);
// 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;
+ }
}
}
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: {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
if (expr->is_postfix()) {
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
- Apply(context_, eax);
+ context()->Plug(eax);
}
break;
}
EmitCallIC(ic, RelocInfo::CODE_TARGET);
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;
}
}
-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());
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(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) {
__ 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);
}
}
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);
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.
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));
}
default: {
- VisitForValue(expr->right(), kAccumulator);
+ VisitForAccumulatorValue(expr->right());
Condition cc = no_condition;
bool strict = false;
switch (op) {
// 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);
}
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);
__ 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);
}
}
+void MacroAssembler::Move(Register dst, Register src) {
+ if (!dst.is(src)) {
+ mov(dst, src);
+ }
+}
+
+
void MacroAssembler::Move(Register dst, Handle<Object> value) {
mov(dst, value);
}
void Call(Label* target) { call(target); }
+ // Move if the registers are not identical.
+ void Move(Register target, Register source);
+
void Move(Register target, Handle<Object> value);
Handle<Object> CodeObject() { return code_object_; }
}
-void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
+}
- case Expression::kEffect:
- // Nothing to do.
- break;
- case Expression::kValue:
- // Move value into place.
- switch (location_) {
- case kAccumulator:
- if (!reg.is(result_register())) __ movq(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());
+ __ movq(result_register(), slot_operand);
+}
- case Expression::kTest:
- // For simplicity we always test the accumulator register.
- if (!reg.is(result_register())) __ movq(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());
+ __ 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:
- __ movq(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 {
+ codegen()->Move(result_register(), slot);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
- case Expression::kTest:
- Move(result_register(), slot);
- DoTest(true_label_, false_label_, fall_through_);
- break;
- }
+
+void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
}
-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:
- __ Move(result_register(), lit->handle());
- break;
- case kStack:
- __ Push(lit->handle());
- break;
- }
- break;
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Heap::RootListIndex index) const {
+ __ LoadRoot(result_register(), index);
+}
- case Expression::kTest:
- __ Move(result_register(), lit->handle());
- DoTest(true_label_, false_label_, fall_through_);
- break;
+
+void FullCodeGenerator::StackValueContext::Plug(
+ Heap::RootListIndex index) const {
+ __ PushRoot(index);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
+ if (index == Heap::kUndefinedValueRootIndex ||
+ index == Heap::kNullValueRootIndex ||
+ index == Heap::kFalseValueRootIndex) {
+ __ jmp(false_label_);
+ } else if (index == Heap::kTrueValueRootIndex) {
+ __ jmp(true_label_);
+ } else {
+ __ LoadRoot(result_register(), index);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
}
}
-void FullCodeGenerator::ApplyTOS(Expression::Context context) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
+}
- case Expression::kEffect:
- __ Drop(1);
- break;
- case Expression::kValue:
- switch (location_) {
- case kAccumulator:
- __ pop(result_register());
- break;
- case kStack:
- break;
- }
- break;
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Handle<Object> lit) const {
+ __ Move(result_register(), lit);
+}
- case Expression::kTest:
- __ pop(result_register());
- DoTest(true_label_, false_label_, fall_through_);
- break;
+
+void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
+ __ Push(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.
+ __ Move(result_register(), lit);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
}
}
-void FullCodeGenerator::DropAndApply(int count,
- Expression::Context context,
- Register reg) {
+void FullCodeGenerator::EffectContext::DropAndPlug(int count,
+ Register reg) const {
ASSERT(count > 0);
- ASSERT(!reg.is(rsp));
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
+ __ Drop(count);
+}
- case Expression::kEffect:
- __ Drop(count);
- break;
- case Expression::kValue:
- switch (location_) {
- case kAccumulator:
- __ Drop(count);
- if (!reg.is(result_register())) __ movq(result_register(), reg);
- break;
- case kStack:
- if (count > 1) __ Drop(count - 1);
- __ movq(Operand(rsp, 0), reg);
- break;
- }
- break;
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
+ int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ __ Drop(count);
+ __ Move(result_register(), reg);
+}
- case Expression::kTest:
- __ Drop(count);
- if (!reg.is(result_register())) __ movq(result_register(), reg);
- DoTest(true_label_, false_label_, fall_through_);
- break;
- }
+
+void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ if (count > 1) __ Drop(count - 1);
+ __ movq(Operand(rsp, 0), reg);
}
-void FullCodeGenerator::Apply(Expression::Context context,
- Label* materialize_true,
- Label* materialize_false) {
- switch (context) {
- case Expression::kUninitialized:
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+ Register reg) const {
+ ASSERT(count > 0);
+ // For simplicity we always test the accumulator register.
+ __ Drop(count);
+ __ Move(result_register(), reg);
+ codegen()->DoTest(true_label_, false_label_, fall_through_);
+}
- case Expression::kEffect:
- ASSERT_EQ(materialize_true, materialize_false);
- __ bind(materialize_true);
- break;
- case Expression::kValue: {
- NearLabel done;
- switch (location_) {
- case kAccumulator:
- __ bind(materialize_true);
- __ Move(result_register(), Factory::true_value());
- __ jmp(&done);
- __ bind(materialize_false);
- __ Move(result_register(), Factory::false_value());
- break;
- case kStack:
- __ bind(materialize_true);
- __ Push(Factory::true_value());
- __ jmp(&done);
- __ bind(materialize_false);
- __ Push(Factory::false_value());
- break;
- }
- __ bind(&done);
- break;
- }
+void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT_EQ(materialize_true, materialize_false);
+ __ bind(materialize_true);
+}
- case Expression::kTest:
- break;
- }
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ NearLabel done;
+ __ bind(materialize_true);
+ __ Move(result_register(), Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ Move(result_register(), Factory::false_value());
+ __ bind(&done);
}
-// 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: {
- Heap::RootListIndex value_root_index =
- flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
- switch (location_) {
- case kAccumulator:
- __ LoadRoot(result_register(), value_root_index);
- break;
- case kStack:
- __ PushRoot(value_root_index);
- 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::StackValueContext::Plug(
+ Label* materialize_true,
+ Label* materialize_false) const {
+ NearLabel done;
+ __ bind(materialize_true);
+ __ Push(Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ Push(Factory::false_value());
+ __ bind(&done);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+ Label* materialize_false) const {
+ ASSERT(materialize_false == false_label_);
+ ASSERT(materialize_true == true_label_);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
+ Heap::RootListIndex value_root_index =
+ flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+ __ LoadRoot(result_register(), value_root_index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
+ Heap::RootListIndex value_root_index =
+ flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+ __ PushRoot(value_root_index);
+}
+
+
+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_);
}
}
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
} else if (function != NULL) {
- VisitForValue(function, kAccumulator);
+ VisitForAccumulatorValue(function);
__ movq(Operand(rbp, SlotOffset(slot)), result_register());
}
break;
__ movq(ContextOperand(rsi, slot->index()), kScratchRegister);
// No write barrier since the hole value is in old space.
} else if (function != NULL) {
- VisitForValue(function, kAccumulator);
+ VisitForAccumulatorValue(function);
__ movq(ContextOperand(rsi, slot->index()), result_register());
int offset = Context::SlotOffset(slot->index());
__ movq(rbx, rsi);
if (mode == Variable::CONST) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else if (function != NULL) {
- VisitForValue(function, kStack);
+ VisitForStackValue(function);
} else {
__ Push(Smi::FromInt(0)); // no initial value!
}
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(rcx);
} else {
- VisitForValue(prop->key(), kAccumulator);
+ VisitForAccumulatorValue(prop->key());
__ movq(rcx, result_register());
__ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
}
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.
next_test.Unuse();
// Compile the label expression.
- VisitForValue(clause->label(), kAccumulator);
+ VisitForAccumulatorValue(clause->label());
// Perform the comparison as if via '==='.
__ movq(rdx, Operand(rsp, 0)); // Switch value.
// 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());
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, &exit);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ Push(info);
__ CallRuntime(Runtime::kNewClosure, 2);
}
- Apply(context_, rax);
+ context()->Plug(rax);
}
void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
- EmitVariableLoad(expr->var(), context_);
+ EmitVariableLoad(expr->var());
}
}
-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.
__ movq(rax, CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
- Apply(context, rax);
+ context()->Plug(rax);
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
Label done, slow;
__ CallRuntime(Runtime::kLoadContextSlot, 2);
__ bind(&done);
- Apply(context, rax);
+ context()->Plug(rax);
} else if (slot != NULL) {
Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
__ j(not_equal, &done);
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
__ bind(&done);
- Apply(context, rax);
+ context()->Plug(rax);
} else {
- Apply(context, slot);
+ context()->Plug(slot);
}
} else {
// Do a keyed property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
- Apply(context, rax);
+ context()->Plug(rax);
}
}
__ movq(rdx, FieldOperand(rbx, size - kPointerSize));
__ movq(FieldOperand(rax, size - kPointerSize), rdx);
}
- Apply(context_, rax);
+ context()->Plug(rax);
}
// Fall through.
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
- VisitForValue(value, kAccumulator);
+ VisitForAccumulatorValue(value);
__ Move(rcx, key->handle());
__ movq(rdx, Operand(rsp, 0));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(rsp, 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(rsp, 0)); // Duplicate receiver.
- VisitForValue(key, kStack);
+ VisitForStackValue(key);
__ Push(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0));
- VisitForValue(value, kStack);
+ VisitForStackValue(value);
__ CallRuntime(Runtime::kDefineAccessor, 4);
break;
}
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, rax);
+ context()->Plug(rax);
}
}
__ push(rax);
result_saved = true;
}
- VisitForValue(subexpr, kAccumulator);
+ VisitForAccumulatorValue(subexpr);
// Store the subexpression value in the array's elements.
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
}
if (result_saved) {
- ApplyTOS(context_);
+ context()->PlugTOS();
} else {
- Apply(context_, rax);
+ context()->Plug(rax);
}
}
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());
__ movq(rdx, Operand(rsp, 0));
__ push(rax);
} 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();
ASSERT(constant == kRightConstant || constant == kNoConstants);
if (constant == kNoConstants) {
__ push(rax); // 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.
switch (assign_type) {
case VARIABLE:
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
- expr->op(),
- context_);
+ expr->op());
break;
case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr);
void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
Token::Value op,
- Expression::Context context,
OverwriteMode mode,
Expression* left,
Expression* right,
}
__ bind(&done);
- Apply(context, rax);
+ context()->Plug(rax);
}
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
- Expression::Context context,
OverwriteMode mode) {
GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS);
if (stub.ArgsInRegistersSupported()) {
__ push(result_register());
__ CallStub(&stub);
}
- Apply(context, rax);
+ context()->Plug(rax);
}
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(rax); // Preserve value.
- VisitForValue(prop->obj(), kAccumulator);
+ VisitForAccumulatorValue(prop->obj());
__ movq(rdx, rax);
__ pop(rax); // Restore value.
__ Move(rcx, prop->key()->AsLiteral()->handle());
}
case KEYED_PROPERTY: {
__ push(rax); // Preserve value.
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kAccumulator);
+ VisitForStackValue(prop->obj());
+ VisitForAccumulatorValue(prop->key());
__ movq(rcx, rax);
__ pop(rdx);
__ pop(rax);
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);
__ bind(&done);
}
- Apply(context, rax);
+ context()->Plug(rax);
}
__ push(Operand(rsp, kPointerSize)); // Receiver is under value.
__ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(rax);
- DropAndApply(1, context_, rax);
+ context()->DropAndPlug(1, rax);
} else {
- Apply(context_, rax);
+ context()->Plug(rax);
}
}
__ pop(rax);
}
- Apply(context_, rax);
+ context()->Plug(rax);
}
Expression* key = expr->key();
if (key->IsPropertyName()) {
- VisitForValue(expr->obj(), kAccumulator);
+ VisitForAccumulatorValue(expr->obj());
EmitNamedPropertyLoad(expr);
- Apply(context_, rax);
} else {
- VisitForValue(expr->obj(), kStack);
- VisitForValue(expr->key(), kAccumulator);
+ VisitForStackValue(expr->obj());
+ VisitForAccumulatorValue(expr->key());
__ pop(rdx);
EmitKeyedPropertyLoad(expr);
- Apply(context_, rax);
}
+ context()->Plug(rax);
}
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));
}
__ Move(rcx, name);
// Record source position for debugger.
EmitCallIC(ic, mode);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- Apply(context_, rax);
+ context()->Plug(rax);
}
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);
__ movq(rcx, rax);
// Record source position for debugger.
SetSourcePosition(expr->position());
EmitCallIC(ic, mode);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- Apply(context_, rax);
+ context()->Plug(rax);
}
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());
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndApply(1, context_, rax);
+ context()->DropAndPlug(1, rax);
}
// resolve the function we need to call and the receiver of the
// call. The we call the resolved function using the given
// arguments.
- VisitForValue(fun, kStack);
+ VisitForStackValue(fun);
__ PushRoot(Heap::kUndefinedValueRootIndex); // 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.
__ CallStub(&stub);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- DropAndApply(1, context_, rax);
+ context()->DropAndPlug(1, rax);
} else if (var != NULL && !var->is_this() && var->is_global()) {
// Call to a global variable.
// Push global object as receiver for the call IC lookup.
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 KeyedCallIC.
- VisitForValue(prop->obj(), kStack);
+ VisitForStackValue(prop->obj());
if (prop->is_synthetic()) {
- VisitForValue(prop->key(), kAccumulator);
+ VisitForAccumulatorValue(prop->key());
__ movq(rdx, Operand(rsp, 0));
// Record source code position for IC call.
SetSourcePosition(prop->position());
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
- VisitForValue(fun, kStack);
+ VisitForStackValue(fun);
// Load global receiver object.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
// 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
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
- Apply(context_, rax);
+ context()->Plug(rax);
}
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);
__ JumpIfSmi(rax, if_true);
__ jmp(if_false);
- 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);
Condition positive_smi = __ CheckPositiveSmi(rax);
Split(positive_smi, 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);
__ JumpIfSmi(rax, if_false);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
__ cmpq(rbx, Immediate(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);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
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);
__ JumpIfSmi(rax, if_false);
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
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);
}
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);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
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);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
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);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
Split(equal, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_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);
// Get the frame pointer for the calling frame.
__ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
Smi::FromInt(StackFrame::CONSTRUCT));
Split(equal, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
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(rbx);
__ cmpq(rax, rbx);
Split(equal, if_true, if_false, fall_through);
- Apply(context_, if_true, if_false);
+ context()->Plug(if_true, if_false);
}
// ArgumentsAccessStub expects the key in rdx and the formal
// parameter count in rax.
- VisitForValue(args->at(0), kAccumulator);
+ VisitForAccumulatorValue(args->at(0));
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(scope()->num_parameters()));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub);
- Apply(context_, rax);
+ context()->Plug(rax);
}
__ bind(&exit);
if (FLAG_debug_code) __ AbortIfNotSmi(rax);
- Apply(context_, rax);
+ context()->Plug(rax);
}
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.
__ JumpIfSmi(rax, &null);
// All done.
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
}
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.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- Apply(context_, rax);
+ context()->Plug(rax);
}
__ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
__ movq(rax, rbx);
- Apply(context_, rax);
+ context()->Plug(rax);
}
// 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_, rax);
+ context()->Plug(rax);
}
// 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_, rax);
+ context()->Plug(rax);
}
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.
__ movq(rax, FieldOperand(rax, JSValue::kValueOffset));
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
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(rbx); // rax = value. rbx = object.
Label done;
__ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx);
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
- VisitForValue(args->at(0), kAccumulator);
+ VisitForAccumulatorValue(args->at(0));
Label done;
StringCharFromCodeGenerator generator(rax, rbx);
generator.GenerateSlow(masm_, call_helper);
__ bind(&done);
- Apply(context_, rbx);
+ context()->Plug(rbx);
}
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 = rbx;
Register index = rax;
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 = rbx;
Register index = rax;
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_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
// 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_, rax);
+ context()->Plug(rax);
}
// 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_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
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 rdi. Move it in there.
if (!result_register().is(rdi)) __ movq(rdi, result_register());
ParameterCount count(arg_count);
__ InvokeFunction(rdi, count, CALL_FUNCTION);
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- Apply(context_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
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_, rax);
+ context()->Plug(rax);
}
if (jsfunction_result_caches->length() <= cache_id) {
__ Abort("Attempt to use undefined cache.");
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
- Apply(context_, rax);
+ context()->Plug(rax);
return;
}
- VisitForValue(args->at(1), kAccumulator);
+ VisitForAccumulatorValue(args->at(1));
Register key = rax;
Register cache = rbx;
__ CallRuntime(Runtime::kGetFromCache, 2);
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
}
Register left = rbx;
Register tmp = rcx;
- VisitForValue(args->at(0), kStack);
- VisitForValue(args->at(1), kAccumulator);
+ VisitForStackValue(args->at(0));
+ VisitForAccumulatorValue(args->at(1));
__ pop(left);
NearLabel done, fail, ok;
__ Move(rax, Factory::true_value());
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
}
void FullCodeGenerator::EmitHasCachedArrayIndex(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);
__ testl(FieldOperand(rax, String::kHashFieldOffset),
Immediate(String::kContainsCachedArrayIndexMask));
__ j(zero, if_true);
__ jmp(if_false);
- 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));
__ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
ASSERT(String::kHashShift >= kSmiTagSize);
__ IndexFromHash(rax, rax);
- Apply(context_, rax);
+ context()->Plug(rax);
}
// 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()) {
} else {
__ CallRuntime(expr->function(), arg_count);
}
- Apply(context_, rax);
+ context()->Plug(rax);
}
// 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(var->name());
__ Push(var->name());
}
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
- Apply(context_, rax);
+ context()->Plug(rax);
}
break;
}
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:
- __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
- break;
- case kStack:
- __ PushRoot(Heap::kUndefinedValueRootIndex);
- break;
- }
- break;
- case Expression::kTest:
- __ jmp(false_label_);
- break;
- }
+ context()->Plug(Heap::kUndefinedValueRootIndex);
break;
}
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_, rax);
+ context()->Plug(rax);
break;
}
case Token::ADD: {
Comment cmt(masm_, "[ UnaryOperation (ADD)");
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
NearLabel no_conversion;
Condition is_smi = masm_->CheckSmi(result_register());
__ j(is_smi, &no_conversion);
__ push(result_register());
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
__ bind(&no_conversion);
- Apply(context_, result_register());
+ context()->Plug(result_register());
break;
}
GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
__ CallStub(&stub);
- Apply(context_, rax);
+ context()->Plug(rax);
break;
}
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
// The generic unary operation stub expects the argument to be
// in the accumulator register rax.
- VisitForValue(expr->expression(), kAccumulator);
+ VisitForAccumulatorValue(expr->expression());
Label done;
bool inline_smi_case = ShouldInlineSmiCase(expr->op());
if (inline_smi_case) {
GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
__ CallStub(&stub);
__ bind(&done);
- Apply(context_, rax);
+ context()->Plug(rax);
break;
}
// 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(Smi::FromInt(0));
}
if (assign_type == NAMED_PROPERTY) {
- VisitForValue(prop->obj(), kAccumulator);
+ VisitForAccumulatorValue(prop->obj());
__ push(rax); // Copy of receiver, needed for later store.
EmitNamedPropertyLoad(prop);
} else {
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kAccumulator);
+ VisitForStackValue(prop->obj());
+ VisitForAccumulatorValue(prop->key());
__ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
__ push(rax); // Copy of key, needed for later store.
EmitKeyedPropertyLoad(prop);
// 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(rax);
- break;
- case NAMED_PROPERTY:
- __ movq(Operand(rsp, kPointerSize), rax);
- break;
- case KEYED_PROPERTY:
- __ movq(Operand(rsp, 2 * kPointerSize), rax);
- 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(rax);
+ break;
+ case NAMED_PROPERTY:
+ __ movq(Operand(rsp, kPointerSize), rax);
+ break;
+ case KEYED_PROPERTY:
+ __ movq(Operand(rsp, 2 * kPointerSize), rax);
+ break;
+ }
}
}
case VARIABLE:
if (expr->is_postfix()) {
// Perform the assignment as if via '='.
- EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
- Token::ASSIGN,
- Expression::kEffect);
+ { EffectContext context(this);
+ EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+ Token::ASSIGN);
+ }
// For all contexts except kEffect: 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: {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
if (expr->is_postfix()) {
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
- Apply(context_, rax);
+ context()->Plug(rax);
}
break;
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
if (expr->is_postfix()) {
- if (context_ != Expression::kEffect) {
- ApplyTOS(context_);
+ if (!context()->IsEffect()) {
+ context()->PlugTOS();
}
} else {
- Apply(context_, rax);
+ context()->Plug(rax);
}
break;
}
}
-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");
__ Move(rcx, proxy->name());
// Use a regular load, not a contextual load, to avoid a reference
// error.
EmitCallIC(ic, RelocInfo::CODE_TARGET);
- if (where == kStack) __ push(rax);
+ context()->Plug(rax);
} else if (proxy != NULL &&
proxy->var()->slot() != NULL &&
proxy->var()->slot()->type() == Slot::LOOKUP) {
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
__ bind(&done);
- if (where == kStack) __ push(rax);
+ context()->Plug(rax);
} else {
// This expression cannot throw a reference error at the top level.
- VisitForValue(expr, where);
+ Visit(expr);
}
}
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())) {
Condition is_smi = masm_->CheckSmi(rax);
__ j(is_smi, if_true);
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.
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 (op) {
case Token::IN:
- VisitForValue(expr->right(), kStack);
+ VisitForStackValue(expr->right());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, fall_through);
break;
case Token::INSTANCEOF: {
- VisitForValue(expr->right(), kStack);
+ VisitForStackValue(expr->right());
InstanceofStub stub;
__ CallStub(&stub);
__ testq(rax, rax);
}
default: {
- VisitForValue(expr->right(), kAccumulator);
+ VisitForAccumulatorValue(expr->right());
Condition cc = no_condition;
bool strict = false;
switch (op) {
// 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);
}
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());
__ CompareRoot(rax, Heap::kNullValueRootIndex);
if (expr->is_strict()) {
Split(equal, if_true, if_false, fall_through);
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) {
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
- Apply(context_, rax);
+ context()->Plug(rax);
}
}
+void MacroAssembler::Move(Register dst, Register src) {
+ if (!dst.is(src)) {
+ movq(dst, src);
+ }
+}
+
+
+
+
void MacroAssembler::Move(Register dst, Handle<Object> source) {
ASSERT(!source->IsFailure());
if (source->IsSmi()) {
void Set(Register dst, int64_t x);
void Set(const Operand& dst, int64_t x);
+ // Move if the registers are not identical.
+ void Move(Register target, Register source);
+
// Handle support
void Move(Register dst, Handle<Object> source);
void Move(const Operand& dst, Handle<Object> source);