Enable writes and reads of context slots in fast compiler.
Review URL: http://codereview.chromium.org/360054 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3242 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
0afb1e1697
commit
493c9f072c
@ -364,6 +364,7 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
|
|||||||
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
|
__ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
|
||||||
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
||||||
__ mov(r2, Operand(offset));
|
__ mov(r2, Operand(offset));
|
||||||
|
// We know that we have written a function, which is not a smi.
|
||||||
__ RecordWrite(cp, r2, r0);
|
__ RecordWrite(cp, r2, r0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -421,6 +422,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
Comment cmnt(masm_, "[ VariableProxy");
|
Comment cmnt(masm_, "[ VariableProxy");
|
||||||
Expression* rewrite = expr->var()->rewrite();
|
Expression* rewrite = expr->var()->rewrite();
|
||||||
if (rewrite == NULL) {
|
if (rewrite == NULL) {
|
||||||
|
ASSERT(expr->var()->is_global());
|
||||||
Comment cmnt(masm_, "Global variable");
|
Comment cmnt(masm_, "Global variable");
|
||||||
// Use inline caching. Variable name is passed in r2 and the global
|
// Use inline caching. Variable name is passed in r2 and the global
|
||||||
// object on the stack.
|
// object on the stack.
|
||||||
@ -431,8 +433,47 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||||
DropAndMove(expr->context(), r0);
|
DropAndMove(expr->context(), r0);
|
||||||
} else {
|
} else {
|
||||||
|
Slot* slot = rewrite->AsSlot();
|
||||||
|
ASSERT_NE(NULL, slot);
|
||||||
|
switch (slot->type()) {
|
||||||
|
case Slot::LOCAL:
|
||||||
|
case Slot::PARAMETER: {
|
||||||
Comment cmnt(masm_, "Stack slot");
|
Comment cmnt(masm_, "Stack slot");
|
||||||
Move(expr->context(), rewrite->AsSlot());
|
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,6 +746,11 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
DropAndMove(expr->context(), r0);
|
DropAndMove(expr->context(), r0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
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()) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -745,6 +791,59 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,6 +650,16 @@ void CodeGenSelector::VisitDeclaration(Declaration* decl) {
|
|||||||
if (decl->fun() != NULL) {
|
if (decl->fun() != NULL) {
|
||||||
ProcessExpression(decl->fun(), Expression::kValue);
|
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 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Slot::Type type = slot->type();
|
Slot::Type type = slot->type();
|
||||||
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
// When LOOKUP slots are enabled, some currently dead code
|
||||||
BAILOUT("non-parameter/non-local slot reference");
|
// implementing unary typeof will become live.
|
||||||
|
if (type == Slot::LOOKUP) {
|
||||||
|
BAILOUT("Lookup slot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -883,8 +895,8 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
|||||||
BAILOUT("non-global/non-slot assignment");
|
BAILOUT("non-global/non-slot assignment");
|
||||||
}
|
}
|
||||||
Slot::Type type = var->slot()->type();
|
Slot::Type type = var->slot()->type();
|
||||||
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
if (type == Slot::LOOKUP) {
|
||||||
BAILOUT("non-parameter/non-local slot assignment");
|
BAILOUT("Lookup slot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (prop != NULL) {
|
} else if (prop != NULL) {
|
||||||
|
@ -410,6 +410,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
Comment cmnt(masm_, "[ VariableProxy");
|
Comment cmnt(masm_, "[ VariableProxy");
|
||||||
Expression* rewrite = expr->var()->rewrite();
|
Expression* rewrite = expr->var()->rewrite();
|
||||||
if (rewrite == NULL) {
|
if (rewrite == NULL) {
|
||||||
|
ASSERT(expr->var()->is_global());
|
||||||
Comment cmnt(masm_, "Global variable");
|
Comment cmnt(masm_, "Global variable");
|
||||||
// Use inline caching. Variable name is passed in ecx and the global
|
// Use inline caching. Variable name is passed in ecx and the global
|
||||||
// object on the stack.
|
// object on the stack.
|
||||||
@ -425,8 +426,48 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
|
|
||||||
DropAndMove(expr->context(), eax);
|
DropAndMove(expr->context(), eax);
|
||||||
} else {
|
} else {
|
||||||
|
Slot* slot = rewrite->AsSlot();
|
||||||
|
ASSERT_NE(NULL, slot);
|
||||||
|
switch (slot->type()) {
|
||||||
|
case Slot::LOCAL:
|
||||||
|
case Slot::PARAMETER: {
|
||||||
Comment cmnt(masm_, "Stack slot");
|
Comment cmnt(masm_, "Stack slot");
|
||||||
Move(expr->context(), rewrite->AsSlot());
|
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,6 +734,11 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
DropAndMove(expr->context(), eax);
|
DropAndMove(expr->context(), eax);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
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()) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -732,6 +778,53 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,6 +418,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
Comment cmnt(masm_, "[ VariableProxy");
|
Comment cmnt(masm_, "[ VariableProxy");
|
||||||
Expression* rewrite = expr->var()->rewrite();
|
Expression* rewrite = expr->var()->rewrite();
|
||||||
if (rewrite == NULL) {
|
if (rewrite == NULL) {
|
||||||
|
ASSERT(expr->var()->is_global());
|
||||||
Comment cmnt(masm_, "Global variable");
|
Comment cmnt(masm_, "Global variable");
|
||||||
// Use inline caching. Variable name is passed in rcx and the global
|
// Use inline caching. Variable name is passed in rcx and the global
|
||||||
// object on the stack.
|
// object on the stack.
|
||||||
@ -425,14 +426,55 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
|||||||
__ Move(rcx, expr->name());
|
__ Move(rcx, expr->name());
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||||
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||||
|
|
||||||
// A test rax instruction following the call is used by the IC to
|
// A test rax instruction following the call is used by the IC to
|
||||||
// indicate that the inobject property case was inlined. Ensure there
|
// indicate that the inobject property case was inlined. Ensure there
|
||||||
// is no test rax instruction here.
|
// is no test rax instruction here.
|
||||||
|
__ nop();
|
||||||
|
|
||||||
DropAndMove(expr->context(), rax);
|
DropAndMove(expr->context(), rax);
|
||||||
} else {
|
} else {
|
||||||
|
Slot* slot = rewrite->AsSlot();
|
||||||
|
ASSERT_NE(NULL, slot);
|
||||||
|
switch (slot->type()) {
|
||||||
|
case Slot::LOCAL:
|
||||||
|
case Slot::PARAMETER: {
|
||||||
Comment cmnt(masm_, "Stack slot");
|
Comment cmnt(masm_, "Stack slot");
|
||||||
Move(expr->context(), rewrite->AsSlot());
|
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,6 +737,11 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
DropAndMove(expr->context(), rax);
|
DropAndMove(expr->context(), rax);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
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()) {
|
switch (expr->context()) {
|
||||||
case Expression::kUninitialized:
|
case Expression::kUninitialized:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -734,6 +781,53 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user