Some cleanup of the toplevel code generator:

* Rename the operation of filling a context with a value.  Formerly it
  was 'Move', now it's 'Apply' so as to avoid confusion with various
  other Moves (eg, in the toplevel codegen, in the macro assemblers).

* Use the abstraction Drop rather than math on the stack pointer.

* Add a predicate on AST expression nodes to abstract a repeated test
  whether we should us a regular (named) IC or a keyed IC.

Review URL: http://codereview.chromium.org/546006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3580 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2010-01-12 08:48:26 +00:00
parent 55b73d9415
commit f0b8c2d97a
14 changed files with 459 additions and 551 deletions

View File

@ -614,15 +614,7 @@ void CodeGenerator::LoadReference(Reference* ref) {
// 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());

View File

@ -214,40 +214,43 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
}
void FastCodeGenerator::Move(Expression::Context context, Register source) {
void FastCodeGenerator::Apply(Expression::Context context,
Slot* slot,
Register scratch) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue:
__ push(source);
break;
case Expression::kTest:
TestAndBranch(source, true_label_, false_label_);
case Expression::kValueTest:
case Expression::kTestValue:
Move(scratch, slot);
Apply(context, scratch);
break;
case Expression::kValueTest: {
Label discard;
__ push(source);
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
__ pop();
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ push(source);
TestAndBranch(source, &discard, false_label_);
__ bind(&discard);
__ pop();
__ jmp(true_label_);
}
}
}
void FastCodeGenerator::MoveTOS(Expression::Context context) {
void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
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(lit->handle()));
Apply(context, ip);
break;
}
}
void FastCodeGenerator::ApplyTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
@ -281,6 +284,49 @@ 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(count);
break;
case Expression::kValue:
if (count > 1) __ Drop(count - 1);
__ str(reg, MemOperand(sp));
break;
case Expression::kTest:
__ Drop(count);
TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
if (count > 1) __ Drop(count - 1);
__ str(reg, MemOperand(sp));
TestAndBranch(reg, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
if (count > 1) __ Drop(count - 1);
__ str(reg, MemOperand(sp));
TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
}
}
}
MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
switch (slot->type()) {
case Slot::PARAMETER:
@ -308,42 +354,6 @@ void FastCodeGenerator::Move(Register destination, Slot* source) {
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,
@ -361,55 +371,6 @@ void FastCodeGenerator::Move(Slot* dst,
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) {
@ -524,7 +485,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
// Value in r0 is ignored (declarations are statements). Receiver
// and key on stack are discarded.
__ add(sp, sp, Operand(2 * kPointerSize));
__ Drop(2);
}
}
}
@ -555,7 +516,7 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
__ mov(r0, Operand(boilerplate));
__ stm(db_w, sp, cp.bit() | r0.bit());
__ CallRuntime(Runtime::kNewClosure, 2);
Move(expr->context(), r0);
Apply(expr->context(), r0);
}
@ -578,7 +539,7 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
__ 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) {
@ -597,17 +558,18 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
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();
@ -616,7 +578,7 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
// 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());
@ -627,12 +589,12 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
// 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);
}
}
@ -660,7 +622,7 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ 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);
}
@ -742,7 +704,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
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);
@ -756,7 +718,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(r0);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -765,7 +727,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(r0);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -824,7 +786,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
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);
@ -838,7 +800,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(r0);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -847,7 +809,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(r0);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -862,7 +824,7 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
__ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, r0);
Apply(context, r0);
}
@ -871,7 +833,7 @@ void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, r0);
Apply(context, r0);
}
@ -882,7 +844,7 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
GenericBinaryOpStub stub(op,
NO_OVERWRITE);
__ CallStub(&stub);
Move(context, r0);
Apply(context, r0);
}
@ -901,7 +863,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
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();
@ -934,7 +896,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ str(r0, target);
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -944,7 +906,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ str(r0, target);
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
__ pop();
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -976,7 +938,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ RecordWrite(r1, r2, r0);
__ bind(&exit);
if (context != Expression::kEffect && context != Expression::kValue) {
Move(context, r3);
Apply(context, r3);
}
break;
}
@ -1022,7 +984,7 @@ void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ pop(r0);
}
DropAndMove(expr->context(), r0);
DropAndApply(1, expr->context(), r0);
}
@ -1054,15 +1016,13 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
}
// 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());
@ -1070,22 +1030,21 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// 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,
@ -1107,7 +1066,7 @@ 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);
}
@ -1125,7 +1084,7 @@ void FastCodeGenerator::EmitCallWithStub(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);
}
@ -1234,7 +1193,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
__ 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);
}
@ -1265,11 +1224,11 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* 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);
} else {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
Move(expr->context(), r0);
Apply(expr->context(), r0);
}
}
@ -1398,7 +1357,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
}
__ CallRuntime(Runtime::kTypeof, 1);
Move(expr->context(), r0);
Apply(expr->context(), r0);
break;
}
@ -1499,7 +1458,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
// 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(),
@ -1513,10 +1472,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1526,10 +1485,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1573,7 +1532,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
GenericBinaryOpStub stub(expr->op(),
NO_OVERWRITE);
__ CallStub(&stub);
Move(expr->context(), r0);
Apply(expr->context(), r0);
break;
}
@ -1748,7 +1707,7 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Move(expr->context(), r0);
Apply(expr->context(), r0);
}

View File

@ -162,9 +162,9 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
}
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);
}
}

View File

@ -64,7 +64,11 @@ class MacroAssembler: public Assembler {
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".

View File

@ -187,6 +187,11 @@ class Expression: public AstNode {
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.
@ -707,6 +712,14 @@ class Literal: public Expression {
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()); }

View File

@ -902,11 +902,7 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
// 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;
}
@ -1030,11 +1026,7 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
// 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;
}

View File

@ -75,6 +75,39 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
}
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();
@ -624,7 +657,7 @@ void FastCodeGenerator::VisitSlot(Slot* expr) {
void FastCodeGenerator::VisitLiteral(Literal* expr) {
Comment cmnt(masm_, "[ Literal");
Move(expr->context(), expr);
Apply(expr->context(), expr);
}

View File

@ -212,10 +212,23 @@ class FastCodeGenerator: public AstVisitor {
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);
@ -224,12 +237,6 @@ class FastCodeGenerator: public AstVisitor {
// 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);

View File

@ -664,15 +664,7 @@ void CodeGenerator::LoadReference(Reference* ref) {
// 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());

View File

@ -194,40 +194,49 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
}
void FastCodeGenerator::Move(Expression::Context context, Register source) {
void FastCodeGenerator::Apply(Expression::Context context,
Slot* slot,
Register scratch) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue: {
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(Immediate(lit->handle()));
break;
case Expression::kTest:
TestAndBranch(source, true_label_, false_label_);
case Expression::kValueTest:
case Expression::kTestValue:
__ mov(eax, lit->handle());
Apply(context, eax);
break;
case Expression::kValueTest: {
Label discard;
__ push(source);
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ push(source);
TestAndBranch(source, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ jmp(true_label_);
}
}
}
void FastCodeGenerator::MoveTOS(Expression::Context context) {
void FastCodeGenerator::ApplyTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
@ -261,6 +270,49 @@ 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(count);
break;
case Expression::kValue:
if (count > 1) __ Drop(count - 1);
__ mov(Operand(esp, 0), reg);
break;
case Expression::kTest:
__ Drop(count);
TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
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_);
break;
}
case Expression::kTestValue: {
Label discard;
if (count > 1) __ Drop(count - 1);
__ mov(Operand(esp, 0), reg);
TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
}
}
}
MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
switch (slot->type()) {
case Slot::PARAMETER:
@ -286,48 +338,6 @@ void FastCodeGenerator::Move(Register destination, Slot* source) {
}
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,
@ -344,55 +354,6 @@ void FastCodeGenerator::Move(Slot* dst,
}
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) {
@ -518,7 +479,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
// Value in eax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
__ add(Operand(esp), Immediate(2 * kPointerSize));
__ Drop(2);
}
}
}
@ -548,7 +509,7 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
__ push(esi);
__ push(Immediate(boilerplate));
__ CallRuntime(Runtime::kNewClosure, 2);
Move(expr->context(), eax);
Apply(expr->context(), eax);
}
@ -575,7 +536,7 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
// Remember that the assembler may choose to do peephole optimization
// (eg, push/pop elimination).
__ nop();
DropAndMove(context, eax);
DropAndApply(1, context, eax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
@ -594,42 +555,43 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
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);
}
}
@ -657,7 +619,7 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
// Label done:
__ bind(&done);
Move(expr->context(), eax);
Apply(expr->context(), eax);
}
@ -733,7 +695,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
if (result_saved) __ add(Operand(esp), Immediate(kPointerSize));
if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(eax);
@ -747,7 +709,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -756,7 +718,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop (1);
__ jmp(true_label_);
break;
}
@ -812,7 +774,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
if (result_saved) __ add(Operand(esp), Immediate(kPointerSize));
if (result_saved) __ Drop(1);
break;
case Expression::kValue:
if (!result_saved) __ push(eax);
@ -826,7 +788,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -835,7 +797,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -850,7 +812,7 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
Move(context, eax);
Apply(context, eax);
}
@ -859,7 +821,7 @@ void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
Move(context, eax);
Apply(context, eax);
}
@ -869,7 +831,7 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(context, eax);
Apply(context, eax);
}
@ -887,7 +849,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
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();
@ -919,7 +881,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ mov(target, eax);
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -929,7 +891,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ mov(target, eax);
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -950,9 +912,8 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
}
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;
}
@ -996,7 +957,7 @@ void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ pop(eax);
}
DropAndMove(expr->context(), eax);
DropAndApply(1, expr->context(), eax);
}
@ -1029,34 +990,32 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
}
// Receiver and key are still on stack.
__ add(Operand(esp), Immediate(2 * kPointerSize));
Move(expr->context(), eax);
DropAndApply(2, expr->context(), eax);
}
void FastCodeGenerator::VisitProperty(Property* expr) {
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
uint32_t dummy;
// Record the source position for the property load.
SetSourcePosition(expr->position());
// Evaluate receiver.
// Evaluate the receiver.
Visit(expr->obj());
if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
!String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
// Do a NAMED property load.
// The IC expects the property name in ecx and the receiver on the stack.
if (key->IsPropertyName()) {
// Do a named property load. The IC expects the property name in ecx
// and the receiver on the stack.
__ mov(ecx, Immediate(key->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// By emitting a nop we make sure that we do not have a test eax
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
DropAndApply(1, expr->context(), eax);
} else {
// Do a KEYED property load.
// Do a keyed property load.
Visit(expr->key());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
@ -1064,9 +1023,8 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ add(Operand(esp), Immediate(kPointerSize));
DropAndApply(2, expr->context(), eax);
}
DropAndMove(expr->context(), eax);
}
@ -1088,7 +1046,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr,
__ call(ic, mode);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
Move(expr->context(), eax);
Apply(expr->context(), eax);
}
@ -1105,7 +1063,7 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) {
__ CallStub(&stub);
// Restore context register.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
DropAndMove(expr->context(), eax);
DropAndApply(1, expr->context(), eax);
}
@ -1146,7 +1104,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ add(Operand(esp), Immediate(kPointerSize));
__ Drop(1);
// Pop receiver.
__ pop(ebx);
// Push result (function).
@ -1214,7 +1172,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
__ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
// Replace function on TOS with result in eax, or pop it.
DropAndMove(expr->context(), eax);
DropAndApply(1, expr->context(), eax);
}
@ -1247,7 +1205,7 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
}
Move(expr->context(), eax);
Apply(expr->context(), eax);
}
@ -1369,7 +1327,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
}
__ CallRuntime(Runtime::kTypeof, 1);
Move(expr->context(), eax);
Apply(expr->context(), eax);
break;
}
@ -1469,7 +1427,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
// 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(),
@ -1486,10 +1444,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1502,10 +1460,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1548,7 +1506,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(expr->context(), eax);
Apply(expr->context(), eax);
break;
}
@ -1719,7 +1677,7 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
Move(expr->context(), eax);
Apply(expr->context(), eax);
}

