diff options
Diffstat (limited to 'deps/v8/src/x64')
-rw-r--r-- | deps/v8/src/x64/assembler-x64.cc | 16 | ||||
-rw-r--r-- | deps/v8/src/x64/assembler-x64.h | 1 | ||||
-rw-r--r-- | deps/v8/src/x64/codegen-x64.cc | 55 | ||||
-rw-r--r-- | deps/v8/src/x64/debug-x64.cc | 5 | ||||
-rw-r--r-- | deps/v8/src/x64/disasm-x64.cc | 8 | ||||
-rw-r--r-- | deps/v8/src/x64/full-codegen-x64.cc | 2 | ||||
-rw-r--r-- | deps/v8/src/x64/macro-assembler-x64.cc | 172 | ||||
-rw-r--r-- | deps/v8/src/x64/macro-assembler-x64.h | 43 | ||||
-rw-r--r-- | deps/v8/src/x64/stub-cache-x64.cc | 81 |
9 files changed, 344 insertions, 39 deletions
diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index c66666a73a..b62db14cb8 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -1496,12 +1496,8 @@ void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) { void Assembler::movq(Register dst, ExternalReference ref) { - EnsureSpace ensure_space(this); - last_pc_ = pc_; - emit_rex_64(dst); - emit(0xB8 | dst.low_bits()); - emitq(reinterpret_cast<uintptr_t>(ref.address()), - RelocInfo::EXTERNAL_REFERENCE); + int64_t value = reinterpret_cast<int64_t>(ref.address()); + movq(dst, value, RelocInfo::EXTERNAL_REFERENCE); } @@ -2529,10 +2525,10 @@ void Assembler::movd(Register dst, XMMRegister src) { EnsureSpace ensure_space(this); last_pc_ = pc_; emit(0x66); - emit_optional_rex_32(dst, src); + emit_optional_rex_32(src, dst); emit(0x0F); emit(0x7E); - emit_sse_operand(dst, src); + emit_sse_operand(src, dst); } @@ -2551,10 +2547,10 @@ void Assembler::movq(Register dst, XMMRegister src) { EnsureSpace ensure_space(this); last_pc_ = pc_; emit(0x66); - emit_rex_64(dst, src); + emit_rex_64(src, dst); emit(0x0F); emit(0x7E); - emit_sse_operand(dst, src); + emit_sse_operand(src, dst); } diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h index 213db2cc8f..7082af7fe1 100644 --- a/deps/v8/src/x64/assembler-x64.h +++ b/deps/v8/src/x64/assembler-x64.h @@ -509,7 +509,6 @@ class Assembler : public Malloced { void push(Immediate value); void push(Register src); void push(const Operand& src); - void push(Label* label, RelocInfo::Mode relocation_mode); void pop(Register dst); void pop(const Operand& dst); diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 35c1a3d0ef..688cd4d75b 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -8071,6 +8071,18 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { result = allocator()->Allocate(); ASSERT(result.is_valid() && receiver.is_valid() && value.is_valid()); + // Cannot use r12 for receiver, because that changes + // the distance between a call and a fixup location, + // due to a special encoding of r12 as r/m in a ModR/M byte. + if (receiver.reg().is(r12)) { + frame()->Spill(receiver.reg()); // It will be overwritten with result. + // Swap receiver and value. + __ movq(result.reg(), receiver.reg()); + Result temp = receiver; + receiver = result; + result = temp; + } + // Check that the receiver is a heap object. Condition is_smi = __ CheckSmi(receiver.reg()); slow.Branch(is_smi, &value, &receiver); @@ -10890,7 +10902,48 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { void ApiGetterEntryStub::Generate(MacroAssembler* masm) { - UNREACHABLE(); + Label empty_result; + Label prologue; + Label promote_scheduled_exception; + __ EnterApiExitFrame(ExitFrame::MODE_NORMAL, kStackSpace, 0); + ASSERT_EQ(kArgc, 4); +#ifdef _WIN64 + // All the parameters should be set up by a caller. +#else + // Set 1st parameter register with property name. + __ movq(rsi, rdx); + // Second parameter register rdi should be set with pointer to AccessorInfo + // by a caller. +#endif + // Call the api function! + __ movq(rax, + reinterpret_cast<int64_t>(fun()->address()), + RelocInfo::RUNTIME_ENTRY); + __ call(rax); + // Check if the function scheduled an exception. + ExternalReference scheduled_exception_address = + ExternalReference::scheduled_exception_address(); + __ movq(rsi, scheduled_exception_address); + __ Cmp(Operand(rsi, 0), Factory::the_hole_value()); + __ j(not_equal, &promote_scheduled_exception); +#ifdef _WIN64 + // rax keeps a pointer to v8::Handle, unpack it. + __ movq(rax, Operand(rax, 0)); +#endif + // Check if the result handle holds 0. + __ testq(rax, rax); + __ j(zero, &empty_result); + // It was non-zero. Dereference to get the result value. + __ movq(rax, Operand(rax, 0)); + __ bind(&prologue); + __ LeaveExitFrame(ExitFrame::MODE_NORMAL); + __ ret(0); + __ bind(&promote_scheduled_exception); + __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); + __ bind(&empty_result); + // It was zero; the result is undefined. + __ Move(rax, Factory::undefined_value()); + __ jmp(&prologue); } diff --git a/deps/v8/src/x64/debug-x64.cc b/deps/v8/src/x64/debug-x64.cc index 96592548ef..2aa77e7752 100644 --- a/deps/v8/src/x64/debug-x64.cc +++ b/deps/v8/src/x64/debug-x64.cc @@ -213,9 +213,10 @@ void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { #undef __ -void Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame, - Handle<Code> code) { +Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame, + Handle<Code> code) { UNREACHABLE(); + return NULL; } const int Debug::kFrameDropperFrameSize = -1; diff --git a/deps/v8/src/x64/disasm-x64.cc b/deps/v8/src/x64/disasm-x64.cc index 06a8c79629..7c9dfc1209 100644 --- a/deps/v8/src/x64/disasm-x64.cc +++ b/deps/v8/src/x64/disasm-x64.cc @@ -1019,10 +1019,10 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { NameOfXMMRegister(regop)); current += PrintRightOperand(current); } else if (opcode == 0x7E) { - AppendToBuffer("mov%c %s,", - rex_w() ? 'q' : 'd', - NameOfCPURegister(regop)); - current += PrintRightXMMOperand(current); + AppendToBuffer("mov%c ", + rex_w() ? 'q' : 'd'); + current += PrintRightOperand(current); + AppendToBuffer(", %s", NameOfXMMRegister(regop)); } else { const char* mnemonic = "?"; if (opcode == 0x57) { diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 0b3b7c4dd4..a8626b3164 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -207,7 +207,7 @@ void FullCodeGenerator::EmitReturnSequence() { Label check_exit_codesize; masm_->bind(&check_exit_codesize); #endif - CodeGenerator::RecordPositions(masm_, function()->end_position()); + CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); __ RecordJSReturn(); // Do not use the leave instruction here because it is too short to // patch with the code required by the debugger. diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc index a5634a794d..88f61d4725 100644 --- a/deps/v8/src/x64/macro-assembler-x64.cc +++ b/deps/v8/src/x64/macro-assembler-x64.cc @@ -336,12 +336,32 @@ void MacroAssembler::CallStub(CodeStub* stub) { } +Object* MacroAssembler::TryCallStub(CodeStub* stub) { + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. + Object* result = stub->TryGetCode(); + if (!result->IsFailure()) { + call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET); + } + return result; +} + + void MacroAssembler::TailCallStub(CodeStub* stub) { ASSERT(allow_stub_calls()); // calls are not allowed in some stubs Jump(stub->GetCode(), RelocInfo::CODE_TARGET); } +Object* MacroAssembler::TryTailCallStub(CodeStub* stub) { + ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. + Object* result = stub->TryGetCode(); + if (!result->IsFailure()) { + jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET); + } + return result; +} + + void MacroAssembler::StubReturn(int argc) { ASSERT(argc >= 1 && generating_stub()); ret((argc - 1) * kPointerSize); @@ -361,6 +381,12 @@ void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { } +Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, + int num_arguments) { + return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); +} + + void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { // If the expected number of arguments of the runtime function is // constant, we check that the actual number of arguments match the @@ -381,6 +407,26 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { } +Object* MacroAssembler::TryCallRuntime(Runtime::Function* f, + int num_arguments) { + if (f->nargs >= 0 && f->nargs != num_arguments) { + IllegalOperation(num_arguments); + // Since we did not call the stub, there was no allocation failure. + // Return some non-failure object. + return Heap::undefined_value(); + } + + // TODO(1236192): Most runtime routines don't need the number of + // arguments passed in because it is constant. At some point we + // should remove this need and make the runtime routine entry code + // smarter. + Set(rax, num_arguments); + movq(rbx, ExternalReference(f)); + CEntryStub ces(f->result_size); + return TryCallStub(&ces); +} + + void MacroAssembler::CallExternalReference(const ExternalReference& ext, int num_arguments) { Set(rax, num_arguments); @@ -417,6 +463,87 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid, } +static int Offset(ExternalReference ref0, ExternalReference ref1) { + int64_t offset = (ref0.address() - ref1.address()); + // Check that fits into int. + ASSERT(static_cast<int>(offset) == offset); + return static_cast<int>(offset); +} + + +void MacroAssembler::PushHandleScope(Register scratch) { + ExternalReference extensions_address = + ExternalReference::handle_scope_extensions_address(); + const int kExtensionsOffset = 0; + const int kNextOffset = Offset( + ExternalReference::handle_scope_next_address(), + extensions_address); + const int kLimitOffset = Offset( + ExternalReference::handle_scope_limit_address(), + extensions_address); + + // Push the number of extensions, smi-tagged so the gc will ignore it. + movq(kScratchRegister, extensions_address); + movq(scratch, Operand(kScratchRegister, kExtensionsOffset)); + movq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0)); + Integer32ToSmi(scratch, scratch); + push(scratch); + // Push next and limit pointers which will be wordsize aligned and + // hence automatically smi tagged. + push(Operand(kScratchRegister, kNextOffset)); + push(Operand(kScratchRegister, kLimitOffset)); +} + + +Object* MacroAssembler::PopHandleScopeHelper(Register saved, + Register scratch, + bool gc_allowed) { + ExternalReference extensions_address = + ExternalReference::handle_scope_extensions_address(); + const int kExtensionsOffset = 0; + const int kNextOffset = Offset( + ExternalReference::handle_scope_next_address(), + extensions_address); + const int kLimitOffset = Offset( + ExternalReference::handle_scope_limit_address(), + extensions_address); + + Object* result = NULL; + Label write_back; + movq(kScratchRegister, extensions_address); + cmpq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0)); + j(equal, &write_back); + push(saved); + if (gc_allowed) { + CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); + } else { + result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); + if (result->IsFailure()) return result; + } + pop(saved); + movq(kScratchRegister, extensions_address); + + bind(&write_back); + pop(Operand(kScratchRegister, kLimitOffset)); + pop(Operand(kScratchRegister, kNextOffset)); + pop(scratch); + SmiToInteger32(scratch, scratch); + movq(Operand(kScratchRegister, kExtensionsOffset), scratch); + + return result; +} + + +void MacroAssembler::PopHandleScope(Register saved, Register scratch) { + PopHandleScopeHelper(saved, scratch, true); +} + + +Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) { + return PopHandleScopeHelper(saved, scratch, false); +} + + void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, int result_size) { // Set the entry point and jump to the C entry runtime stub. @@ -2208,7 +2335,8 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) { } -void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { +void MacroAssembler::EnterExitFramePrologue(ExitFrame::Mode mode, + bool save_rax) { // Setup the frame structure on the stack. // All constants are relative to the frame pointer of the exit frame. ASSERT(ExitFrameConstants::kCallerSPDisplacement == +2 * kPointerSize); @@ -2226,18 +2354,19 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { // Save the frame pointer and the context in top. ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address); ExternalReference context_address(Top::k_context_address); - movq(r14, rax); // Backup rax before we use it. + if (save_rax) { + movq(r14, rax); // Backup rax before we use it. + } movq(rax, rbp); store_rax(c_entry_fp_address); movq(rax, rsi); store_rax(context_address); +} - // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, - // so it must be retained across the C-call. - int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; - lea(r12, Operand(rbp, r14, times_pointer_size, offset)); - +void MacroAssembler::EnterExitFrameEpilogue(ExitFrame::Mode mode, + int result_size, + int argc) { #ifdef ENABLE_DEBUGGER_SUPPORT // Save the state of all registers to the stack from the memory // location. This is needed to allow nested break points. @@ -2258,7 +2387,7 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { // Reserve space for the Arguments object. The Windows 64-bit ABI // requires us to pass this structure as a pointer to its location on // the stack. The structure contains 2 values. - int argument_stack_space = 2 * kPointerSize; + int argument_stack_space = argc * kPointerSize; // We also need backing space for 4 parameters, even though // we only pass one or two parameter, and it is in a register. int argument_mirror_space = 4 * kPointerSize; @@ -2280,6 +2409,33 @@ void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { } +void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode, int result_size) { + EnterExitFramePrologue(mode, true); + + // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, + // so it must be retained across the C-call. + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; + lea(r12, Operand(rbp, r14, times_pointer_size, offset)); + + EnterExitFrameEpilogue(mode, result_size, 2); +} + + +void MacroAssembler::EnterApiExitFrame(ExitFrame::Mode mode, + int stack_space, + int argc, + int result_size) { + EnterExitFramePrologue(mode, false); + + // Setup argv in callee-saved register r12. It is reused in LeaveExitFrame, + // so it must be retained across the C-call. + int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize; + lea(r12, Operand(rbp, (stack_space * kPointerSize) + offset)); + + EnterExitFrameEpilogue(mode, result_size, argc); +} + + void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode, int result_size) { // Registers: // r12 : argv diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h index 64f35e10de..7a90dd0175 100644 --- a/deps/v8/src/x64/macro-assembler-x64.h +++ b/deps/v8/src/x64/macro-assembler-x64.h @@ -163,6 +163,11 @@ class MacroAssembler: public Assembler { // to the first argument in register rsi. void EnterExitFrame(ExitFrame::Mode mode, int result_size = 1); + void EnterApiExitFrame(ExitFrame::Mode mode, + int stack_space, + int argc, + int result_size = 1); + // Leave the current exit frame. Expects/provides the return value in // register rax:rdx (untouched) and the pointer to the first // argument in register rsi. @@ -719,18 +724,36 @@ class MacroAssembler: public Assembler { // Call a code stub. void CallStub(CodeStub* stub); + // Call a code stub and return the code object called. Try to generate + // the code if necessary. Do not perform a GC but instead return a retry + // after GC failure. + Object* TryCallStub(CodeStub* stub); + // Tail call a code stub (jump). void TailCallStub(CodeStub* stub); + // Tail call a code stub (jump) and return the code object called. Try to + // generate the code if necessary. Do not perform a GC but instead return + // a retry after GC failure. + Object* TryTailCallStub(CodeStub* stub); + // Return from a code stub after popping its arguments. void StubReturn(int argc); // Call a runtime routine. void CallRuntime(Runtime::Function* f, int num_arguments); + // Call a runtime function, returning the CodeStub object called. + // Try to generate the stub code if necessary. Do not perform a GC + // but instead return a retry after GC failure. + Object* TryCallRuntime(Runtime::Function* f, int num_arguments); + // Convenience function: Same as above, but takes the fid instead. void CallRuntime(Runtime::FunctionId id, int num_arguments); + // Convenience function: Same as above, but takes the fid instead. + Object* TryCallRuntime(Runtime::FunctionId id, int num_arguments); + // Convenience function: call an external reference. void CallExternalReference(const ExternalReference& ext, int num_arguments); @@ -747,6 +770,16 @@ class MacroAssembler: public Assembler { int num_arguments, int result_size); + void PushHandleScope(Register scratch); + + // Pops a handle scope using the specified scratch register and + // ensuring that saved register is left unchanged. + void PopHandleScope(Register saved, Register scratch); + + // As PopHandleScope, but does not perform a GC. Instead, returns a + // retry after GC failure object if GC is necessary. + Object* TryPopHandleScope(Register saved, Register scratch); + // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& ext, int result_size); @@ -835,6 +868,9 @@ class MacroAssembler: public Assembler { void EnterFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type); + void EnterExitFramePrologue(ExitFrame::Mode mode, bool save_rax); + void EnterExitFrameEpilogue(ExitFrame::Mode mode, int result_size, int argc); + // Allocation support helpers. // Loads the top of new-space into the result register. // If flags contains RESULT_CONTAINS_TOP then result_end is valid and @@ -848,6 +884,13 @@ class MacroAssembler: public Assembler { // Update allocation top with value in result_end register. // If scratch is valid, it contains the address of the allocation top. void UpdateAllocationTopHelper(Register result_end, Register scratch); + + // Helper for PopHandleScope. Allowed to perform a GC and returns + // NULL if gc_allowed. Does not perform a GC if !gc_allowed, and + // possibly returns a failure object indicating an allocation failure. + Object* PopHandleScopeHelper(Register saved, + Register scratch, + bool gc_allowed); }; diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 2a918f1687..e67000a133 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -2211,23 +2211,80 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, // Check that the maps haven't changed. Register reg = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, scratch3, name, miss); + CheckPrototypes(object, receiver, holder, scratch1, + scratch2, scratch3, name, miss); - // Push the arguments on the JS stack of the caller. - __ pop(scratch2); // remove return address + Handle<AccessorInfo> callback_handle(callback); + + __ EnterInternalFrame(); + __ PushHandleScope(scratch2); + // Push the stack address where the list of arguments ends. + __ movq(scratch2, rsp); + __ subq(scratch2, Immediate(2 * kPointerSize)); + __ push(scratch2); __ push(receiver); // receiver __ push(reg); // holder - __ Move(reg, Handle<AccessorInfo>(callback)); // callback data - __ push(reg); - __ push(FieldOperand(reg, AccessorInfo::kDataOffset)); + if (Heap::InNewSpace(callback_handle->data())) { + __ Move(scratch2, callback_handle); + __ push(FieldOperand(scratch2, AccessorInfo::kDataOffset)); // data + } else { + __ Push(Handle<Object>(callback_handle->data())); + } __ push(name_reg); // name - __ push(scratch2); // restore return address + // Save a pointer to where we pushed the arguments pointer. + // This will be passed as the const AccessorInfo& to the C++ callback. + +#ifdef _WIN64 + // Win64 uses first register--rcx--for returned value. + Register accessor_info_arg = r8; + Register name_arg = rdx; +#else + Register accessor_info_arg = rdx; // temporary, copied to rsi by the stub. + Register name_arg = rdi; +#endif - // Do tail-call to the runtime system. - ExternalReference load_callback_property = - ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); - __ TailCallExternalReference(load_callback_property, 5, 1); + __ movq(accessor_info_arg, rsp); + __ addq(accessor_info_arg, Immediate(4 * kPointerSize)); + __ movq(name_arg, rsp); + + // Do call through the api. + ASSERT_EQ(5, ApiGetterEntryStub::kStackSpace); + Address getter_address = v8::ToCData<Address>(callback->getter()); + ApiFunction fun(getter_address); + ApiGetterEntryStub stub(callback_handle, &fun); +#ifdef _WIN64 + // We need to prepare a slot for result handle on stack and put + // a pointer to it into 1st arg register. + __ push(Immediate(0)); + __ movq(rcx, rsp); +#endif + // Emitting a stub call may try to allocate (if the code is not + // already generated). Do not allow the assembler to perform a + // garbage collection but instead return the allocation failure + // object. + Object* result = masm()->TryCallStub(&stub); + if (result->IsFailure()) { + *failure = Failure::cast(result); + return false; + } +#ifdef _WIN64 + // Discard allocated slot. + __ addq(rsp, Immediate(kPointerSize)); +#endif + + // We need to avoid using rax since that now holds the result. + Register tmp = scratch2.is(rax) ? reg : scratch2; + // Emitting PopHandleScope may try to allocate. Do not allow the + // assembler to perform a garbage collection but instead return a + // failure object. + result = masm()->TryPopHandleScope(rax, tmp); + if (result->IsFailure()) { + *failure = Failure::cast(result); + return false; + } + __ LeaveInternalFrame(); + + __ ret(0); return true; } |