Revision: 3242
Author: [email protected]
Date: Mon Nov  9 01:56:57 2009
Log: Enable writes and reads of context slots in fast compiler.
Review URL: http://codereview.chromium.org/360054
http://code.google.com/p/v8/source/detail?r=3242

Modified:
  /branches/bleeding_edge/src/arm/fast-codegen-arm.cc
  /branches/bleeding_edge/src/compiler.cc
  /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc
  /branches/bleeding_edge/src/x64/fast-codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Nov  5 09:33:50  
2009
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Nov  9 01:56:57  
2009
@@ -364,6 +364,7 @@
          __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
          __ mov(r2, Operand(offset));
+        // We know that we have written a function, which is not a smi.
          __ RecordWrite(cp, r2, r0);
        }
        break;
@@ -421,6 +422,7 @@
    Comment cmnt(masm_, "[ VariableProxy");
    Expression* rewrite = expr->var()->rewrite();
    if (rewrite == NULL) {
+    ASSERT(expr->var()->is_global());
      Comment cmnt(masm_, "Global variable");
      // Use inline caching. Variable name is passed in r2 and the global
      // object on the stack.
@@ -431,8 +433,47 @@
      __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
      DropAndMove(expr->context(), r0);
    } else {
-    Comment cmnt(masm_, "Stack slot");
-    Move(expr->context(), rewrite->AsSlot());
+    Slot* slot = rewrite->AsSlot();
+    ASSERT_NE(NULL, slot);
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        Comment cmnt(masm_, "Stack slot");
+        Move(expr->context(), rewrite->AsSlot());
+        break;
+      }
+
+      case Slot::CONTEXT: {
+        Comment cmnt(masm_, "Context slot");
+        int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the chain of contexts to the context containing the  
slot.
+          __ ldr(r0, CodeGenerator::ContextOperand(cp,  
Context::CLOSURE_INDEX));
+          // Load the function context (which is the incoming, outer  
context).
+          __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ ldr(r0,
+                   CodeGenerator::ContextOperand(r0,  
Context::CLOSURE_INDEX));
+            // Load the function context (which is the incoming, outer  
context).
+            __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
+          }
+          // The context may be an intermediate context, not a function  
context.
+          __ ldr(r0,
+                 CodeGenerator::ContextOperand(r0,  
Context::FCONTEXT_INDEX));
+        } else {  // Slot is in the current context.
+          __ ldr(r0,
+                 CodeGenerator::ContextOperand(cp,  
Context::FCONTEXT_INDEX));
+        }
+        __ ldr(r0, CodeGenerator::ContextOperand(r0, slot->index()));
+        Move(expr->context(), r0);
+        break;
+      }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
+    }
    }
  }

