// The expression is either a property or a variable proxy that rewrites
// to a property.
LoadAndSpill(property->obj());
- // We use a named reference if the key is a literal symbol, unless it is
- // a string that can be legally parsed as an integer. This is because
- // otherwise we will not get into the slow case code that handles [] on
- // String objects.
- Literal* literal = property->key()->AsLiteral();
- uint32_t dummy;
- if (literal != NULL &&
- literal->handle()->IsSymbol() &&
- !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+ if (property->key()->IsPropertyName()) {
ref->set_type(Reference::NAMED);
} else {
LoadAndSpill(property->key());
}
-void FastCodeGenerator::Move(Expression::Context context, Register source) {
+void FastCodeGenerator::Apply(Expression::Context context,
+ Slot* slot,
+ Register scratch) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
- __ push(source);
+ case Expression::kTest:
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ Move(scratch, slot);
+ Apply(context, scratch);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
break;
+ case Expression::kValue:
case Expression::kTest:
- TestAndBranch(source, true_label_, false_label_);
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ __ mov(ip, Operand(lit->handle()));
+ Apply(context, ip);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::ApplyTOS(Expression::Context context) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ __ Drop(1);
+ break;
+ case Expression::kValue:
+ break;
+ case Expression::kTest:
+ __ pop(r0);
+ TestAndBranch(r0, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ push(source);
- TestAndBranch(source, true_label_, &discard);
+ __ ldr(r0, MemOperand(sp, 0));
+ TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
- __ push(source);
- TestAndBranch(source, &discard, false_label_);
+ __ ldr(r0, MemOperand(sp, 0));
+ TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(true_label_);
}
}
}
-void FastCodeGenerator::MoveTOS(Expression::Context context) {
+void FastCodeGenerator::DropAndApply(int count,
+ Expression::Context context,
+ Register reg) {
+ ASSERT(count > 0);
+ ASSERT(!reg.is(sp));
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- __ Drop(1);
+ __ Drop(count);
break;
case Expression::kValue:
+ if (count > 1) __ Drop(count - 1);
+ __ str(reg, MemOperand(sp));
break;
case Expression::kTest:
- __ pop(r0);
- TestAndBranch(r0, true_label_, false_label_);
+ __ Drop(count);
+ TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ ldr(r0, MemOperand(sp, 0));
- TestAndBranch(r0, true_label_, &discard);
+ if (count > 1) __ Drop(count - 1);
+ __ str(reg, MemOperand(sp));
+ TestAndBranch(reg, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
}
case Expression::kTestValue: {
Label discard;
- __ ldr(r0, MemOperand(sp, 0));
- TestAndBranch(r0, &discard, false_label_);
+ if (count > 1) __ Drop(count - 1);
+ __ str(reg, MemOperand(sp));
+ TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
+ break;
}
}
}
-void FastCodeGenerator::Move(Expression::Context context,
- Slot* source,
- Register scratch) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue:
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- Move(scratch, source);
- Move(context, scratch);
- break;
- }
-}
-
-
-void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue:
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- __ mov(ip, Operand(expr->handle()));
- Move(context, ip);
- break;
- }
-}
-
-
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
-void FastCodeGenerator::DropAndMove(Expression::Context context,
- Register source,
- int drop_count) {
- ASSERT(drop_count > 0);
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- __ add(sp, sp, Operand(drop_count * kPointerSize));
- break;
- case Expression::kValue:
- if (drop_count > 1) {
- __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
- }
- __ str(source, MemOperand(sp));
- break;
- case Expression::kTest:
- ASSERT(!source.is(sp));
- __ add(sp, sp, Operand(drop_count * kPointerSize));
- TestAndBranch(source, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (drop_count > 1) {
- __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
- }
- __ str(source, MemOperand(sp));
- TestAndBranch(source, true_label_, &discard);
- __ bind(&discard);
- __ pop();
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (drop_count > 1) {
- __ add(sp, sp, Operand((drop_count - 1) * kPointerSize));
- }
- __ str(source, MemOperand(sp));
- TestAndBranch(source, &discard, false_label_);
- __ bind(&discard);
- __ pop();
- __ jmp(true_label_);
- break;
- }
- }
-}
-
-
void FastCodeGenerator::TestAndBranch(Register source,
Label* true_label,
Label* false_label) {
// Value in r0 is ignored (declarations are statements). Receiver
// and key on stack are discarded.
- __ add(sp, sp, Operand(2 * kPointerSize));
+ __ Drop(2);
}
}
}
__ mov(r0, Operand(boilerplate));
__ stm(db_w, sp, cp.bit() | r0.bit());
__ CallRuntime(Runtime::kNewClosure, 2);
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
}
__ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
- DropAndMove(context, r0);
+ DropAndApply(1, context, r0);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
break;
}
}
- Move(context, slot, r0);
+ Apply(context, slot, r0);
} else {
- // A variable has been rewritten into an explicit access to
- // an object property.
+ Comment cmnt(masm_, "Variable rewritten to property");
+ // A variable has been rewritten into an explicit access to an object
+ // property.
Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property);
- // Currently the only parameter expressions that can occur are
- // on the form "slot[literal]".
+ // The only property expressions that can occur are of the form
+ // "slot[literal]".
- // Check that the object is in a slot.
+ // Assert that the object is in a slot.
Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object_var);
Slot* object_slot = object_var->slot();
// Load the object.
Move(r2, object_slot);
- // Check that the key is a smi.
+ // Assert that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Push both as arguments to ic.
__ stm(db_w, sp, r2.bit() | r1.bit());
- // Do a KEYED property load.
+ // Do a keyed property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC, and push the result.
- DropAndMove(context, r0, 2);
+ DropAndApply(2, context, r0);
}
}
__ stm(db_w, sp, r4.bit() | r3.bit() | r2.bit() | r1.bit());
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
__ bind(&done);
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ pop();
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(r0);
if (!result_saved) __ push(r0);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(r0);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(true_label_);
break;
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ pop();
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(r0);
if (!result_saved) __ push(r0);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(r0);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(true_label_);
break;
}
__ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Move(context, r0);
+ Apply(context, r0);
}
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Move(context, r0);
+ Apply(context, r0);
}
GenericBinaryOpStub stub(op,
NO_OVERWRITE);
__ CallStub(&stub);
- Move(context, r0);
+ Apply(context, r0);
}
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed.
- DropAndMove(context, r0);
+ DropAndApply(1, context, r0);
} else if (var->slot() != NULL) {
Slot* slot = var->slot();
__ str(r0, target);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(false_label_);
break;
}
__ str(r0, target);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
- __ pop();
+ __ Drop(1);
__ jmp(true_label_);
break;
}
__ RecordWrite(r1, r2, r0);
__ bind(&exit);
if (context != Expression::kEffect && context != Expression::kValue) {
- Move(context, r3);
+ Apply(context, r3);
}
break;
}
__ pop(r0);
}
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
}
}
// Receiver and key are still on stack.
- __ add(sp, sp, Operand(2 * kPointerSize));
- Move(expr->context(), r0);
+ DropAndApply(2, expr->context(), r0);
}
void FastCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
- uint32_t dummy;
// Record the source position for the property load.
SetSourcePosition(expr->position());
// Evaluate receiver.
Visit(expr->obj());
- if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
- !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
- // Do a NAMED property load.
- // The IC expects the property name in r2 and the receiver on the stack.
+ if (key->IsPropertyName()) {
+ // Do a named property load. The IC expects the property name in r2 and
+ // the receiver on the stack.
__ mov(r2, Operand(key->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
+ DropAndApply(1, expr->context(), r0);
} else {
- // Do a KEYED property load.
+ // Do a keyed property load.
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and receiver left on the stack by IC.
- __ pop();
+ DropAndApply(2, expr->context(), r0);
}
- DropAndMove(expr->context(), r0);
}
void FastCodeGenerator::EmitCallWithIC(Call* expr,
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
}
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
}
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in r0, or pop it.
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
}
// Restore context register.
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
} else {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
}
}
}
__ CallRuntime(Runtime::kTypeof, 1);
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
break;
}
// For all contexts except kEffect: We have the result on
// top of the stack.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
if (expr->is_postfix()) {
__ Drop(1); // Result is on the stack under the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), r0);
+ DropAndApply(1, expr->context(), r0);
}
break;
}
if (expr->is_postfix()) {
__ Drop(2); // Result is on the stack under the key and the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), r0, 2);
+ DropAndApply(2, expr->context(), r0);
}
break;
}
GenericBinaryOpStub stub(expr->op(),
NO_OVERWRITE);
__ CallStub(&stub);
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
break;
}
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
- Move(expr->context(), r0);
+ Apply(expr->context(), r0);
}
}
-void MacroAssembler::Drop(int stack_elements, Condition cond) {
- if (stack_elements > 0) {
- add(sp, sp, Operand(stack_elements * kPointerSize), LeaveCC, cond);
+void MacroAssembler::Drop(int count, Condition cond) {
+ if (count > 0) {
+ add(sp, sp, Operand(count * kPointerSize), LeaveCC, cond);
}
}
void Call(byte* target, RelocInfo::Mode rmode, Condition cond = al);
void Call(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
void Ret(Condition cond = al);
- void Drop(int stack_elements, Condition cond = al);
+
+ // Emit code to discard a non-negative number of pointer-sized elements
+ // from the stack, clobbering only the sp register.
+ void Drop(int count, Condition cond = al);
+
void Call(Label* target);
void Move(Register dst, Handle<Object> value);
// Jumps to the label at the index given by the Smi in "index".
virtual bool IsValidJSON() { return false; }
virtual bool IsValidLeftHandSide() { return false; }
+ // Symbols that cannot be parsed as array indices are considered property
+ // names. We do not treat symbols that can be array indexes as property
+ // names because [] for string objects is handled only by keyed ICs.
+ virtual bool IsPropertyName() { return false; }
+
// Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
virtual bool IsValidJSON() { return true; }
+ virtual bool IsPropertyName() {
+ if (handle_->IsSymbol()) {
+ uint32_t ignored;
+ return !String::cast(*handle_)->AsArrayIndex(&ignored);
+ }
+ return false;
+ }
+
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
// We will only visit the key during code generation for keyed property
// stores. Leave its expression context uninitialized for named
// property stores.
- Literal* lit = prop->key()->AsLiteral();
- uint32_t ignored;
- if (lit == NULL ||
- !lit->handle()->IsSymbol() ||
- String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
+ if (!prop->key()->IsPropertyName()) {
ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT;
}
// We will only visit the key during code generation for keyed property
// stores. Leave its expression context uninitialized for named
// property stores.
- Literal* lit = prop->key()->AsLiteral();
- uint32_t ignored;
- if (lit == NULL ||
- !lit->handle()->IsSymbol() ||
- String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
+ if (!prop->key()->IsPropertyName()) {
ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT;
}
}
+void FastCodeGenerator::Apply(Expression::Context context, Register reg) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ break;
+ case Expression::kValue:
+ __ push(reg);
+ break;
+ case Expression::kTest:
+ TestAndBranch(reg, true_label_, false_label_);
+ break;
+ case Expression::kValueTest: {
+ Label discard;
+ __ push(reg);
+ TestAndBranch(reg, true_label_, &discard);
+ __ bind(&discard);
+ __ Drop(1);
+ __ jmp(false_label_);
+ break;
+ }
+ case Expression::kTestValue: {
+ Label discard;
+ __ push(reg);
+ TestAndBranch(reg, &discard, false_label_);
+ __ bind(&discard);
+ __ Drop(1);
+ __ jmp(true_label_);
+ }
+ }
+}
+
+
void FastCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
- Move(expr->context(), expr);
+ Apply(expr->context(), expr);
}
int SlotOffset(Slot* slot);
- void Move(Expression::Context destination, Register source);
- void MoveTOS(Expression::Context destination);
- void Move(Expression::Context destination, Slot* source, Register scratch);
- void Move(Expression::Context destination, Literal* source);
+
+ // Emit code to complete the evaluation of an expression based on its
+ // expression context and given its value is in a register, non-lookup
+ // slot, or a literal.
+ void Apply(Expression::Context context, Register reg);
+ void Apply(Expression::Context context, Slot* slot, Register scratch);
+ void Apply(Expression::Context context, Literal* lit);
+
+ // Emit code to complete the evaluation of an expression based on its
+ // expression context and given its value is on top of the stack.
+ void ApplyTOS(Expression::Context context);
+
+ // Emit code to discard count elements from the top of stack, then
+ // complete the evaluation of an expression based on its expression
+ // context and given its value is in a register.
+ void DropAndApply(int count, Expression::Context context, Register reg);
+
void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
void Move(Register dst, Slot* source);
// register.
MemOperand EmitSlotSearch(Slot* slot, Register scratch);
- // Drop the TOS, and store source to destination.
- // If destination is TOS, just overwrite TOS with source.
- void DropAndMove(Expression::Context destination,
- Register source,
- int drop_count = 1);
-
// Test the JavaScript value in source as if in a test context, compile
// control flow to a pair of labels.
void TestAndBranch(Register source, Label* true_label, Label* false_label);
// The expression is either a property or a variable proxy that rewrites
// to a property.
Load(property->obj());
- // We use a named reference if the key is a literal symbol, unless it is
- // a string that can be legally parsed as an integer. This is because
- // otherwise we will not get into the slow case code that handles [] on
- // String objects.
- Literal* literal = property->key()->AsLiteral();
- uint32_t dummy;
- if (literal != NULL &&
- literal->handle()->IsSymbol() &&
- !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+ if (property->key()->IsPropertyName()) {
ref->set_type(Reference::NAMED);
} else {
Load(property->key());
}
-void FastCodeGenerator::Move(Expression::Context context, Register source) {
+void FastCodeGenerator::Apply(Expression::Context context,
+ Slot* slot,
+ Register scratch) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
+ case Expression::kValue: {
+ MemOperand location = EmitSlotSearch(slot, scratch);
+ __ push(location);
+ break;
+ }
+ case Expression::kTest:
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ Move(scratch, slot);
+ Apply(context, scratch);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ break;
+ case Expression::kValue:
+ __ push(Immediate(lit->handle()));
+ break;
+ case Expression::kTest:
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ __ mov(eax, lit->handle());
+ Apply(context, eax);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::ApplyTOS(Expression::Context context) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ __ Drop(1);
+ break;
case Expression::kValue:
- __ push(source);
break;
case Expression::kTest:
- TestAndBranch(source, true_label_, false_label_);
+ __ pop(eax);
+ TestAndBranch(eax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ push(source);
- TestAndBranch(source, true_label_, &discard);
+ __ mov(eax, Operand(esp, 0));
+ TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
- __ push(source);
- TestAndBranch(source, &discard, false_label_);
+ __ mov(eax, Operand(esp, 0));
+ TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
}
}
}
-void FastCodeGenerator::MoveTOS(Expression::Context context) {
+void FastCodeGenerator::DropAndApply(int count,
+ Expression::Context context,
+ Register reg) {
+ ASSERT(count > 0);
+ ASSERT(!reg.is(esp));
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- __ Drop(1);
+ __ Drop(count);
break;
case Expression::kValue:
+ if (count > 1) __ Drop(count - 1);
+ __ mov(Operand(esp, 0), reg);
break;
case Expression::kTest:
- __ pop(eax);
- TestAndBranch(eax, true_label_, false_label_);
+ __ Drop(count);
+ TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ mov(eax, Operand(esp, 0));
- TestAndBranch(eax, true_label_, &discard);
+ if (count > 1) __ Drop(count - 1);
+ __ mov(Operand(esp, 0), reg);
+ TestAndBranch(reg, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
}
case Expression::kTestValue: {
Label discard;
- __ mov(eax, Operand(esp, 0));
- TestAndBranch(eax, &discard, false_label_);
+ if (count > 1) __ Drop(count - 1);
+ __ mov(Operand(esp, 0), reg);
+ TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
+ break;
}
}
}
}
-void FastCodeGenerator::Move(Expression::Context context,
- Slot* source,
- Register scratch) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue: {
- MemOperand location = EmitSlotSearch(source, scratch);
- __ push(location);
- break;
- }
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- Move(scratch, source);
- Move(context, scratch);
- break;
- }
-}
-
-
-void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue:
- __ push(Immediate(expr->handle()));
- break;
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- __ mov(eax, expr->handle());
- Move(context, eax);
- break;
- }
-}
-
-
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
}
-void FastCodeGenerator::DropAndMove(Expression::Context context,
- Register source,
- int count) {
- ASSERT(count > 0);
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- __ add(Operand(esp), Immediate(count * kPointerSize));
- break;
- case Expression::kValue:
- if (count > 1) {
- __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
- }
- __ mov(Operand(esp, 0), source);
- break;
- case Expression::kTest:
- ASSERT(!source.is(esp));
- __ add(Operand(esp), Immediate(count * kPointerSize));
- TestAndBranch(source, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (count > 1) {
- __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
- }
- __ mov(Operand(esp, 0), source);
- TestAndBranch(source, true_label_, &discard);
- __ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (count > 1) {
- __ add(Operand(esp), Immediate((count - 1) * kPointerSize));
- }
- __ mov(Operand(esp, 0), source);
- TestAndBranch(source, &discard, false_label_);
- __ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
- __ jmp(true_label_);
- break;
- }
- }
-}
-
-
void FastCodeGenerator::TestAndBranch(Register source,
Label* true_label,
Label* false_label) {
// Value in eax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
- __ add(Operand(esp), Immediate(2 * kPointerSize));
+ __ Drop(2);
}
}
}
__ push(esi);
__ push(Immediate(boilerplate));
__ CallRuntime(Runtime::kNewClosure, 2);
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
}
// Remember that the assembler may choose to do peephole optimization
// (eg, push/pop elimination).
__ nop();
- DropAndMove(context, eax);
+ DropAndApply(1, context, eax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
break;
}
}
- Move(context, slot, eax);
+ Apply(context, slot, eax);
} else {
- Comment cmnt(masm_, "Variable rewritten to Property");
- // A variable has been rewritten into an explicit access to
- // an object property.
+ Comment cmnt(masm_, "Variable rewritten to property");
+ // A variable has been rewritten into an explicit access to an object
+ // property.
Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property);
- // Currently the only parameter expressions that can occur are
- // on the form "slot[literal]".
+ // The only property expressions that can occur are of the form
+ // "slot[literal]".
- // Check that the object is in a slot.
+ // Assert that the object is in a slot.
Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object_var);
Slot* object_slot = object_var->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
- Move(Expression::kValue, object_slot, eax);
+ MemOperand object_loc = EmitSlotSearch(object_slot, eax);
+ __ push(object_loc);
- // Check that the key is a smi.
+ // Assert that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
- Move(Expression::kValue, key_literal);
+ __ push(Immediate(key_literal->handle()));
- // Do a KEYED property load.
+ // Do a keyed property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
- // Notice: We must not have a "test eax, ..." instruction after
- // the call. It is treated specially by the LoadIC code.
+ // Notice: We must not have a "test eax, ..." instruction after the
+ // call. It is treated specially by the LoadIC code.
__ nop();
// Drop key and object left on the stack by IC.
- DropAndMove(context, eax, 2);
+ DropAndApply(2, context, eax);
}
}
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
// Label done:
__ bind(&done);
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ add(Operand(esp), Immediate(kPointerSize));
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(eax);
if (!result_saved) __ push(eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop (1);
__ jmp(true_label_);
break;
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ add(Operand(esp), Immediate(kPointerSize));
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(eax);
if (!result_saved) __ push(eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
break;
}
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
- Move(context, eax);
+ Apply(context, eax);
}
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
- Move(context, eax);
+ Apply(context, eax);
}
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
- Move(context, eax);
+ Apply(context, eax);
}
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Overwrite the receiver on the stack with the result if needed.
- DropAndMove(context, eax);
+ DropAndApply(1, context, eax);
} else if (var->slot() != NULL) {
Slot* slot = var->slot();
__ mov(target, eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
__ mov(target, eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
break;
}
}
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(ecx, offset, eax, ebx);
- if (context != Expression::kEffect &&
- context != Expression::kValue) {
- Move(context, edx);
+ if (context != Expression::kEffect && context != Expression::kValue) {
+ Apply(context, edx);
}
break;
}
__ pop(eax);
}
- DropAndMove(expr->context(), eax);
+ DropAndApply(1, expr->context(), eax);
}
}
// Receiver and key are still on stack.
- __ add(Operand(esp), Immediate(2 * kPointerSize));
- Move(expr->context(), eax);
+ DropAndApply(2, expr->context(), eax);
}
void FastCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
- uint32_t dummy;
// Record the source position for the property load.
SetSourcePosition(expr->position());
- // Evaluate receiver.
+ // Evaluate the receiver.
Visit(expr->obj());
- if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
- !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
- // Do a NAMED property load.
- // The IC expects the property name in ecx and the receiver on the stack.
+ if (key->IsPropertyName()) {
+ // Do a named property load. The IC expects the property name in ecx
+ // and the receiver on the stack.
__ mov(ecx, Immediate(key->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a test eax
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
+ DropAndApply(1, expr->context(), eax);
} else {
- // Do a KEYED property load.
+ // Do a keyed property load.
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
- __ add(Operand(esp), Immediate(kPointerSize));
+ DropAndApply(2, expr->context(), eax);
}
- DropAndMove(expr->context(), eax);
}
__ call(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
}
__ CallStub(&stub);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
- DropAndMove(expr->context(), eax);
+ DropAndApply(1, expr->context(), eax);
}
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
- __ add(Operand(esp), Immediate(kPointerSize));
+ __ Drop(1);
// Pop receiver.
__ pop(ebx);
// Push result (function).
__ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in eax, or pop it.
- DropAndMove(expr->context(), eax);
+ DropAndApply(1, expr->context(), eax);
}
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
}
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
}
}
__ CallRuntime(Runtime::kTypeof, 1);
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
break;
}
// For all contexts except kEffect: We have the result on
// top of the stack.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
if (expr->is_postfix()) {
__ Drop(1); // Result is on the stack under the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), eax);
+ DropAndApply(1, expr->context(), eax);
}
break;
}
if (expr->is_postfix()) {
__ Drop(2); // Result is on the stack under the key and the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), eax, 2);
+ DropAndApply(2, expr->context(), eax);
}
break;
}
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
break;
}
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
- Move(expr->context(), eax);
+ Apply(expr->context(), eax);
}
void Ret();
+ // Emit code to discard a non-negative number of pointer-sized elements
+ // from the stack, clobbering only the esp register.
void Drop(int element_count);
void Call(Label* target) { call(target); }
// The expression is either a property or a variable proxy that rewrites
// to a property.
Load(property->obj());
- // We use a named reference if the key is a literal symbol, unless it is
- // a string that can be legally parsed as an integer. This is because
- // otherwise we will not get into the slow case code that handles [] on
- // String objects.
- Literal* literal = property->key()->AsLiteral();
- uint32_t dummy;
- if (literal != NULL &&
- literal->handle()->IsSymbol() &&
- !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
+ if (property->key()->IsPropertyName()) {
ref->set_type(Reference::NAMED);
} else {
Load(property->key());
}
-void FastCodeGenerator::Move(Expression::Context context, Register source) {
+void FastCodeGenerator::Apply(Expression::Context context,
+ Slot* slot,
+ Register scratch) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ break;
+ case Expression::kValue: {
+ MemOperand location = EmitSlotSearch(slot, scratch);
+ __ push(location);
+ break;
+ }
+ case Expression::kTest:
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ Move(scratch, slot);
+ Apply(context, scratch);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
- __ push(source);
+ __ Push(lit->handle());
break;
case Expression::kTest:
- TestAndBranch(source, true_label_, false_label_);
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ __ Move(rax, lit->handle());
+ Apply(context, rax);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::ApplyTOS(Expression::Context context) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ __ Drop(1);
+ break;
+ case Expression::kValue:
+ break;
+ case Expression::kTest:
+ __ pop(rax);
+ TestAndBranch(rax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ push(source);
- TestAndBranch(source, true_label_, &discard);
+ __ movq(rax, Operand(rsp, 0));
+ TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
- __ push(source);
- TestAndBranch(source, &discard, false_label_);
+ __ movq(rax, Operand(rsp, 0));
+ TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
- break;
}
}
}
-void FastCodeGenerator::MoveTOS(Expression::Context context) {
+void FastCodeGenerator::DropAndApply(int count,
+ Expression::Context context,
+ Register reg) {
+ ASSERT(count > 0);
+ ASSERT(!reg.is(rsp));
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- __ Drop(1);
+ __ Drop(count);
break;
case Expression::kValue:
+ if (count > 1) __ Drop(count - 1);
+ __ movq(Operand(rsp, 0), reg);
break;
case Expression::kTest:
- __ pop(rax);
- TestAndBranch(rax, true_label_, false_label_);
+ __ Drop(count);
+ TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
- __ movq(rax, Operand(rsp, 0));
- TestAndBranch(rax, true_label_, &discard);
+ if (count > 1) __ Drop(count - 1);
+ __ movq(Operand(rsp, 0), reg);
+ TestAndBranch(reg, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
}
case Expression::kTestValue: {
Label discard;
- __ movq(rax, Operand(rsp, 0));
- TestAndBranch(rax, &discard, false_label_);
+ if (count > 1) __ Drop(count - 1);
+ __ movq(Operand(rsp, 0), reg);
+ TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
+ break;
}
}
}
}
-void FastCodeGenerator::Move(Expression::Context context,
- Slot* source,
- Register scratch) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue: {
- MemOperand location = EmitSlotSearch(source, scratch);
- __ push(location);
- break;
- }
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- Move(scratch, source);
- Move(context, scratch);
- break;
- }
-}
-
-
-void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- break;
- case Expression::kValue:
- __ Push(expr->handle());
- break;
- case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
- __ Move(rax, expr->handle());
- Move(context, rax);
- break;
- }
-}
-
-
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
}
-void FastCodeGenerator::DropAndMove(Expression::Context context,
- Register source,
- int drop_count) {
- ASSERT(drop_count > 0);
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- __ addq(rsp, Immediate(drop_count * kPointerSize));
- break;
- case Expression::kValue:
- if (drop_count > 1) {
- __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
- }
- __ movq(Operand(rsp, 0), source);
- break;
- case Expression::kTest:
- ASSERT(!source.is(rsp));
- __ addq(rsp, Immediate(drop_count * kPointerSize));
- TestAndBranch(source, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (drop_count > 1) {
- __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
- }
- __ movq(Operand(rsp, 0), source);
- TestAndBranch(source, true_label_, &discard);
- __ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ movq(Operand(rsp, 0), source);
- TestAndBranch(source, &discard, false_label_);
- __ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
- __ jmp(true_label_);
- break;
- }
- }
-}
-
-
void FastCodeGenerator::TestAndBranch(Register source,
Label* true_label,
Label* false_label) {
// Value in rax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
- __ addq(rsp, Immediate(2 * kPointerSize));
+ __ Drop(2);
}
}
}
__ push(rsi);
__ Push(boilerplate);
__ CallRuntime(Runtime::kNewClosure, 2);
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
}
// is no test rax instruction here.
__ nop();
- DropAndMove(context, rax);
+ DropAndApply(1, context, rax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
break;
}
}
- Move(context, slot, rax);
+ Apply(context, slot, rax);
} else {
- // A variable has been rewritten into an explicit access to
- // an object property.
+ Comment cmnt(masm_, "Variable rewritten to property");
+ // A variable has been rewritten into an explicit access to an object
+ // property.
Property* property = rewrite->AsProperty();
ASSERT_NOT_NULL(property);
- // Currently the only parameter expressions that can occur are
- // on the form "slot[literal]".
+ // The only property expressions that can occur are of the form
+ // "slot[literal]".
- // Check that the object is in a slot.
+ // Assert that the object is in a slot.
Variable* object = property->obj()->AsVariableProxy()->AsVariable();
ASSERT_NOT_NULL(object);
Slot* object_slot = object->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
- Move(Expression::kValue, object_slot, rax);
+ MemOperand object_loc = EmitSlotSearch(object_slot, rax);
+ __ push(object_loc);
- // Check that the key is a smi.
+ // Assert that the key is a smi.
Literal* key_literal = property->key()->AsLiteral();
ASSERT_NOT_NULL(key_literal);
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
- Move(Expression::kValue, key_literal);
+ __ Push(key_literal->handle());
- // Do a KEYED property load.
+ // Do a keyed property load.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
- // Notice: We must not have a "test rax, ..." instruction after
- // the call. It is treated specially by the LoadIC code.
+ // Notice: We must not have a "test rax, ..." instruction after the
+ // call. It is treated specially by the LoadIC code.
// Drop key and object left on the stack by IC, and push the result.
- DropAndMove(context, rax, 2);
+ DropAndApply(2, context, rax);
}
}
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
// Label done:
__ bind(&done);
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ addq(rsp, Immediate(kPointerSize));
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(rax);
if (!result_saved) __ push(rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
break;
}
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
- if (result_saved) __ addq(rsp, Immediate(kPointerSize));
+ if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(rax);
if (!result_saved) __ push(rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
if (!result_saved) __ push(rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
break;
}
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Move(context, rax);
+ Apply(context, rax);
}
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Move(context, rax);
+ Apply(context, rax);
}
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
- Move(context, rax);
+ Apply(context, rax);
}
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed.
- DropAndMove(context, rax);
+ DropAndApply(1, context, rax);
} else if (var->slot() != NULL) {
Slot* slot = var->slot();
__ movq(target, rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(false_label_);
break;
}
__ movq(target, rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
__ jmp(true_label_);
break;
}
}
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(rcx, offset, rax, rbx);
- if (context != Expression::kEffect &&
- context != Expression::kValue) {
- Move(context, rdx);
+ if (context != Expression::kEffect && context != Expression::kValue) {
+ Apply(context, rdx);
}
break;
}
__ pop(rax);
}
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
}
}
// Receiver and key are still on stack.
- __ addq(rsp, Immediate(2 * kPointerSize));
- Move(expr->context(), rax);
+ DropAndApply(2, expr->context(), rax);
}
void FastCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
- uint32_t dummy;
// Record the source position for the property load.
SetSourcePosition(expr->position());
// Evaluate receiver.
Visit(expr->obj());
-
- if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
- !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
- // Do a NAMED property load.
- // The IC expects the property name in rcx and the receiver on the stack.
+ if (key->IsPropertyName()) {
+ // Do a named property load. The IC expects the property name in rcx
+ // and the receiver on the stack.
__ Move(rcx, key->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a "test rax,..."
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
+ DropAndApply(1, expr->context(), rax);
} else {
- // Do a KEYED property load.
+ // Do a keyed property load.
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
- // Notice: We must not have a "test rax, ..." instruction after
- // the call. It is treated specially by the LoadIC code.
-
- // Drop key left on the stack by IC.
- __ addq(rsp, Immediate(kPointerSize));
+ // Notice: We must not have a "test rax, ..." instruction after the
+ // call. It is treated specially by the LoadIC code.
+ __ nop();
+ // Drop key and receiver left on the stack by IC.
+ DropAndApply(2, expr->context(), rax);
}
- DropAndMove(expr->context(), rax);
}
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
}
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
}
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
- __ addq(rsp, Immediate(kPointerSize));
+ __ Drop(1);
// Pop receiver.
__ pop(rbx);
// Push result (function).
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in rax, or pop it.
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
}
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
} else {
__ CallRuntime(expr->function(), arg_count);
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
}
}
}
__ CallRuntime(Runtime::kTypeof, 1);
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
break;
}
// For all contexts except kEffect: We have the result on
// top of the stack.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
if (expr->is_postfix()) {
__ Drop(1); // Result is on the stack under the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), rax);
+ DropAndApply(1, expr->context(), rax);
}
break;
}
if (expr->is_postfix()) {
__ Drop(2); // Result is on the stack under the key and the receiver.
if (expr->context() != Expression::kEffect) {
- MoveTOS(expr->context());
+ ApplyTOS(expr->context());
}
} else {
- DropAndMove(expr->context(), rax, 2);
+ DropAndApply(2, expr->context(), rax);
}
break;
}
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
break;
}
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
- Move(expr->context(), rax);
+ Apply(expr->context(), rax);
}
void Cmp(Register dst, Handle<Object> source);
void Cmp(const Operand& dst, Handle<Object> source);
void Push(Handle<Object> source);
+
+ // Emit code to discard a non-negative number of pointer-sized elements
+ // from the stack, clobbering only the rsp register.
void Drop(int stack_elements);
+
void Call(Label* target) { call(target); }
// Control Flow