From: sgjesse@chromium.org Date: Thu, 24 Feb 2011 11:36:14 +0000 (+0000) Subject: X64: Port r6635 and r6659 X-Git-Tag: upstream/4.7.83~20098 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c8f8c69fd65745035d255cd1cdd7e8981df2a779;p=platform%2Fupstream%2Fv8.git X64: Port r6635 and r6659 r6635: Remove the redundant load on every context lookup. r6659: Do not compile the unreachable body of functions with illegal redeclarations. The crankshaft part of these changes are already ported. Review URL: http://codereview.chromium.org/6581029 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6929 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 8711f42..d037021 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -207,43 +207,45 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { Move(dot_arguments_slot, rcx, rbx, rdx); } - { Comment cmnt(masm_, "[ Declarations"); - // For named function expressions, declare the function name as a - // constant. - if (scope()->is_function_scope() && scope()->function() != NULL) { - EmitDeclaration(scope()->function(), Variable::CONST, NULL); - } - // Visit all the explicit declarations unless there is an illegal - // redeclaration. - if (scope()->HasIllegalRedeclaration()) { - scope()->VisitIllegalRedeclaration(this); - } else { - VisitDeclarations(scope()->declarations()); - } - } - if (FLAG_trace) { __ CallRuntime(Runtime::kTraceEnter, 0); } - { Comment cmnt(masm_, "[ Stack check"); - PrepareForBailout(info->function(), NO_REGISTERS); - NearLabel ok; - __ CompareRoot(rsp, Heap::kStackLimitRootIndex); - __ j(above_equal, &ok); - StackCheckStub stub; - __ CallStub(&stub); - __ bind(&ok); - } + // Visit the declarations and body unless there is an illegal + // redeclaration. + if (scope()->HasIllegalRedeclaration()) { + Comment cmnt(masm_, "[ Declarations"); + scope()->VisitIllegalRedeclaration(this); + } else { + { Comment cmnt(masm_, "[ Declarations"); + // For named function expressions, declare the function name as a + // constant. + if (scope()->is_function_scope() && scope()->function() != NULL) { + EmitDeclaration(scope()->function(), Variable::CONST, NULL); + } + VisitDeclarations(scope()->declarations()); + } - { Comment cmnt(masm_, "[ Body"); - ASSERT(loop_depth() == 0); - VisitStatements(function()->body()); - ASSERT(loop_depth() == 0); + { Comment cmnt(masm_, "[ Stack check"); + PrepareForBailout(info->function(), NO_REGISTERS); + NearLabel ok; + __ CompareRoot(rsp, Heap::kStackLimitRootIndex); + __ j(above_equal, &ok); + StackCheckStub stub; + __ CallStub(&stub); + __ bind(&ok); + } + + { Comment cmnt(masm_, "[ Body"); + ASSERT(loop_depth() == 0); + VisitStatements(function()->body()); + ASSERT(loop_depth() == 0); + } } + // Always emit a 'return undefined' in case control fell off the end of + // the body. { Comment cmnt(masm_, "[ return ;"); - // Emit a 'return undefined' in case control fell off the end of the body. __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); EmitReturnSequence(); } @@ -1082,7 +1084,10 @@ MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( // Check that last extension is NULL. __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); __ j(not_equal, slow); - __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); + + // This function is used only for loads, not stores, so it's safe to + // return an rsi-based operand (the write barrier cannot be allowed to + // destroy the rsi register). return ContextOperand(temp, slot->index()); } @@ -1730,57 +1735,75 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, : Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); - } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { - // Perform the assignment for non-const variables and for initialization - // of const variables. Const assignments are simply skipped. - Label done; + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function + // scope. However, unlike var initializers, const initializers are able + // to drill a hole to that function context, even from inside a 'with' + // context. We thus bypass the normal static scope lookup. + Slot* slot = var->AsSlot(); + Label skip; + switch (slot->type()) { + case Slot::PARAMETER: + // No const parameters. + UNREACHABLE(); + break; + case Slot::LOCAL: + __ movq(rdx, Operand(rbp, SlotOffset(slot))); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &skip); + __ movq(Operand(rbp, SlotOffset(slot)), rax); + break; + case Slot::CONTEXT: { + __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); + __ movq(rdx, ContextOperand(rcx, slot->index())); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &skip); + __ movq(ContextOperand(rcx, slot->index()), rax); + int offset = Context::SlotOffset(slot->index()); + __ movq(rdx, rax); // Preserve the stored value in eax. + __ RecordWrite(rcx, offset, rdx, rbx); + break; + } + case Slot::LOOKUP: + __ push(rax); + __ push(rsi); + __ Push(var->name()); + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); + break; + } + __ bind(&skip); + + } else if (var->mode() != Variable::CONST) { + // Perform the assignment for non-const variables. Const assignments + // are simply skipped. Slot* slot = var->AsSlot(); switch (slot->type()) { case Slot::PARAMETER: case Slot::LOCAL: - if (op == Token::INIT_CONST) { - // Detect const reinitialization by checking for the hole value. - __ movq(rdx, Operand(rbp, SlotOffset(slot))); - __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); - __ j(not_equal, &done); - } // Perform the assignment. __ movq(Operand(rbp, SlotOffset(slot)), rax); break; case Slot::CONTEXT: { MemOperand target = EmitSlotSearch(slot, rcx); - if (op == Token::INIT_CONST) { - // Detect const reinitialization by checking for the hole value. - __ movq(rdx, target); - __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); - __ j(not_equal, &done); - } // Perform the assignment and issue the write barrier. __ movq(target, rax); // The value of the assignment is in rax. RecordWrite clobbers its // register arguments. __ movq(rdx, rax); - int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; + int offset = Context::SlotOffset(slot->index()); __ RecordWrite(rcx, offset, rdx, rbx); break; } case Slot::LOOKUP: - // Call the runtime for the assignment. The runtime will ignore - // const reinitialization. + // Call the runtime for the assignment. __ push(rax); // Value. __ push(rsi); // Context. __ Push(var->name()); - if (op == Token::INIT_CONST) { - // The runtime will ignore const redeclaration. - __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); - } else { - __ CallRuntime(Runtime::kStoreContextSlot, 3); - } + __ CallRuntime(Runtime::kStoreContextSlot, 3); break; } - __ bind(&done); } } diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 48e42c8..e55b26c 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -136,7 +136,7 @@ void MacroAssembler::RecordWrite(Register object, Register value) { // The compiled code assumes that record write doesn't change the // context register, so we check that none of the clobbered - // registers are esi. + // registers are rsi. ASSERT(!object.is(rsi) && !value.is(rsi) && !address.is(rsi)); // First, check if a write barrier is even needed. The tests below @@ -2531,9 +2531,21 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) { } // The context may be an intermediate context, not a function context. movq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); - } else { // context is the current function context. - // The context may be an intermediate context, not a function context. - movq(dst, Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX))); + } else { + // Slot is in the current function context. Move it into the + // destination register in case we store into it (the write barrier + // cannot be allowed to destroy the context in rsi). + movq(dst, rsi); + } + + // We should not have found a 'with' context by walking the context chain + // (i.e., the static scope chain and runtime context chain do not agree). + // A variable occurring in such a scope should have slot type LOOKUP and + // not CONTEXT. + if (FLAG_debug_code) { + cmpq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); + Check(equal, "Yo dawg, I heard you liked function contexts " + "so I put function contexts in all your contexts"); } }