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
-~----------~----~----~----~------~----~------~--~---