Added general pre- and postfix count operations to top-level compiler.

Until now we only supported postfix operations on global variables.
This change add generic count operations to the top-level compiler.

I tried to re-use code from the code generator used for assignment expressions
where possible.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3530 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 88ba93d9
...@@ -247,6 +247,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) { ...@@ -247,6 +247,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::MoveTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ Drop(1);
break;
case Expression::kValue:
break;
case Expression::kTest:
__ pop(r0);
TestAndBranch(r0, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ ldr(r0, MemOperand(sp, 0));
TestAndBranch(r0, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ ldr(r0, MemOperand(sp, 0));
TestAndBranch(r0, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
}
}
}
template <> template <>
MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>( MemOperand FastCodeGenerator::CreateSlotOperand<MemOperand>(
Slot* source, Slot* source,
...@@ -839,6 +873,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -839,6 +873,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
Expression::Context context) { Expression::Context context) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle())); __ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
...@@ -847,7 +882,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, ...@@ -847,7 +882,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
} }
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
Expression::Context context) {
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
Move(context, r0); Move(context, r0);
...@@ -865,8 +902,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, ...@@ -865,8 +902,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
} }
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { void FastCodeGenerator::EmitVariableAssignment(Variable* var,
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Expression::Context context) {
ASSERT(var != NULL); ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL); ASSERT(var->is_global() || var->slot() != NULL);
if (var->is_global()) { if (var->is_global()) {
...@@ -880,7 +917,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -880,7 +917,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(expr->context(), r0); DropAndMove(context, r0);
} else if (var->slot()) { } else if (var->slot()) {
Slot* slot = var->slot(); Slot* slot = var->slot();
...@@ -888,7 +925,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -888,7 +925,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
switch (slot->type()) { switch (slot->type()) {
case Slot::LOCAL: case Slot::LOCAL:
case Slot::PARAMETER: { case Slot::PARAMETER: {
switch (expr->context()) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
...@@ -953,9 +990,9 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -953,9 +990,9 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
__ str(r1, CodeGenerator::ContextOperand(r0, slot->index())); __ str(r1, CodeGenerator::ContextOperand(r0, slot->index()));
// RecordWrite may destroy all its register arguments. // RecordWrite may destroy all its register arguments.
if (expr->context() == Expression::kValue) { if (context == Expression::kValue) {
__ push(r1); __ push(r1);
} else if (expr->context() != Expression::kEffect) { } else if (context != Expression::kEffect) {
__ mov(r3, r1); __ mov(r3, r1);
} }
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
...@@ -970,9 +1007,9 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -970,9 +1007,9 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
__ mov(r2, Operand(offset)); __ mov(r2, Operand(offset));
__ RecordWrite(r0, r2, r1); __ RecordWrite(r0, r2, r1);
__ bind(&exit); __ bind(&exit);
if (expr->context() != Expression::kEffect && if (context != Expression::kEffect &&
expr->context() != Expression::kValue) { context != Expression::kValue) {
Move(expr->context(), r3); Move(context, r3);
} }
break; break;
} }
...@@ -1025,7 +1062,7 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { ...@@ -1025,7 +1062,7 @@ void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
// change to slow case to avoid the quadratic behavior of repeatedly // change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties. // adding fast properties.
if (expr->starts_initialization_block()) { if (expr->starts_initialization_block()) {
// Reciever is under the key and value. // Receiver is under the key and value.
__ ldr(ip, MemOperand(sp, 2 * kPointerSize)); __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
__ push(ip); __ push(ip);
__ CallRuntime(Runtime::kToSlowProperties, 1); __ CallRuntime(Runtime::kToSlowProperties, 1);
...@@ -1219,7 +1256,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) { ...@@ -1219,7 +1256,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* expr) {
// Load function, arg_count into r1 and r0. // Load function, arg_count into r1 and r0.
__ mov(r0, Operand(arg_count)); __ mov(r0, Operand(arg_count));
// Function is in esp[arg_count + 1]. // Function is in sp[arg_count + 1].
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
...@@ -1402,27 +1439,76 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1402,27 +1439,76 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy); // Expression can only be a property, a global or a (parameter or local)
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
Property* prop = expr->expression()->AsProperty();
// In case of a property we use the uninitialized expression context
// of the key to detect a named property.
if (prop != NULL) {
assign_type = (prop->key()->context() == Expression::kUninitialized)
? NAMED_PROPERTY
: KEYED_PROPERTY;
}
// Evaluate expression and get value.
if (assign_type == VARIABLE) {
ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
Expression::kValue);
} else {
// Reserve space for result of postfix operation.
if (expr->is_postfix() && expr->context() != Expression::kEffect) {
ASSERT(expr->context() != Expression::kUninitialized);
__ mov(ip, Operand(Smi::FromInt(0)));
__ push(ip);
}
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
if (assign_type == NAMED_PROPERTY) {
EmitNamedPropertyLoad(prop, Expression::kValue);
} else {
Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context());
EmitKeyedPropertyLoad(prop, Expression::kValue);
}
}
// Convert to number.
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
// Save result for postfix expressions.
if (expr->is_postfix()) {
switch (expr->context()) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect:
// Do not save result.
break;
case Expression::kValue: // Fall through case Expression::kValue: // Fall through
case Expression::kTest: // Fall through case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through case Expression::kTestValue: // Fall through
case Expression::kValueTest: case Expression::kValueTest:
// Duplicate the result on the stack. // Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(r0); __ push(r0);
break; break;
case Expression::kEffect: case NAMED_PROPERTY:
// Do not save result. __ str(r0, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ str(r0, MemOperand(sp, 2 * kPointerSize));
break; break;
} }
break;
}
}
// Call runtime for +1/-1. // Call runtime for +1/-1.
__ push(r0); __ push(r0);
__ mov(ip, Operand(Smi::FromInt(1))); __ mov(ip, Operand(Smi::FromInt(1)));
...@@ -1432,43 +1518,49 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -1432,43 +1518,49 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
} else { } else {
__ CallRuntime(Runtime::kNumberSub, 2); __ CallRuntime(Runtime::kNumberSub, 2);
} }
// Call Store IC.
__ mov(r2, Operand(proxy->AsVariable()->name()));
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC.
__ add(sp, sp, Operand(kPointerSize));
switch (expr->context()) { // Store the value returned in r0.
case Expression::kUninitialized: switch (assign_type) {
UNREACHABLE(); case VARIABLE:
case Expression::kEffect: // Fall through __ push(r0);
case Expression::kValue: if (expr->is_postfix()) {
// Do nothing. Result in either on the stack for value context EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
// or discarded for effect context. Expression::kEffect);
break; // For all contexts except kEffect: We have the result on
case Expression::kTest: // top of the stack.
__ pop(r0); if (expr->context() != Expression::kEffect) {
TestAndBranch(r0, true_label_, false_label_); MoveTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
expr->context());
}
break; break;
case Expression::kValueTest: { case NAMED_PROPERTY: {
Label discard; __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
__ ldr(r0, MemOperand(sp)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
TestAndBranch(r0, true_label_, &discard); __ Call(ic, RelocInfo::CODE_TARGET);
__ bind(&discard); if (expr->is_postfix()) {
__ add(sp, sp, Operand(kPointerSize)); __ Drop(1); // Result is on the stack under the receiver.
__ b(false_label_); if (expr->context() != Expression::kEffect) {
MoveTOS(expr->context());
}
} else {
DropAndMove(expr->context(), r0);
}
break; break;
} }
case Expression::kTestValue: { case KEYED_PROPERTY: {
Label discard; Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ ldr(r0, MemOperand(sp)); __ Call(ic, RelocInfo::CODE_TARGET);
TestAndBranch(r0, &discard, false_label_); if (expr->is_postfix()) {
__ bind(&discard); __ Drop(2); // Result is on the stack under the key and the receiver.
__ add(sp, sp, Operand(kPointerSize)); if (expr->context() != Expression::kEffect) {
__ b(true_label_); MoveTOS(expr->context());
}
} else {
DropAndMove(expr->context(), r0, 2);
}
break; break;
} }
} }
......
...@@ -649,12 +649,6 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) { ...@@ -649,12 +649,6 @@ void CodeGenSelector::VisitStatements(ZoneList<Statement*>* stmts) {
void CodeGenSelector::VisitDeclaration(Declaration* decl) { void CodeGenSelector::VisitDeclaration(Declaration* decl) {
Property* prop = decl->proxy()->AsProperty(); Property* prop = decl->proxy()->AsProperty();
if (prop != NULL) { if (prop != NULL) {
// Property rewrites are shared, ensure we are not changing its
// expression context state.
ASSERT(prop->obj()->context() == Expression::kUninitialized ||
prop->obj()->context() == Expression::kValue);
ASSERT(prop->key()->context() == Expression::kUninitialized ||
prop->key()->context() == Expression::kValue);
ProcessExpression(prop->obj(), Expression::kValue); ProcessExpression(prop->obj(), Expression::kValue);
ProcessExpression(prop->key(), Expression::kValue); ProcessExpression(prop->key(), Expression::kValue);
} }
...@@ -903,8 +897,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { ...@@ -903,8 +897,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
} }
} }
} else if (prop != NULL) { } else if (prop != NULL) {
ASSERT(prop->obj()->context() == Expression::kUninitialized ||
prop->obj()->context() == Expression::kValue);
ProcessExpression(prop->obj(), Expression::kValue); ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT; CHECK_BAILOUT;
// We will only visit the key during code generation for keyed property // We will only visit the key during code generation for keyed property
...@@ -915,8 +907,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) { ...@@ -915,8 +907,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
if (lit == NULL || if (lit == NULL ||
!lit->handle()->IsSymbol() || !lit->handle()->IsSymbol() ||
String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) { String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
ASSERT(prop->key()->context() == Expression::kUninitialized ||
prop->key()->context() == Expression::kValue);
ProcessExpression(prop->key(), Expression::kValue); ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT; CHECK_BAILOUT;
} }
...@@ -1022,11 +1012,36 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1022,11 +1012,36 @@ void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
void CodeGenSelector::VisitCountOperation(CountOperation* expr) { void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
// We support postfix count operations on global variables.
if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement"); Property* prop = expr->expression()->AsProperty();
ProcessExpression(expr->expression(), Expression::kValue); ASSERT(var == NULL || prop == NULL);
if (var != NULL) {
// All global variables are supported.
if (!var->is_global()) {
ASSERT(var->slot() != NULL);
Slot::Type type = var->slot()->type();
if (type == Slot::LOOKUP) {
BAILOUT("CountOperation with lookup slot");
}
}
} else if (prop != NULL) {
ProcessExpression(prop->obj(), Expression::kValue);
CHECK_BAILOUT;
// We will only visit the key during code generation for keyed property
// stores. Leave its expression context uninitialized for named
// property stores.
Literal* lit = prop->key()->AsLiteral();
uint32_t ignored;
if (lit == NULL ||
!lit->handle()->IsSymbol() ||
String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
ProcessExpression(prop->key(), Expression::kValue);
CHECK_BAILOUT;
}
} else {
// This is a throw reference error.
BAILOUT("CountOperation non-variable/non-property expression");
}
} }
......
...@@ -676,7 +676,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -676,7 +676,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
EmitNamedPropertyLoad(prop, Expression::kValue); EmitNamedPropertyLoad(prop, Expression::kValue);
break; break;
case KEYED_PROPERTY: case KEYED_PROPERTY:
EmitKeyedPropertyLoad(Expression::kValue); EmitKeyedPropertyLoad(prop, Expression::kValue);
break; break;
} }
} }
...@@ -694,7 +694,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -694,7 +694,8 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE:
EmitVariableAssignment(expr); EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
expr->context());
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
......
...@@ -213,6 +213,7 @@ class FastCodeGenerator: public AstVisitor { ...@@ -213,6 +213,7 @@ class FastCodeGenerator: public AstVisitor {
int SlotOffset(Slot* slot); int SlotOffset(Slot* slot);
void Move(Expression::Context destination, Register source); 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, Slot* source, Register scratch);
void Move(Expression::Context destination, Literal* source); void Move(Expression::Context destination, Literal* source);
void Move(Slot* dst, Register source, Register scratch1, Register scratch2); void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
...@@ -247,13 +248,13 @@ class FastCodeGenerator: public AstVisitor { ...@@ -247,13 +248,13 @@ class FastCodeGenerator: public AstVisitor {
// Platform-specific support for compiling assignments. // Platform-specific support for compiling assignments.
// Load a value from a named property and push the result on the stack. // Load a value from a named property.
// The receiver is left on the stack by the IC. // The receiver is left on the stack by the IC.
void EmitNamedPropertyLoad(Property* expr, Expression::Context context); void EmitNamedPropertyLoad(Property* expr, Expression::Context context);
// Load a value from a named property and push the result on the stack. // Load a value from a keyed property.
// The receiver and the key is left on the stack by the IC. // The receiver and the key is left on the stack by the IC.
void EmitKeyedPropertyLoad(Expression::Context context); void EmitKeyedPropertyLoad(Property* expr, Expression::Context context);
// Apply the compound assignment operator. Expects both operands on top // Apply the compound assignment operator. Expects both operands on top
// of the stack. // of the stack.
...@@ -261,7 +262,7 @@ class FastCodeGenerator: public AstVisitor { ...@@ -261,7 +262,7 @@ class FastCodeGenerator: public AstVisitor {
// Complete a variable assignment. The right-hand-side value is expected // Complete a variable assignment. The right-hand-side value is expected
// on top of the stack. // on top of the stack.
void EmitVariableAssignment(Assignment* expr); void EmitVariableAssignment(Variable* var, Expression::Context context);
// Complete a named property assignment. The receiver and right-hand-side // Complete a named property assignment. The receiver and right-hand-side
// value are expected on top of the stack. // value are expected on top of the stack.
......
...@@ -227,6 +227,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) { ...@@ -227,6 +227,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::MoveTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ Drop(1);
break;
case Expression::kValue:
break;
case Expression::kTest:
__ pop(eax);
TestAndBranch(eax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ mov(eax, Operand(esp, 0));
TestAndBranch(eax, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ mov(eax, Operand(esp, 0));
TestAndBranch(eax, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
}
}
}
template <> template <>
Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
Register scratch) { Register scratch) {
...@@ -828,6 +862,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -828,6 +862,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
Expression::Context context) { Expression::Context context) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
__ mov(ecx, Immediate(key->handle())); __ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
...@@ -836,7 +871,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, ...@@ -836,7 +871,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
} }
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
Expression::Context context) {
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
Move(context, eax); Move(context, eax);
...@@ -853,8 +890,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, ...@@ -853,8 +890,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
} }
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { void FastCodeGenerator::EmitVariableAssignment(Variable* var,
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Expression::Context context) {
ASSERT(var != NULL); ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL); ASSERT(var->is_global() || var->slot() != NULL);
if (var->is_global()) { if (var->is_global()) {
...@@ -867,7 +904,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -867,7 +904,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET); __ call(ic, RelocInfo::CODE_TARGET);
// Overwrite the receiver on the stack with the result if needed. // Overwrite the receiver on the stack with the result if needed.
DropAndMove(expr->context(), eax); DropAndMove(context, eax);
} else if (var->slot() != NULL) { } else if (var->slot() != NULL) {
Slot* slot = var->slot(); Slot* slot = var->slot();
...@@ -875,7 +912,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -875,7 +912,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
case Slot::LOCAL: case Slot::LOCAL:
case Slot::PARAMETER: { case Slot::PARAMETER: {
Operand target = Operand(ebp, SlotOffset(var->slot())); Operand target = Operand(ebp, SlotOffset(var->slot()));
switch (expr->context()) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
...@@ -943,16 +980,16 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -943,16 +980,16 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
__ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx); __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx);
// RecordWrite may destroy all its register arguments. // RecordWrite may destroy all its register arguments.
if (expr->context() == Expression::kValue) { if (context == Expression::kValue) {
__ push(ecx); __ push(ecx);
} else if (expr->context() != Expression::kEffect) { } else if (context != Expression::kEffect) {
__ mov(edx, ecx); __ mov(edx, ecx);
} }
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(eax, offset, ecx, ebx); __ RecordWrite(eax, offset, ecx, ebx);
if (expr->context() != Expression::kEffect && if (context != Expression::kEffect &&
expr->context() != Expression::kValue) { context != Expression::kValue) {
Move(expr->context(), edx); Move(context, edx);
} }
break; break;
} }
...@@ -1377,27 +1414,75 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1377,27 +1414,75 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
Comment cmnt(masm_, "[ CountOperation"); Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy); // Expression can only be a property, a global or a (parameter or local)
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
Property* prop = expr->expression()->AsProperty();
// In case of a property we use the uninitialized expression context
// of the key to detect a named property.
if (prop != NULL) {
assign_type = (prop->key()->context() == Expression::kUninitialized)
? NAMED_PROPERTY
: KEYED_PROPERTY;
}
// Evaluate expression and get value.
if (assign_type == VARIABLE) {
ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
Expression::kValue);
} else {
// Reserve space for result of postfix operation.
if (expr->is_postfix() && expr->context() != Expression::kEffect) {
ASSERT(expr->context() != Expression::kUninitialized);
__ push(Immediate(Smi::FromInt(0)));
}
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
if (assign_type == NAMED_PROPERTY) {
EmitNamedPropertyLoad(prop, Expression::kValue);
} else {
Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context());
EmitKeyedPropertyLoad(prop, Expression::kValue);
}
}
// Convert to number.
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
// Save result for postfix expressions.
if (expr->is_postfix()) {
switch (expr->context()) { switch (expr->context()) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect:
// Do not save result.
break;
case Expression::kValue: // Fall through case Expression::kValue: // Fall through
case Expression::kTest: // Fall through case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through case Expression::kTestValue: // Fall through
case Expression::kValueTest: case Expression::kValueTest:
// Duplicate the result on the stack. // Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(eax); __ push(eax);
break; break;
case Expression::kEffect: case NAMED_PROPERTY:
// Do not save result. __ mov(Operand(esp, kPointerSize), eax);
break; break;
case KEYED_PROPERTY:
__ mov(Operand(esp, 2 * kPointerSize), eax);
break;
}
break;
}
} }
// Call runtime for +1/-1. // Call runtime for +1/-1.
__ push(eax); __ push(eax);
__ push(Immediate(Smi::FromInt(1))); __ push(Immediate(Smi::FromInt(1)));
...@@ -1406,42 +1491,55 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -1406,42 +1491,55 @@ void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
} else { } else {
__ CallRuntime(Runtime::kNumberSub, 2); __ CallRuntime(Runtime::kNumberSub, 2);
} }
// Call Store IC.
__ mov(ecx, proxy->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC.
__ add(Operand(esp), Immediate(kPointerSize));
switch (expr->context()) { // Store the value returned in eax.
case Expression::kUninitialized: switch (assign_type) {
UNREACHABLE(); case VARIABLE:
case Expression::kEffect: // Fall through __ push(eax);
case Expression::kValue: if (expr->is_postfix()) {
// Do nothing. Result in either on the stack for value context EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
// or discarded for effect context. Expression::kEffect);
break; // For all contexts except kEffect: We have the result on
case Expression::kTest: // top of the stack.
__ pop(eax); if (expr->context() != Expression::kEffect) {
TestAndBranch(eax, true_label_, false_label_); MoveTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
expr->context());
}
break; break;
case Expression::kValueTest: { case NAMED_PROPERTY: {
Label discard; __ mov(ecx, prop->key()->AsLiteral()->handle());
__ mov(eax, Operand(esp, 0)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
TestAndBranch(eax, true_label_, &discard); __ call(ic, RelocInfo::CODE_TARGET);
__ bind(&discard); // This nop signals to the IC that there is no inlined code at the call
__ add(Operand(esp), Immediate(kPointerSize)); // site for it to patch.
__ jmp(false_label_); __ nop();
if (expr->is_postfix()) {
__ Drop(1); // Result is on the stack under the receiver.
if (expr->context() != Expression::kEffect) {
MoveTOS(expr->context());
}
} else {
DropAndMove(expr->context(), eax);
}
break; break;
} }
case Expression::kTestValue: { case KEYED_PROPERTY: {
Label discard; Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ mov(eax, Operand(esp, 0)); __ call(ic, RelocInfo::CODE_TARGET);
TestAndBranch(eax, &discard, false_label_); // This nop signals to the IC that there is no inlined code at the call
__ bind(&discard); // site for it to patch.
__ add(Operand(esp), Immediate(kPointerSize)); __ nop();
__ jmp(true_label_); 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());
}
} else {
DropAndMove(expr->context(), eax, 2);
}
break; break;
} }
} }
......
...@@ -236,6 +236,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) { ...@@ -236,6 +236,40 @@ void FastCodeGenerator::Move(Expression::Context context, Register source) {
} }
void FastCodeGenerator::MoveTOS(Expression::Context context) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
__ Drop(1);
break;
case Expression::kValue:
break;
case Expression::kTest:
__ pop(rax);
TestAndBranch(rax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
}
}
}
template <> template <>
Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source, Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
Register scratch) { Register scratch) {
...@@ -837,6 +871,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { ...@@ -837,6 +871,7 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
Expression::Context context) { Expression::Context context) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral(); Literal* key = prop->key()->AsLiteral();
__ Move(rcx, key->handle()); __ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
...@@ -845,7 +880,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, ...@@ -845,7 +880,9 @@ void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
} }
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
Expression::Context context) {
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
Move(context, rax); Move(context, rax);
...@@ -862,8 +899,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, ...@@ -862,8 +899,8 @@ void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
} }
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { void FastCodeGenerator::EmitVariableAssignment(Variable* var,
Variable* var = expr->target()->AsVariableProxy()->AsVariable(); Expression::Context context) {
ASSERT(var != NULL); ASSERT(var != NULL);
ASSERT(var->is_global() || var->slot() != NULL); ASSERT(var->is_global() || var->slot() != NULL);
if (var->is_global()) { if (var->is_global()) {
...@@ -876,7 +913,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -876,7 +913,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET); __ Call(ic, RelocInfo::CODE_TARGET);
// Overwrite the global object on the stack with the result if needed. // Overwrite the global object on the stack with the result if needed.
DropAndMove(expr->context(), rax); DropAndMove(context, rax);
} else if (var->slot()) { } else if (var->slot()) {
Slot* slot = var->slot(); Slot* slot = var->slot();
...@@ -884,7 +921,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -884,7 +921,7 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
switch (slot->type()) { switch (slot->type()) {
case Slot::LOCAL: case Slot::LOCAL:
case Slot::PARAMETER: { case Slot::PARAMETER: {
switch (expr->context()) { switch (context) {
case Expression::kUninitialized: case Expression::kUninitialized:
UNREACHABLE(); UNREACHABLE();
case Expression::kEffect: case Expression::kEffect:
...@@ -952,16 +989,16 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { ...@@ -952,16 +989,16 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
__ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx); __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx);
// RecordWrite may destroy all its register arguments. // RecordWrite may destroy all its register arguments.
if (expr->context() == Expression::kValue) { if (context == Expression::kValue) {
__ push(rcx); __ push(rcx);
} else if (expr->context() != Expression::kEffect) { } else if (context != Expression::kEffect) {
__ movq(rdx, rcx); __ movq(rdx, rcx);
} }
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ RecordWrite(rax, offset, rcx, rbx); __ RecordWrite(rax, offset, rcx, rbx);
if (expr->context() != Expression::kEffect && if (context != Expression::kEffect &&
expr->context() != Expression::kValue) { context != Expression::kValue) {
Move(expr->context(), rdx); Move(context, rdx);
} }
break; break;
} }
...@@ -1263,78 +1300,6 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { ...@@ -1263,78 +1300,6 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
} }
} }
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
Comment cmnt(masm_, "[ CountOperation");
VariableProxy* proxy = expr->expression()->AsVariableProxy();
ASSERT(proxy->AsVariable() != NULL);
ASSERT(proxy->AsVariable()->is_global());
Visit(proxy);
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kValue: // Fall through
case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through
case Expression::kValueTest:
// Duplicate the result on the stack.
__ push(rax);
break;
case Expression::kEffect:
// Do not save result.
break;
}
// Call runtime for +1/-1.
__ push(rax);
__ Push(Smi::FromInt(1));
if (expr->op() == Token::INC) {
__ CallRuntime(Runtime::kNumberAdd, 2);
} else {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Call Store IC.
__ Move(rcx, proxy->AsVariable()->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Restore up stack after store IC
__ addq(rsp, Immediate(kPointerSize));
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect: // Fall through
case Expression::kValue:
// Do nothing. Result in either on the stack for value context
// or discarded for effect context.
break;
case Expression::kTest:
__ pop(rax);
TestAndBranch(rax, true_label_, false_label_);
break;
case Expression::kValueTest: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, true_label_, &discard);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
__ movq(rax, Operand(rsp, 0));
TestAndBranch(rax, &discard, false_label_);
__ bind(&discard);
__ addq(rsp, Immediate(kPointerSize));
__ jmp(true_label_);
break;
}
}
}
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
switch (expr->op()) { switch (expr->op()) {
...@@ -1464,6 +1429,139 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { ...@@ -1464,6 +1429,139 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
} }
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
Comment cmnt(masm_, "[ CountOperation");
// Expression can only be a property, a global or a (parameter or local)
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
Property* prop = expr->expression()->AsProperty();
// In case of a property we use the uninitialized expression context
// of the key to detect a named property.
if (prop != NULL) {
assign_type = (prop->key()->context() == Expression::kUninitialized)
? NAMED_PROPERTY
: KEYED_PROPERTY;
}
// Evaluate expression and get value.
if (assign_type == VARIABLE) {
ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
Expression::kValue);
} else {
// Reserve space for result of postfix operation.
if (expr->is_postfix() && expr->context() != Expression::kEffect) {
ASSERT(expr->context() != Expression::kUninitialized);
__ Push(Smi::FromInt(0));
}
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
if (assign_type == NAMED_PROPERTY) {
EmitNamedPropertyLoad(prop, Expression::kValue);
} else {
Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context());
EmitKeyedPropertyLoad(prop, Expression::kValue);
}
}
// Convert to number.
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
// Save result for postfix expressions.
if (expr->is_postfix()) {
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
// Do not save result.
break;
case Expression::kValue: // Fall through
case Expression::kTest: // Fall through
case Expression::kTestValue: // Fall through
case Expression::kValueTest:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(rax);
break;
case NAMED_PROPERTY:
__ movq(Operand(rsp, kPointerSize), rax);
break;
case KEYED_PROPERTY:
__ movq(Operand(rsp, 2 * kPointerSize), rax);
break;
}
break;
}
}
// Call runtime for +1/-1.
__ push(rax);
__ Push(Smi::FromInt(1));
if (expr->op() == Token::INC) {
__ CallRuntime(Runtime::kNumberAdd, 2);
} else {
__ CallRuntime(Runtime::kNumberSub, 2);
}
// Store the value returned in rax.
switch (assign_type) {
case VARIABLE:
__ push(rax);
if (expr->is_postfix()) {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Expression::kEffect);
// For all contexts except kEffect: We have the result on
// top of the stack.
if (expr->context() != Expression::kEffect) {
MoveTOS(expr->context());
}
} else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
expr->context());
}
break;
case NAMED_PROPERTY: {
__ Move(rcx, prop->key()->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call
// site for it to patch.
__ nop();
if (expr->is_postfix()) {
__ Drop(1); // Result is on the stack under the receiver.
if (expr->context() != Expression::kEffect) {
MoveTOS(expr->context());
}
} else {
DropAndMove(expr->context(), rax);
}
break;
}
case KEYED_PROPERTY: {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call
// site for it to patch.
__ nop();
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());
}
} else {
DropAndMove(expr->context(), rax, 2);
}
break;
}
}
}
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation"); Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) { switch (expr->op()) {
......
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test pre- and postfix count operations.
// Test value context.
var a = 42;
var b = {x:42};
var c = "x";
assertEquals(43, ++a);
assertEquals(43, a);
assertEquals(43, a++);
assertEquals(44, a);
assertEquals(43, ++b.x);
assertEquals(43, b.x);
assertEquals(43, b.x++);
assertEquals(44, b.x);
assertEquals(45, ++b[c]);
assertEquals(45, b[c]);
assertEquals(45, b[c]++);
assertEquals(46, b[c]);
// Test effect context.
a = 42;
b = {x:42};
c = "x";
assertEquals(1, eval("++a; 1"));
assertEquals(43, a);
assertEquals(1, eval("a++; 1"));
assertEquals(44, a);
assertEquals(1, eval("++b.x; 1"));
assertEquals(43, b.x);
assertEquals(1, eval("b.x++; 1"));
assertEquals(44, b.x);
assertEquals(1, eval("++b[c]; 1"));
assertEquals(45, b[c]);
assertEquals(1, eval("b[c]++; 1"));
assertEquals(46, b[c]);
// Test test context.
a = 42;
b = {x:42};
c = "x";
assertEquals(1, (++a) ? 1 : 0);
assertEquals(43, a);
assertEquals(1, (a++) ? 1 : 0);
assertEquals(44, a);
assertEquals(1, (++b.x) ? 1 : 0);
assertEquals(43, b.x);
assertEquals(1, (b.x++) ? 1 : 0);
assertEquals(44, b.x);
assertEquals(1, (++b[c]) ? 1 : 0);
assertEquals(45, b[c]);
assertEquals(1, (b[c]++) ? 1 : 0);
assertEquals(46, b[c]);
// Test value/test and test/value contexts.
a = 42;
b = {x:42};
c = "x";
assertEquals(43, ++a || 1);
assertEquals(43, a);
assertEquals(43, a++ || 1);
assertEquals(44, a);
assertEquals(43, ++b.x || 1);
assertEquals(43, b.x);
assertEquals(43, (b.x++) || 1);
assertEquals(44, b.x);
assertEquals(45, ++b[c] || 1);
assertEquals(45, b[c]);
assertEquals(45, b[c]++ || 1);
assertEquals(46, b[c]);
a = 42;
b = {x:42};
c = "x";
assertEquals(1, ++a && 1);
assertEquals(43, a);
assertEquals(1, a++ && 1);
assertEquals(44, a);
assertEquals(1, ++b.x && 1);
assertEquals(43, b.x);
assertEquals(1, (b.x++) && 1);
assertEquals(44, b.x);
assertEquals(1, ++b[c] && 1);
assertEquals(45, b[c]);
assertEquals(1, b[c]++ && 1);
assertEquals(46, b[c]);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment