Add support for initialization block assignments in the toplevel code
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 13:30:24 +0000 (13:30 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Nov 2009 13:30:24 +0000 (13:30 +0000)
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

src/arm/fast-codegen-arm.cc
src/compiler.cc
src/fast-codegen.cc
src/fast-codegen.h
src/ia32/fast-codegen-ia32.cc
src/parser.cc
src/x64/fast-codegen-x64.cc

index 2bf2659a962686b8cf5aa4fcb97d8f6a797156a7..d410a50e4501d93a2497d5c3d8de0f9849814309 100644 (file)
@@ -572,12 +572,14 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
-                                               Variable* var) {
+void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  ASSERT(var != NULL);
+
   if (var->is_global()) {
-    // Assignment to a global variable, use inline caching.  Right-hand-side
-    // value is passed in r0, variable name in r2, and the global object
-    // on the stack.
+    // Assignment to a global variable.  Use inline caching for the
+    // assignment.  Right-hand-side value is passed in r0, variable name in
+    // r2, and the global object on the stack.
     __ pop(r0);
     __ mov(r2, Operand(var->name()));
     __ ldr(ip, CodeGenerator::GlobalObject());
@@ -585,9 +587,10 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
     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);
+    DropAndMove(expr->context(), r0);
+
   } else {
-    switch (context) {
+    switch (expr->context()) {
       case Expression::kUninitialized:
         UNREACHABLE();
       case Expression::kEffect:
@@ -631,25 +634,69 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
 }
 
 
-void FastCodeGenerator::EmitNamedPropertyAssignment(
-    Expression::Context context,
-    Handle<Object> name) {
+void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
+  // Assignment to a property, using a named store IC.
+  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);
-  __ mov(r2, Operand(name));
+  __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   __ 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(
-    Expression::Context context) {
+void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
+  // 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);
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   __ 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.
   __ add(sp, sp, Operand(2 * kPointerSize));
-  Move(context, r0);
+  Move(expr->context(), r0);
 }
 
 
index 2526ad7660b281c61a4f113386fcb7553968988e..fc5ffe1ad171bf3be8fb7dd2c5b157afd97c98d8 100644 (file)
@@ -724,11 +724,6 @@ void CodeGenSelector::VisitCatchExtensionObject(CatchExtensionObject* expr) {
 void CodeGenSelector::VisitAssignment(Assignment* expr) {
   // We support plain non-compound assignments to properties, parameters and
   // 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();
   if (op == Token::INIT_CONST) BAILOUT("initialize constant");
   if (op != Token::ASSIGN && op != Token::INIT_VAR) {
index 1d12a0ddf59f3e08d91cbcbd776ff87e678efe17..76d51c06ce701376f54ea394ddb433fd54925212 100644 (file)
@@ -439,7 +439,7 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
   if (var != NULL) {
     Visit(rhs);
     ASSERT_EQ(Expression::kValue, rhs->context());
-    EmitVariableAssignment(expr->context(), var);
+    EmitVariableAssignment(expr);
   } else if (prop != NULL) {
     // Assignment to a property.
     Visit(prop->obj());
@@ -450,14 +450,13 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
       ASSERT(prop->key()->AsLiteral() != NULL);
       Visit(rhs);
       ASSERT_EQ(Expression::kValue, rhs->context());
-      EmitNamedPropertyAssignment(expr->context(),
-                                  prop->key()->AsLiteral()->handle());
+      EmitNamedPropertyAssignment(expr);
     } else {
       Visit(prop->key());
       ASSERT_EQ(Expression::kValue, prop->key()->context());
       Visit(rhs);
       ASSERT_EQ(Expression::kValue, rhs->context());
-      EmitKeyedPropertyAssignment(expr->context());
+      EmitKeyedPropertyAssignment(expr);
     }
   } else {
     UNREACHABLE();
index 319bb2f04f3d2799c78aea8aa5d62cc1ca707f16..92af19ebd4f5902ecba8dc2b478b9d33c524ee4f 100644 (file)
@@ -77,18 +77,17 @@ class FastCodeGenerator: public AstVisitor {
 
   // 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.
-  void EmitVariableAssignment(Expression::Context context, Variable* var);
+  void EmitVariableAssignment(Assignment* expr);
 
   // Complete a named property assignment.  The receiver and right-hand-side
   // value are expected on top of the stack.
-  void EmitNamedPropertyAssignment(Expression::Context context,
-                                   Handle<Object> name);
+  void EmitNamedPropertyAssignment(Assignment* expr);
 
   // Complete a keyed property assignment.  The reciever, key, and
   // 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 SetReturnPosition(FunctionLiteral* fun);
index a234ae1e20877decffb4fc3eea395aa4829c4ace..e049dba23cb44622117d1c60ac1a9b9f6d1b0324 100644 (file)
@@ -586,21 +586,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
-                                               Variable* var) {
+void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  ASSERT(var != NULL);
+
   if (var->is_global()) {
-    // Assignment to a global variable, use inline caching.  Right-hand-side
-    // value is passed in eax, variable name in ecx, and the global object
-    // on the stack.
+    // Assignment to a global variable.  Use inline caching for the
+    // assignment.  Right-hand-side value is passed in eax, variable name in
+    // ecx, and the global object on the stack.
     __ pop(eax);
     __ mov(ecx, var->name());
     __ push(CodeGenerator::GlobalObject());
     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, eax);
+    // Overwrite the receiver on the stack with the result if needed.
+    DropAndMove(expr->context(), eax);
+
   } else {
-    switch (context) {
+    switch (expr->context()) {
       case Expression::kUninitialized:
         UNREACHABLE();
       case Expression::kEffect:
@@ -643,28 +646,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
 }
 
 
-void FastCodeGenerator::EmitNamedPropertyAssignment(
-    Expression::Context context,
-    Handle<Object> name) {
+void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
+  // Assignment to a property, using a named store IC.
+  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);
-  __ mov(ecx, name);
+  __ mov(ecx, prop->key()->AsLiteral()->handle());
   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   __ 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(
-    Expression::Context context) {
+void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
+  // 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);
   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 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.
   __ add(Operand(esp), Immediate(2 * kPointerSize));
-  Move(context, eax);
+  Move(expr->context(), eax);
 }
 
 
index 02fcfdc594364d18f78df1a4737bd5f165e29569..d64d8befd5cd07aca6f7b4a686fad380d6c425b9 100644 (file)
@@ -1339,7 +1339,7 @@ class ParserFinder {
 
 
 // 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 {
  public:
   InitializationBlockFinder()
@@ -1367,7 +1367,7 @@ class InitializationBlockFinder : public ParserFinder {
  private:
   // Returns true if the expressions appear to denote the same object.
   // 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) {
     VariableProxy* v1 = e1->AsVariableProxy();
     VariableProxy* v2 = e2->AsVariableProxy();
index b4c75ab787041dc797d0d39898ffe6b03bc48203..5df9146231977fc0c4c8f238ccaa28133c2be9d4 100644 (file)
@@ -600,21 +600,24 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
-                                               Variable* var) {
+void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
+  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+  ASSERT(var != NULL);
+
   if (var->is_global()) {
-    // Assignment to a global variable, use inline caching.  Right-hand-side
-    // value is passed in rax, variable name in rcx, and the global object
-    // on the stack.
+    // Assignment to a global variable.  Use inline caching for the
+    // assignment.  Right-hand-side value is passed in rax, variable name in
+    // rcx, and the global object on the stack.
     __ pop(rax);
     __ Move(rcx, var->name());
     __ push(CodeGenerator::GlobalObject());
     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);
+    DropAndMove(expr->context(), rax);
+
   } else {
-    switch (context) {
+    switch (expr->context()) {
       case Expression::kUninitialized:
         UNREACHABLE();
       case Expression::kEffect:
@@ -657,28 +660,68 @@ void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
 }
 
 
-void FastCodeGenerator::EmitNamedPropertyAssignment(
-    Expression::Context context,
-    Handle<Object> name) {
+void FastCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
+  // Assignment to a property, using a named store IC.
+  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);
-  __ Move(rcx, name);
+  __ Move(rcx, prop->key()->AsLiteral()->handle());
   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   __ 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(
-    Expression::Context context) {
+void FastCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
+  // 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);
   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 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.
   __ addq(rsp, Immediate(2 * kPointerSize));
-  Move(context, rax);
+  Move(expr->context(), rax);
 }