@@ -705,45 +746,103 @@
      DropAndMove(expr->context(), r0);

    } else {
-    switch (expr->context()) {
-      case Expression::kUninitialized:
-        UNREACHABLE();
-      case Expression::kEffect:
-        // Perform assignment and discard value.
-        __ pop(r0);
-        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+    Slot* slot = var->slot();
+    ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not  
handled.
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        switch (expr->context()) {
+          case Expression::kUninitialized:
+            UNREACHABLE();
+          case Expression::kEffect:
+            // Perform assignment and discard value.
+            __ pop(r0);
+            __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+            break;
+          case Expression::kValue:
+            // Perform assignment and preserve value.
+            __ ldr(r0, MemOperand(sp));
+            __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+            break;
+          case Expression::kTest:
+            // Perform assignment and test (and discard) value.
+            __ pop(r0);
+            __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+            TestAndBranch(r0, true_label_, false_label_);
+            break;
+          case Expression::kValueTest: {
+            Label discard;
+            __ ldr(r0, MemOperand(sp));
+            __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+            TestAndBranch(r0, true_label_, &discard);
+            __ bind(&discard);
+            __ pop();
+            __ jmp(false_label_);
+            break;
+          }
+          case Expression::kTestValue: {
+            Label discard;
+            __ ldr(r0, MemOperand(sp));
+            __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
+            TestAndBranch(r0, &discard, false_label_);
+            __ bind(&discard);
+            __ pop();
+            __ jmp(true_label_);
+            break;
+          }
+        }
          break;
-      case Expression::kValue:
-        // Perform assignment and preserve value.
-        __ ldr(r0, MemOperand(sp));
-        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-        break;
-      case Expression::kTest:
-        // Perform assignment and test (and discard) value.
-        __ pop(r0);
-        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-        TestAndBranch(r0, true_label_, false_label_);
-        break;
-      case Expression::kValueTest: {
-        Label discard;
-        __ ldr(r0, MemOperand(sp));
-        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-        TestAndBranch(r0, true_label_, &discard);
-        __ bind(&discard);
-        __ pop();
-        __ jmp(false_label_);
-        break;
-      }
-      case Expression::kTestValue: {
-        Label discard;
-        __ ldr(r0, MemOperand(sp));
-        __ str(r0, MemOperand(fp, SlotOffset(var->slot())));
-        TestAndBranch(r0, &discard, false_label_);
-        __ bind(&discard);
-        __ pop();
-        __ jmp(true_label_);
+      }
+
+      case Slot::CONTEXT: {
+        int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the chain of contexts to the context containing the  
slot.
+          __ ldr(r0, CodeGenerator::ContextOperand(cp,  
Context::CLOSURE_INDEX));
+          // Load the function context (which is the incoming, outer  
context).
+          __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ ldr(r0,
+                   CodeGenerator::ContextOperand(r0,  
Context::CLOSURE_INDEX));
+            __ ldr(r0, FieldMemOperand(r0, JSFunction::kContextOffset));
+          }
+        } else {  // Slot is in the current context.  Generate optimized  
code.
+          __ mov(r0, cp);
+        }
+        // The context may be an intermediate context, not a function  
context.
+        __ ldr(r0, CodeGenerator::ContextOperand(r0,  
Context::FCONTEXT_INDEX));
+        __ pop(r1);
+        __ str(r1, CodeGenerator::ContextOperand(r0, slot->index()));
+
+        // RecordWrite may destroy all its register arguments.
+        if (expr->context() == Expression::kValue) {
+          __ push(r1);
+        } else if (expr->context() != Expression::kEffect) {
+          __ mov(r3, r1);
+        }
+        int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
+
+        // Update the write barrier for the array store with r0 as the  
scratch
+        // register.  Skip the write barrier if r0 is a smi.
+        // The smi test is part of RecordWrite on other platforms, not on  
arm.
+        Label exit;
+        __ tst(r0, Operand(kSmiTagMask));
+        __ b(eq, &exit);
+
+        __ mov(r2, Operand(offset));
+        __ RecordWrite(r0, r2, r1);
+        __ bind(&exit);
+        if (expr->context() != Expression::kEffect &&
+            expr->context() != Expression::kValue) {
+        Move(expr->context(), r3);
+        }
          break;
        }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
      }
    }
  }
=======================================
--- /branches/bleeding_edge/src/compiler.cc     Mon Nov  9 01:43:24 2009
+++ /branches/bleeding_edge/src/compiler.cc     Mon Nov  9 01:56:57 2009
@@ -650,6 +650,16 @@
    if (decl->fun() != NULL) {
      ProcessExpression(decl->fun(), Expression::kValue);
    }
+  Variable* var = decl->proxy()->var();
+  ASSERT_NOT_NULL(var);
+  if ((!var->is_global() && decl->fun() != NULL)) {
+    BAILOUT("Non-global function declaration");
+  }
+  if ((!var->is_global() &&
+       var->slot() != NULL &&
+       var->slot()->type() == Slot::LOOKUP)) {
+    BAILOUT("Lookup slot encountered in declaration");
+  }
  }


@@ -794,8 +804,10 @@
      }

      Slot::Type type = slot->type();
