Add support for initialization block assignments in the toplevel code
generator, mimicing the behavior of the optimizing compiler. Initialization blocks can only contain (thus begin and end) with a property assignment in toplevel code. Review URL: http://codereview.chromium.org/348038 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3198 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b4c11d0816
commit
aa3b00a25a
@ -572,12 +572,14 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||||
Variable* var) {
|
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||||
|
ASSERT(var != NULL);
|
||||||
|
|
||||||
if (var->is_global()) {
|
if (var->is_global()) {
|
||||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
// Assignment to a global variable. Use inline caching for the
|
||||||
// value is passed in r0, variable name in r2, and the global object
|
// assignment. Right-hand-side value is passed in r0, variable name in
|
||||||
// on the stack.
|
// r2, and the global object on the stack.
|
||||||
__ pop(r0);
|
__ pop(r0);
|
||||||
__ mov(r2, Operand(var->name()));
|
__ mov(r2, Operand(var->name()));
|
||||||
__ ldr(ip, CodeGenerator::GlobalObject());
|
__ ldr(ip, CodeGenerator::GlobalObject());
|
||||||
@ -585,9 +587,10 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
|||||||
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(context, r0);
|
DropAndMove(expr->context(), r0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (context) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
case Expression::kEffect:
|
case Expression::kEffect:
|
||||||
@ -631,25 +634,69 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context,
|
// Assignment to a property, using a named store IC.
|
||||||
Handle<Object> name) {
|
Property* prop = expr->target()->AsProperty();
|
||||||
|
ASSERT(prop != NULL);
|
||||||
|
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
__ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ push(ip);
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(r0);
|
__ pop(r0);
|
||||||
__ mov(r2, Operand(name));
|
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
|
||||||
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);
|
||||||
DropAndMove(context, r0);
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(r0); // Result of assignment, saved even if not needed.
|
||||||
|
__ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ push(ip);
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(r0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DropAndMove(expr->context(), r0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context) {
|
// Assignment to a property, using a keyed store IC.
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ ldr(ip, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ push(ip);
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(r0);
|
__ pop(r0);
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(r0); // Result of assignment, saved even if not needed.
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ ldr(ip, MemOperand(sp, 2 * kPointerSize));
|
||||||
|
__ push(ip);
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(r0);
|
||||||
|
}
|
||||||
|
|
||||||
// Receiver and key are still on stack.
|
// Receiver and key are still on stack.
|
||||||
__ add(sp, sp, Operand(2 * kPointerSize));
|
__ add(sp, sp, Operand(2 * kPointerSize));
|
||||||
Move(context, r0);
|
Move(expr->context(), r0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -724,11 +724,6 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
|||||||
void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
||||||
// We support plain non-compound assignments to properties, parameters and
|
// We support plain non-compound assignments to properties, parameters and
|
||||||
// non-context (stack-allocated) locals, and global variables.
|
// non-context (stack-allocated) locals, and global variables.
|
||||||
if (expr->starts_initialization_block() ||
|
|
||||||
expr->ends_initialization_block()) {
|
|
||||||
BAILOUT("initialization block start");
|
|
||||||
}
|
|
||||||
|
|
||||||
Token::Value op = expr->op();
|
Token::Value op = expr->op();
|
||||||
if (op == Token::INIT_CONST) BAILOUT("initialize constant");
|
if (op == Token::INIT_CONST) BAILOUT("initialize constant");
|
||||||
if (op != Token::ASSIGN && op != Token::INIT_VAR) {
|
if (op != Token::ASSIGN && op != Token::INIT_VAR) {
|
||||||
|
@ -439,7 +439,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
if (var != NULL) {
|
if (var != NULL) {
|
||||||
Visit(rhs);
|
Visit(rhs);
|
||||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||||
EmitVariableAssignment(expr->context(), var);
|
EmitVariableAssignment(expr);
|
||||||
} else if (prop != NULL) {
|
} else if (prop != NULL) {
|
||||||
// Assignment to a property.
|
// Assignment to a property.
|
||||||
Visit(prop->obj());
|
Visit(prop->obj());
|
||||||
@ -450,14 +450,13 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||||
Visit(rhs);
|
Visit(rhs);
|
||||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||||
EmitNamedPropertyAssignment(expr->context(),
|
EmitNamedPropertyAssignment(expr);
|
||||||
prop->key()->AsLiteral()->handle());
|
|
||||||
} else {
|
} else {
|
||||||
Visit(prop->key());
|
Visit(prop->key());
|
||||||
ASSERT_EQ(Expression::kValue, prop->key()->context());
|
ASSERT_EQ(Expression::kValue, prop->key()->context());
|
||||||
Visit(rhs);
|
Visit(rhs);
|
||||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||||
EmitKeyedPropertyAssignment(expr->context());
|
EmitKeyedPropertyAssignment(expr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -77,18 +77,17 @@ class FastCodeGenerator: public AstVisitor {
|
|||||||
|
|
||||||
// Platform-specific support for compiling assignments.
|
// Platform-specific support for compiling assignments.
|
||||||
|
|
||||||
// Complete a variable assignment. The right-hand-side value are expected
|
// Complete a variable assignment. The right-hand-side value is expected
|
||||||
// on top of the stack.
|
// on top of the stack.
|
||||||
void EmitVariableAssignment(Expression::Context context, Variable* var);
|
void EmitVariableAssignment(Assignment* expr);
|
||||||
|
|
||||||
// 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.
|
||||||
void EmitNamedPropertyAssignment(Expression::Context context,
|
void EmitNamedPropertyAssignment(Assignment* expr);
|
||||||
Handle<Object> name);
|
|
||||||
|
|
||||||
// Complete a keyed property assignment. The reciever, key, and
|
// Complete a keyed property assignment. The reciever, key, and
|
||||||
// right-hand-side value are expected on top of the stack.
|
// right-hand-side value are expected on top of the stack.
|
||||||
void EmitKeyedPropertyAssignment(Expression::Context context);
|
void EmitKeyedPropertyAssignment(Assignment* expr);
|
||||||
|
|
||||||
void SetFunctionPosition(FunctionLiteral* fun);
|
void SetFunctionPosition(FunctionLiteral* fun);
|
||||||
void SetReturnPosition(FunctionLiteral* fun);
|
void SetReturnPosition(FunctionLiteral* fun);
|
||||||
|
@ -586,21 +586,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||||
Variable* var) {
|
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||||
|
ASSERT(var != NULL);
|
||||||
|
|
||||||
if (var->is_global()) {
|
if (var->is_global()) {
|
||||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
// Assignment to a global variable. Use inline caching for the
|
||||||
// value is passed in eax, variable name in ecx, and the global object
|
// assignment. Right-hand-side value is passed in eax, variable name in
|
||||||
// on the stack.
|
// ecx, and the global object on the stack.
|
||||||
__ pop(eax);
|
__ pop(eax);
|
||||||
__ mov(ecx, var->name());
|
__ mov(ecx, var->name());
|
||||||
__ push(CodeGenerator::GlobalObject());
|
__ push(CodeGenerator::GlobalObject());
|
||||||
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 receiver on the stack with the result if needed.
|
||||||
DropAndMove(context, eax);
|
DropAndMove(expr->context(), eax);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (context) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
case Expression::kEffect:
|
case Expression::kEffect:
|
||||||
@ -643,28 +646,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context,
|
// Assignment to a property, using a named store IC.
|
||||||
Handle<Object> name) {
|
Property* prop = expr->target()->AsProperty();
|
||||||
|
ASSERT(prop != NULL);
|
||||||
|
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
__ push(Operand(esp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(eax);
|
__ pop(eax);
|
||||||
__ mov(ecx, name);
|
__ mov(ecx, prop->key()->AsLiteral()->handle());
|
||||||
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);
|
||||||
DropAndMove(context, eax);
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(eax); // Result of assignment, saved even if not needed.
|
||||||
|
__ push(Operand(esp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(eax);
|
||||||
|
}
|
||||||
|
|
||||||
|
DropAndMove(expr->context(), eax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context) {
|
// Assignment to a property, using a keyed store IC.
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ push(Operand(esp, 2 * kPointerSize));
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(eax);
|
__ pop(eax);
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||||
__ call(ic, RelocInfo::CODE_TARGET);
|
__ call(ic, RelocInfo::CODE_TARGET);
|
||||||
// This nop signals to the IC that there is no inlined code at the call
|
// This nop signals to the IC that there is no inlined code at the call
|
||||||
// site for it to patch.
|
// site for it to patch.
|
||||||
__ nop();
|
__ nop();
|
||||||
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(eax); // Result of assignment, saved even if not needed.
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ push(Operand(esp, 2 * kPointerSize));
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(eax);
|
||||||
|
}
|
||||||
|
|
||||||
// Receiver and key are still on stack.
|
// Receiver and key are still on stack.
|
||||||
__ add(Operand(esp), Immediate(2 * kPointerSize));
|
__ add(Operand(esp), Immediate(2 * kPointerSize));
|
||||||
Move(context, eax);
|
Move(expr->context(), eax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1339,7 +1339,7 @@ class ParserFinder {
|
|||||||
|
|
||||||
|
|
||||||
// An InitializationBlockFinder finds and marks sequences of statements of the
|
// An InitializationBlockFinder finds and marks sequences of statements of the
|
||||||
// form x.y.z.a = ...; x.y.z.b = ...; etc.
|
// form expr.a = ...; expr.b = ...; etc.
|
||||||
class InitializationBlockFinder : public ParserFinder {
|
class InitializationBlockFinder : public ParserFinder {
|
||||||
public:
|
public:
|
||||||
InitializationBlockFinder()
|
InitializationBlockFinder()
|
||||||
@ -1367,7 +1367,7 @@ class InitializationBlockFinder : public ParserFinder {
|
|||||||
private:
|
private:
|
||||||
// Returns true if the expressions appear to denote the same object.
|
// Returns true if the expressions appear to denote the same object.
|
||||||
// In the context of initialization blocks, we only consider expressions
|
// In the context of initialization blocks, we only consider expressions
|
||||||
// of the form 'x.y.z'.
|
// of the form 'expr.x' or expr["x"].
|
||||||
static bool SameObject(Expression* e1, Expression* e2) {
|
static bool SameObject(Expression* e1, Expression* e2) {
|
||||||
VariableProxy* v1 = e1->AsVariableProxy();
|
VariableProxy* v1 = e1->AsVariableProxy();
|
||||||
VariableProxy* v2 = e2->AsVariableProxy();
|
VariableProxy* v2 = e2->AsVariableProxy();
|
||||||
|
@ -600,21 +600,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||||
Variable* var) {
|
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||||
|
ASSERT(var != NULL);
|
||||||
|
|
||||||
if (var->is_global()) {
|
if (var->is_global()) {
|
||||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
// Assignment to a global variable. Use inline caching for the
|
||||||
// value is passed in rax, variable name in rcx, and the global object
|
// assignment. Right-hand-side value is passed in rax, variable name in
|
||||||
// on the stack.
|
// rcx, and the global object on the stack.
|
||||||
__ pop(rax);
|
__ pop(rax);
|
||||||
__ Move(rcx, var->name());
|
__ Move(rcx, var->name());
|
||||||
__ push(CodeGenerator::GlobalObject());
|
__ push(CodeGenerator::GlobalObject());
|
||||||
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(context, rax);
|
DropAndMove(expr->context(), rax);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (context) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
case Expression::kEffect:
|
case Expression::kEffect:
|
||||||
@ -657,28 +660,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context,
|
// Assignment to a property, using a named store IC.
|
||||||
Handle<Object> name) {
|
Property* prop = expr->target()->AsProperty();
|
||||||
|
ASSERT(prop != NULL);
|
||||||
|
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
__ push(Operand(rsp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(rax);
|
__ pop(rax);
|
||||||
__ Move(rcx, name);
|
__ Move(rcx, prop->key()->AsLiteral()->handle());
|
||||||
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);
|
||||||
DropAndMove(context, rax);
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(rax); // Result of assignment, saved even if not needed.
|
||||||
|
__ push(Operand(rsp, kPointerSize)); // Receiver is under value.
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(rax);
|
||||||
|
}
|
||||||
|
|
||||||
|
DropAndMove(expr->context(), rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
||||||
Expression::Context context) {
|
// Assignment to a property, using a keyed store IC.
|
||||||
|
|
||||||
|
// If the assignment starts a block of assignments to the same object,
|
||||||
|
// change to slow case to avoid the quadratic behavior of repeatedly
|
||||||
|
// adding fast properties.
|
||||||
|
if (expr->starts_initialization_block()) {
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ push(Operand(rsp, 2 * kPointerSize));
|
||||||
|
__ CallRuntime(Runtime::kToSlowProperties, 1);
|
||||||
|
}
|
||||||
|
|
||||||
__ pop(rax);
|
__ pop(rax);
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||||
// This nop signals to the IC that there is no inlined code at the call
|
// This nop signals to the IC that there is no inlined code at the call
|
||||||
// site for it to patch.
|
// site for it to patch.
|
||||||
__ nop();
|
__ nop();
|
||||||
|
|
||||||
|
// If the assignment ends an initialization block, revert to fast case.
|
||||||
|
if (expr->ends_initialization_block()) {
|
||||||
|
__ push(rax); // Result of assignment, saved even if not needed.
|
||||||
|
// Reciever is under the key and value.
|
||||||
|
__ push(Operand(rsp, 2 * kPointerSize));
|
||||||
|
__ CallRuntime(Runtime::kToFastProperties, 1);
|
||||||
|
__ pop(rax);
|
||||||
|
}
|
||||||
|
|
||||||
// Receiver and key are still on stack.
|
// Receiver and key are still on stack.
|
||||||
__ addq(rsp, Immediate(2 * kPointerSize));
|
__ addq(rsp, Immediate(2 * kPointerSize));
|
||||||
Move(context, rax);
|
Move(expr->context(), rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user