View File

@ -368,6 +368,8 @@ class MacroAssembler: public Assembler {
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); }

View File

@ -4256,15 +4256,7 @@ void CodeGenerator::LoadReference(Reference* ref) {
// 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());

View File

@ -202,41 +202,49 @@ void FastCodeGenerator::EmitReturnSequence(int position) {
}
void FastCodeGenerator::Move(Expression::Context context, Register source) {
void FastCodeGenerator::Apply(Expression::Context context,
Slot* slot,
Register scratch) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
break;
case Expression::kValue: {
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;
case Expression::kValueTest: {
Label discard;
__ push(source);
TestAndBranch(source, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ push(source);
TestAndBranch(source, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(true_label_);
break;
}
}
}
void FastCodeGenerator::MoveTOS(Expression::Context context) {
void FastCodeGenerator::ApplyTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
@ -270,6 +278,49 @@ 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(count);
break;
case Expression::kValue:
if (count > 1) __ Drop(count - 1);
__ movq(Operand(rsp, 0), reg);
break;
case Expression::kTest:
__ Drop(count);
TestAndBranch(reg, true_label_, false_label_);
break;
case Expression::kValueTest: {
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_);
break;
}
case Expression::kTestValue: {
Label discard;
if (count > 1) __ Drop(count - 1);
__ movq(Operand(rsp, 0), reg);
TestAndBranch(reg, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
}
}
}
MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
switch (slot->type()) {
case Slot::PARAMETER:
@ -295,48 +346,6 @@ void FastCodeGenerator::Move(Register destination, Slot* source) {
}
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,
@ -353,52 +362,6 @@ void FastCodeGenerator::Move(Slot* dst,
}
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) {
@ -528,7 +491,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
// Value in rax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
__ addq(rsp, Immediate(2 * kPointerSize));
__ Drop(2);
}
}
}
@ -558,7 +521,7 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
__ push(rsi);
__ Push(boilerplate);
__ CallRuntime(Runtime::kNewClosure, 2);
Move(expr->context(), rax);
Apply(expr->context(), rax);
}
@ -585,7 +548,7 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
// 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) {
@ -604,41 +567,43 @@ void FastCodeGenerator::EmitVariableLoad(Variable* var,
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);
}
}
@ -666,7 +631,7 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
// Label done:
__ bind(&done);
Move(expr->context(), rax);
Apply(expr->context(), rax);
}
@ -742,7 +707,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
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);
@ -756,7 +721,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -765,7 +730,7 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (!result_saved) __ push(rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -821,7 +786,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
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);
@ -835,7 +800,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -844,7 +809,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
if (!result_saved) __ push(rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -859,7 +824,7 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, rax);
Apply(context, rax);
}
@ -868,7 +833,7 @@ void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, rax);
Apply(context, rax);
}
@ -878,7 +843,7 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(context, rax);
Apply(context, rax);
}
@ -896,7 +861,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
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();
@ -928,7 +893,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ movq(target, rax);
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(false_label_);
break;
}
@ -938,7 +903,7 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
__ movq(target, rax);
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
__ jmp(true_label_);
break;
}
@ -959,9 +924,8 @@ void FastCodeGenerator::EmitVariableAssignment(Variable* var,
}
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;
}
@ -1005,7 +969,7 @@ void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ pop(rax);
}
DropAndMove(expr->context(), rax);
DropAndApply(1, expr->context(), rax);
}
@ -1038,15 +1002,13 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
}
// 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());
@ -1054,29 +1016,27 @@ void FastCodeGenerator::VisitProperty(Property* expr) {
// 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);
}
@ -1099,7 +1059,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr,
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), rax);
DropAndApply(1, expr->context(), rax);
}
@ -1117,7 +1077,7 @@ void FastCodeGenerator::EmitCallWithStub(Call* expr) {
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
DropAndMove(expr->context(), rax);
DropAndApply(1, expr->context(), rax);
}
@ -1161,7 +1121,7 @@ void FastCodeGenerator::VisitCall(Call* expr) {
// instruction after the call it is treated specially by the LoadIC code.
__ nop();
// Drop key left on the stack by IC.
__ addq(rsp, Immediate(kPointerSize));
__ Drop(1);
// Pop receiver.
__ pop(rbx);
// Push result (function).
@ -1230,7 +1190,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
__ 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);
}
@ -1260,10 +1220,10 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
// 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);
}
}
@ -1386,7 +1346,7 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
}
__ CallRuntime(Runtime::kTypeof, 1);
Move(expr->context(), rax);
Apply(expr->context(), rax);
break;
}
@ -1486,7 +1446,7 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
// 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(),
@ -1503,10 +1463,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1519,10 +1479,10 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
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;
}
@ -1564,7 +1524,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(expr->context(), rax);
Apply(expr->context(), rax);
break;
}
@ -1732,7 +1692,7 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Move(expr->context(), rax);
Apply(expr->context(), rax);
}

View File

@ -415,7 +415,11 @@ class MacroAssembler: public Assembler {
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