-    if (type != Slot::PARAMETER && type != Slot::LOCAL) {
-      BAILOUT("non-parameter/non-local slot reference");
+    // When LOOKUP slots are enabled, some currently dead code
+    // implementing unary typeof will become live.
+    if (type == Slot::LOOKUP) {
+      BAILOUT("Lookup slot");
      }
    }
  }
@@ -883,8 +895,8 @@
          BAILOUT("non-global/non-slot assignment");
        }
        Slot::Type type = var->slot()->type();
-      if (type != Slot::PARAMETER && type != Slot::LOCAL) {
-        BAILOUT("non-parameter/non-local slot assignment");
+      if (type == Slot::LOOKUP) {
+        BAILOUT("Lookup slot");
        }
      }
    } else if (prop != NULL) {
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Thu Nov  5  
09:33:50 2009
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Mon Nov  9  
01:56:57 2009
@@ -410,6 +410,7 @@
    Comment cmnt(masm_, "[ VariableProxy");
    Expression* rewrite = expr->var()->rewrite();
    if (rewrite == NULL) {
+    ASSERT(expr->var()->is_global());
      Comment cmnt(masm_, "Global variable");
      // Use inline caching. Variable name is passed in ecx and the global
      // object on the stack.
@@ -425,8 +426,48 @@

      DropAndMove(expr->context(), eax);
    } else {
-    Comment cmnt(masm_, "Stack slot");
-    Move(expr->context(), rewrite->AsSlot());
+    Slot* slot = rewrite->AsSlot();
+    ASSERT_NE(NULL, slot);
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        Comment cmnt(masm_, "Stack slot");
+        Move(expr->context(), slot);
+        break;
+      }
+
+      case Slot::CONTEXT: {
+        Comment cmnt(masm_, "Context slot");
+         int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the chain of contexts to the context containing the  
slot.
+          __ mov(eax,
+                 Operand(esi,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+          // Load the function context (which is the incoming, outer  
context).
+          __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ mov(eax,
+                   Operand(eax,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+            __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
+          }
+          // The context may be an intermediate context, not a function  
context.
+          __ mov(eax,
+                 Operand(eax,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+        } else {  // Slot is in the current function context.
+          // The context may be an intermediate context, not a function  
context.
+          __ mov(eax,
+                 Operand(esi,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+        }
+        __ mov(eax, Operand(eax, Context::SlotOffset(slot->index())));
+        Move(expr->context(), eax);
+        break;
+      }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
+    }
    }
  }

@@ -693,44 +734,96 @@
      DropAndMove(expr->context(), eax);

    } else {
-    switch (expr->context()) {
-      case Expression::kUninitialized:
-        UNREACHABLE();
-      case Expression::kEffect:
-        // Perform assignment and discard value.
-        __ pop(Operand(ebp, SlotOffset(var->slot())));
+    Slot* slot = var->slot();
+    ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not  
handled.
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        switch (expr->context()) {
+          case Expression::kUninitialized:
+            UNREACHABLE();
+          case Expression::kEffect:
+            // Perform assignment and discard value.
+            __ pop(Operand(ebp, SlotOffset(var->slot())));
+            break;
+          case Expression::kValue:
+            // Perform assignment and preserve value.
+            __ mov(eax, Operand(esp, 0));
+            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            break;
+          case Expression::kTest:
+            // Perform assignment and test (and discard) value.
+            __ pop(eax);
+            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            TestAndBranch(eax, true_label_, false_label_);
+            break;
+          case Expression::kValueTest: {
+            Label discard;
+            __ mov(eax, Operand(esp, 0));
+            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            TestAndBranch(eax, true_label_, &discard);
+            __ bind(&discard);
+            __ add(Operand(esp), Immediate(kPointerSize));
+            __ jmp(false_label_);
+            break;
+          }
+          case Expression::kTestValue: {
+            Label discard;
+            __ mov(eax, Operand(esp, 0));
+            __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
+            TestAndBranch(eax, &discard, false_label_);
+            __ bind(&discard);
+            __ add(Operand(esp), Immediate(kPointerSize));
+            __ jmp(true_label_);
+            break;
+          }
+        }
          break;
-      case Expression::kValue:
-        // Perform assignment and preserve value.
-        __ mov(eax, Operand(esp, 0));
-        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-        break;
-      case Expression::kTest:
-        // Perform assignment and test (and discard) value.
-        __ pop(eax);
-        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-        TestAndBranch(eax, true_label_, false_label_);
-        break;
-      case Expression::kValueTest: {
-        Label discard;
-        __ mov(eax, Operand(esp, 0));
-        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-        TestAndBranch(eax, true_label_, &discard);
-        __ bind(&discard);
-        __ add(Operand(esp), Immediate(kPointerSize));
-        __ jmp(false_label_);
-        break;
-      }
-      case Expression::kTestValue: {
-        Label discard;
-        __ mov(eax, Operand(esp, 0));
-        __ mov(Operand(ebp, SlotOffset(var->slot())), eax);
-        TestAndBranch(eax, &discard, false_label_);
-        __ bind(&discard);
-        __ add(Operand(esp), Immediate(kPointerSize));
-        __ jmp(true_label_);
+      }
+
+      case Slot::CONTEXT: {
+        int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the context chain to the context containing the slot.
+          __ mov(eax,
+                  Operand(esi,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+          // Load the function context (which is the incoming, outer  
context).
+          __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ mov(eax,
+                    Operand(eax,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+            __ mov(eax, FieldOperand(eax, JSFunction::kContextOffset));
+          }
+        } else {  // Slot is in the current context.  Generate optimized  
code.
+          __ mov(eax, esi);  // RecordWrite destroys the object register.
+        }
+        if (FLAG_debug_code) {
+          __ cmp(eax,
+                  Operand(eax,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+          __ Check(equal, "Context Slot chain length wrong.");
+        }
+        __ pop(ecx);
+        __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx);
+
+        // RecordWrite may destroy all its register arguments.
+        if (expr->context() == Expression::kValue) {
+          __ push(ecx);
+        } else if (expr->context() != Expression::kEffect) {
+          __ mov(edx, ecx);
+        }
+        int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
+        __ RecordWrite(eax, offset, ecx, ebx);
+        if (expr->context() != Expression::kEffect &&
+            expr->context() != Expression::kValue) {
+          Move(expr->context(), edx);
+        }
          break;
        }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
      }
    }
  }
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Nov  5 09:33:50  
2009
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Nov  9 01:56:57  
2009
@@ -418,6 +418,7 @@
    Comment cmnt(masm_, "[ VariableProxy");
    Expression* rewrite = expr->var()->rewrite();
    if (rewrite == NULL) {
+    ASSERT(expr->var()->is_global());
      Comment cmnt(masm_, "Global variable");
      // Use inline caching. Variable name is passed in rcx and the global
      // object on the stack.
@@ -425,14 +426,55 @@
      __ Move(rcx, expr->name());
      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
      __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
-
      // A test rax instruction following the call is used by the IC to
      // indicate that the inobject property case was inlined.  Ensure there
      // is no test rax instruction here.
+    __ nop();
+
      DropAndMove(expr->context(), rax);
    } else {
-    Comment cmnt(masm_, "Stack slot");
-    Move(expr->context(), rewrite->AsSlot());
+    Slot* slot = rewrite->AsSlot();
+    ASSERT_NE(NULL, slot);
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        Comment cmnt(masm_, "Stack slot");
+        Move(expr->context(), slot);
+        break;
+      }
+
+      case Slot::CONTEXT: {
+        Comment cmnt(masm_, "Context slot");
+         int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the chain of contexts to the context containing the  
slot.
+          __ movq(rax,
+                  Operand(rsi,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+          // Load the function context (which is the incoming, outer  
context).
+          __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ movq(rax,
+                    Operand(rax,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+            __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
+          }
+          // The context may be an intermediate context, not a function  
context.
+          __ movq(rax,
+                  Operand(rax,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+        } else {  // Slot is in the current function context.
+          // The context may be an intermediate context, not a function  
context.
+          __ movq(rax,
+                  Operand(rsi,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+        }
+        __ movq(rax, Operand(rax, Context::SlotOffset(slot->index())));
+        Move(expr->context(), rax);
+        break;
+      }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
+    }
    }
  }

@@ -695,44 +737,96 @@
      DropAndMove(expr->context(), rax);

    } else {
-    switch (expr->context()) {
-      case Expression::kUninitialized:
-        UNREACHABLE();
-      case Expression::kEffect:
-        // Perform assignment and discard value.
-        __ pop(Operand(rbp, SlotOffset(var->slot())));
+    Slot* slot = var->slot();
+    ASSERT_NOT_NULL(slot);  // Variables rewritten as properties not  
handled.
+    switch (slot->type()) {
+      case Slot::LOCAL:
+      case Slot::PARAMETER: {
+        switch (expr->context()) {
+          case Expression::kUninitialized:
+            UNREACHABLE();
+          case Expression::kEffect:
+            // Perform assignment and discard value.
+            __ pop(Operand(rbp, SlotOffset(var->slot())));
+            break;
+          case Expression::kValue:
+            // Perform assignment and preserve value.
+            __ movq(rax, Operand(rsp, 0));
+            __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+            break;
+          case Expression::kTest:
+            // Perform assignment and test (and discard) value.
+            __ pop(rax);
+            __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+            TestAndBranch(rax, true_label_, false_label_);
+            break;
+          case Expression::kValueTest: {
+            Label discard;
+            __ movq(rax, Operand(rsp, 0));
+            __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+            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));
+            __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
+            TestAndBranch(rax, &discard, false_label_);
+            __ bind(&discard);
+            __ addq(rsp, Immediate(kPointerSize));
+            __ jmp(true_label_);
+            break;
+          }
+        }
          break;
-      case Expression::kValue:
-        // Perform assignment and preserve value.
-        __ movq(rax, Operand(rsp, 0));
-        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-        break;
-      case Expression::kTest:
-        // Perform assignment and test (and discard) value.
-        __ pop(rax);
-        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-        TestAndBranch(rax, true_label_, false_label_);
-        break;
-      case Expression::kValueTest: {
-        Label discard;
-        __ movq(rax, Operand(rsp, 0));
-        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-        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));
-        __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
-        TestAndBranch(rax, &discard, false_label_);
-        __ bind(&discard);
-        __ addq(rsp, Immediate(kPointerSize));
-        __ jmp(true_label_);
+      }
+
+      case Slot::CONTEXT: {
+        int chain_length =
+            function_->scope()->ContextChainLength(slot->var()->scope());
+        if (chain_length > 0) {
+          // Move up the context chain to the context containing the slot.
+          __ movq(rax,
+                  Operand(rsi,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+          // Load the function context (which is the incoming, outer  
context).
+          __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
+          for (int i = 1; i < chain_length; i++) {
+            __ movq(rax,
+                    Operand(rax,  
Context::SlotOffset(Context::CLOSURE_INDEX)));
+            __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
+          }
+        } else {  // Slot is in the current context.  Generate optimized  
code.
+          __ movq(rax, rsi);  // RecordWrite destroys the object register.
+        }
+        if (FLAG_debug_code) {
+          __ cmpq(rax,
+                  Operand(rax,  
Context::SlotOffset(Context::FCONTEXT_INDEX)));
+          __ Check(equal, "Context Slot chain length wrong.");
+        }
+        __ pop(rcx);
+        __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx);
+
+        // RecordWrite may destroy all its register arguments.
+        if (expr->context() == Expression::kValue) {
+          __ push(rcx);
+        } else if (expr->context() != Expression::kEffect) {
+          __ movq(rdx, rcx);
+        }
+        int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
+        __ RecordWrite(rax, offset, rcx, rbx);
+        if (expr->context() != Expression::kEffect &&
+            expr->context() != Expression::kValue) {
+          Move(expr->context(), rdx);
+        }
          break;
        }
+
+      case Slot::LOOKUP:
+        UNREACHABLE();
+        break;
      }
    }
  }

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to