diff options
Diffstat (limited to 'deps/v8/src/x64/fast-codegen-x64.cc')
-rw-r--r-- | deps/v8/src/x64/fast-codegen-x64.cc | 353 |
1 files changed, 198 insertions, 155 deletions
diff --git a/deps/v8/src/x64/fast-codegen-x64.cc b/deps/v8/src/x64/fast-codegen-x64.cc index f73f2b90f9..7a991cb07e 100644 --- a/deps/v8/src/x64/fast-codegen-x64.cc +++ b/deps/v8/src/x64/fast-codegen-x64.cc @@ -420,73 +420,97 @@ void FastCodeGenerator::VisitDeclaration(Declaration* decl) { Variable* var = decl->proxy()->var(); ASSERT(var != NULL); // Must have been resolved. Slot* slot = var->slot(); - ASSERT(slot != NULL); // No global declarations here. - - // We have 3 cases for slots: LOOKUP, LOCAL, CONTEXT. - switch (slot->type()) { - case Slot::LOOKUP: { - __ push(rsi); - __ Push(var->name()); - // Declaration nodes are always introduced in one of two modes. - ASSERT(decl->mode() == Variable::VAR || decl->mode() == Variable::CONST); - PropertyAttributes attr = decl->mode() == Variable::VAR ? - NONE : READ_ONLY; - __ Push(Smi::FromInt(attr)); - // Push initial value, if any. - // Note: For variables we must not push an initial value (such as - // 'undefined') because we may have a (legal) redeclaration and we - // must not destroy the current value. - if (decl->mode() == Variable::CONST) { - __ Push(Factory::the_hole_value()); - } else if (decl->fun() != NULL) { - Visit(decl->fun()); - } else { - __ Push(Smi::FromInt(0)); // no initial value! - } - __ CallRuntime(Runtime::kDeclareContextSlot, 4); - break; - } - case Slot::LOCAL: - if (decl->mode() == Variable::CONST) { - __ Move(Operand(rbp, SlotOffset(var->slot())), - Factory::the_hole_value()); - } else if (decl->fun() != NULL) { - Visit(decl->fun()); - __ pop(Operand(rbp, SlotOffset(var->slot()))); - } - break; - case Slot::CONTEXT: - // The variable in the decl always resides in the current context. - ASSERT(function_->scope()->ContextChainLength(slot->var()->scope()) == 0); - if (decl->mode() == Variable::CONST) { - __ Move(rax, Factory::the_hole_value()); + Property* prop = var->AsProperty(); + + if (slot != NULL) { + switch (slot->type()) { + case Slot::PARAMETER: // Fall through. + case Slot::LOCAL: + if (decl->mode() == Variable::CONST) { + __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); + __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); + } else if (decl->fun() != NULL) { + Visit(decl->fun()); + __ pop(Operand(rbp, SlotOffset(var->slot()))); + } + break; + + case Slot::CONTEXT: + // The variable in the decl always resides in the current context. + ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope())); if (FLAG_debug_code) { // Check if we have the correct context pointer. - __ movq(rbx, CodeGenerator::ContextOperand(rsi, - Context::FCONTEXT_INDEX)); + __ movq(rbx, + CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX)); __ cmpq(rbx, rsi); __ Check(equal, "Unexpected declaration in current context."); } - __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); - // No write barrier since the_hole_value is in old space. - ASSERT(!Heap::InNewSpace(*Factory::the_hole_value())); - } else if (decl->fun() != NULL) { + if (decl->mode() == Variable::CONST) { + __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); + __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), + kScratchRegister); + // No write barrier since the hole value is in old space. + } else if (decl->fun() != NULL) { + Visit(decl->fun()); + __ pop(rax); + __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); + int offset = Context::SlotOffset(slot->index()); + __ RecordWrite(rsi, offset, rax, rcx); + } + break; + + case Slot::LOOKUP: { + __ push(rsi); + __ Push(var->name()); + // Declaration nodes are always introduced in one of two modes. + ASSERT(decl->mode() == Variable::VAR || + decl->mode() == Variable::CONST); + PropertyAttributes attr = + (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; + __ Push(Smi::FromInt(attr)); + // Push initial value, if any. + // Note: For variables we must not push an initial value (such as + // 'undefined') because we may have a (legal) redeclaration and we + // must not destroy the current value. + if (decl->mode() == Variable::CONST) { + __ PushRoot(Heap::kTheHoleValueRootIndex); + } else if (decl->fun() != NULL) { + Visit(decl->fun()); + } else { + __ Push(Smi::FromInt(0)); // no initial value! + } + __ CallRuntime(Runtime::kDeclareContextSlot, 4); + break; + } + } + + } else if (prop != NULL) { + if (decl->fun() != NULL || decl->mode() == Variable::CONST) { + // We are declaring a function or constant that rewrites to a + // property. Use (keyed) IC to set the initial value. + ASSERT_EQ(Expression::kValue, prop->obj()->context()); + Visit(prop->obj()); + ASSERT_EQ(Expression::kValue, prop->key()->context()); + Visit(prop->key()); + + if (decl->fun() != NULL) { + ASSERT_EQ(Expression::kValue, decl->fun()->context()); Visit(decl->fun()); __ pop(rax); - if (FLAG_debug_code) { - // Check if we have the correct context pointer. - __ movq(rbx, CodeGenerator::ContextOperand(rsi, - Context::FCONTEXT_INDEX)); - __ cmpq(rbx, rsi); - __ Check(equal, "Unexpected declaration in current context."); - } - __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax); - int offset = Context::SlotOffset(slot->index()); - __ RecordWrite(rsi, offset, rax, rcx); + } else { + __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); } - break; - default: - UNREACHABLE(); + + Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + + // Absence of a test rax instruction following the call + // indicates that none of the load was inlined. + + // Value in rax is ignored (declarations are statements). Receiver + // and key on stack are discarded. + __ addq(rsp, Immediate(2 * kPointerSize)); + } } } @@ -501,20 +525,6 @@ void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { } -void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { - Comment cmnt(masm_, "[ ReturnStatement"); - Expression* expr = stmt->expression(); - if (expr->AsLiteral() != NULL) { - __ Move(rax, expr->AsLiteral()->handle()); - } else { - Visit(expr); - ASSERT_EQ(Expression::kValue, expr->context()); - __ pop(rax); - } - EmitReturnSequence(stmt->statement_pos()); -} - - void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { Comment cmnt(masm_, "[ FunctionLiteral"); @@ -535,14 +545,20 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { Comment cmnt(masm_, "[ VariableProxy"); - Expression* rewrite = expr->var()->rewrite(); + EmitVariableLoad(expr->var(), expr->context()); +} + + +void FastCodeGenerator::EmitVariableLoad(Variable* var, + Expression::Context context) { + Expression* rewrite = var->rewrite(); if (rewrite == NULL) { - ASSERT(expr->var()->is_global()); + ASSERT(var->is_global()); Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in rcx and the global // object on the stack. __ push(CodeGenerator::GlobalObject()); - __ Move(rcx, expr->name()); + __ Move(rcx, var->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 @@ -550,7 +566,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { // is no test rax instruction here. __ nop(); - DropAndMove(expr->context(), rax); + DropAndMove(context, rax); } else if (rewrite->AsSlot() != NULL) { Slot* slot = rewrite->AsSlot(); if (FLAG_debug_code) { @@ -571,7 +587,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { UNREACHABLE(); } } - Move(expr->context(), slot, rax); + Move(context, slot, rax); } else { // A variable has been rewritten into an explicit access to // an object property. @@ -605,7 +621,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { // the call. It is treated specially by the LoadIC code. // Drop key and object left on the stack by IC, and push the result. - DropAndMove(expr->context(), rax, 2); + DropAndMove(context, rax, 2); } } @@ -639,31 +655,14 @@ void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { Comment cmnt(masm_, "[ ObjectLiteral"); - Label boilerplate_exists; - __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); - __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); - int literal_offset = - FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; - __ movq(rax, FieldOperand(rbx, literal_offset)); - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); - __ j(not_equal, &boilerplate_exists); - // Create boilerplate if it does not exist. - // Literal array (0). - __ push(rbx); - // Literal index (1). + __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(expr->literal_index())); - // Constant properties (2). __ Push(expr->constant_properties()); - __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); - __ bind(&boilerplate_exists); - // rax contains boilerplate. - // Clone boilerplate. - __ push(rax); - if (expr->depth() == 1) { - __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); + if (expr->depth() > 1) { + __ CallRuntime(Runtime::kCreateObjectLiteral, 3); } else { - __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); + __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); } // If result_saved == true: The result is saved on top of the @@ -759,31 +758,14 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { Comment cmnt(masm_, "[ ArrayLiteral"); - Label make_clone; - - // Fetch the function's literals array. __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); - __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); - // Check if the literal's boilerplate has been instantiated. - int offset = - FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); - __ movq(rax, FieldOperand(rbx, offset)); - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); - __ j(not_equal, &make_clone); - - // Instantiate the boilerplate. - __ push(rbx); + __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset)); __ Push(Smi::FromInt(expr->literal_index())); __ Push(expr->literals()); - __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3); - - __ bind(&make_clone); - // Clone the boilerplate. - __ push(rax); if (expr->depth() > 1) { - __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); + __ CallRuntime(Runtime::kCreateArrayLiteral, 3); } else { - __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); + __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); } bool result_saved = false; // Is the result saved to the stack? @@ -853,10 +835,37 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { } +void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, + Expression::Context context) { + Literal* key = prop->key()->AsLiteral(); + __ Move(rcx, key->handle()); + Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + Move(context, rax); +} + + +void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { + Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + Move(context, rax); +} + + +void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op, + Expression::Context context) { + GenericBinaryOpStub stub(op, + NO_OVERWRITE, + NO_GENERIC_BINARY_FLAGS); + __ CallStub(&stub); + Move(context, rax); +} + + void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { Variable* var = expr->target()->AsVariableProxy()->AsVariable(); ASSERT(var != NULL); - + ASSERT(var->is_global() || var->slot() != NULL); if (var->is_global()) { // Assignment to a global variable. Use inline caching for the // assignment. Right-hand-side value is passed in rax, variable name in @@ -961,36 +970,6 @@ void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) { UNREACHABLE(); break; } - } else { - Property* property = var->AsProperty(); - ASSERT_NOT_NULL(property); - // A variable has been rewritten into a property on an object. - - // Load object and key onto the stack. - Slot* object_slot = property->obj()->AsSlot(); - ASSERT_NOT_NULL(object_slot); - Move(Expression::kValue, object_slot, rax); - - Literal* key_literal = property->key()->AsLiteral(); - ASSERT_NOT_NULL(key_literal); - Move(Expression::kValue, key_literal); - - // Value to store was pushed before object and key on the stack. - __ movq(rax, Operand(rsp, 2 * kPointerSize)); - - // Arguments to ic is value in rax, object and key on stack. - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); - __ call(ic, RelocInfo::CODE_TARGET); - - if (expr->context() == Expression::kEffect) { - __ addq(rsp, Immediate(3 * kPointerSize)); - } else if (expr->context() == Expression::kValue) { - // Value is still on the stack in rsp[2 * kPointerSize] - __ addq(rsp, Immediate(2 * kPointerSize)); - } else { - __ movq(rax, Operand(rsp, 2 * kPointerSize)); - DropAndMove(expr->context(), rax, 3); - } } } @@ -1097,7 +1076,9 @@ void FastCodeGenerator::VisitProperty(Property* expr) { } -void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { +void FastCodeGenerator::EmitCallWithIC(Call* expr, + Handle<Object> ignored, + RelocInfo::Mode mode) { // Code common for calls using the IC. ZoneList<Expression*>* args = expr->arguments(); int arg_count = args->length(); @@ -1110,7 +1091,7 @@ void FastCodeGenerator::EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info) { // Call the IC initialization code. Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, NOT_IN_LOOP); - __ call(ic, reloc_info); + __ call(ic, mode); // Restore context register. __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); // Discard the function left on TOS. @@ -1149,7 +1130,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { __ Push(var->name()); // Push global object as receiver for the call IC lookup. __ push(CodeGenerator::GlobalObject()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET_CONTEXT); + EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { // Call to a lookup slot. @@ -1162,7 +1143,7 @@ void FastCodeGenerator::VisitCall(Call* expr) { // Call to a named property, use call IC. __ Push(key->handle()); Visit(prop->obj()); - EmitCallWithIC(expr, RelocInfo::CODE_TARGET); + EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { // Call to a keyed property, use keyed load IC followed by function // call. @@ -1684,6 +1665,68 @@ void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { } +void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { + __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); + Move(expr->context(), rax); +} + + +Register FastCodeGenerator::result_register() { return rax; } + + +Register FastCodeGenerator::context_register() { return rsi; } + + +void FastCodeGenerator::StoreToFrameField(int frame_offset, Register value) { + ASSERT(IsAligned(frame_offset, kPointerSize)); + __ movq(Operand(rbp, frame_offset), value); +} + + +void FastCodeGenerator::LoadContextField(Register dst, int context_index) { + __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index)); +} + + +// ---------------------------------------------------------------------------- +// Non-local control flow support. + + +void FastCodeGenerator::EnterFinallyBlock() { + ASSERT(!result_register().is(rdx)); + ASSERT(!result_register().is(rcx)); + // Cook return address on top of stack (smi encoded Code* delta) + __ movq(rdx, Operand(rsp, 0)); + __ Move(rcx, masm_->CodeObject()); + __ subq(rdx, rcx); + __ Integer32ToSmi(rdx, rdx); + __ movq(Operand(rsp, 0), rdx); + // Store result register while executing finally block. + __ push(result_register()); +} + + +void FastCodeGenerator::ExitFinallyBlock() { + ASSERT(!result_register().is(rdx)); + ASSERT(!result_register().is(rcx)); + // Restore result register from stack. + __ pop(result_register()); + // Uncook return address. + __ movq(rdx, Operand(rsp, 0)); + __ SmiToInteger32(rdx, rdx); + __ Move(rcx, masm_->CodeObject()); + __ addq(rdx, rcx); + __ movq(Operand(rsp, 0), rdx); + // And return. + __ ret(0); +} + + +void FastCodeGenerator::ThrowException() { + __ push(result_register()); + __ CallRuntime(Runtime::kThrow, 1); +} + #undef __ |