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()));
|
||||
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 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
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 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
__ 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 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||
DropAndMove(expr->context(), r0);
|
||||
|
||||
} else {
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
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 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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -650,6 +650,16 @@ void CodeGenSelector::VisitDeclaration(Declaration* decl) {
|
||||
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 @@ void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
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 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
||||
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) {
|
||||
|
@ -410,6 +410,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
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 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
|
||||
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 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||
DropAndMove(expr->context(), eax);
|
||||
|
||||
} else {
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
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 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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,6 +418,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
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 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
__ 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 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
|
||||
DropAndMove(expr->context(), rax);
|
||||
|
||||
} else {
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
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 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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user