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:
parent
55b73d9415
commit
f0b8c2d97a
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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".
|
||||
|
13
src/ast.h
13
src/ast.h
@ -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()); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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); }
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user