diff options
author | Timothy J Fontaine <tjfontaine@gmail.com> | 2013-10-22 15:14:25 -0700 |
---|---|---|
committer | Timothy J Fontaine <tjfontaine@gmail.com> | 2013-10-23 09:17:31 -0700 |
commit | a53c763c16eeabb0901a05dbcf38a72fa96d2f26 (patch) | |
tree | 309bf250e1521cedf0e945d7a7629db511e64498 /deps/v8/src/arm | |
parent | 54910044b33a6405c72ad085915a55c575c027fc (diff) | |
download | node-new-a53c763c16eeabb0901a05dbcf38a72fa96d2f26.tar.gz |
v8: upgrade 3.21.18.3
Diffstat (limited to 'deps/v8/src/arm')
25 files changed, 1342 insertions, 2076 deletions
diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h index bfe9bc8335..a1d1e1b567 100644 --- a/deps/v8/src/arm/assembler-arm-inl.h +++ b/deps/v8/src/arm/assembler-arm-inl.h @@ -279,7 +279,7 @@ bool RelocInfo::IsPatchedDebugBreakSlotSequence() { } -void RelocInfo::Visit(ObjectVisitor* visitor) { +void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { RelocInfo::Mode mode = rmode(); if (mode == RelocInfo::EMBEDDED_OBJECT) { visitor->VisitEmbeddedPointer(this); @@ -292,12 +292,11 @@ void RelocInfo::Visit(ObjectVisitor* visitor) { } else if (RelocInfo::IsCodeAgeSequence(mode)) { visitor->VisitCodeAgeSequence(this); #ifdef ENABLE_DEBUGGER_SUPPORT - // TODO(isolates): Get a cached isolate below. } else if (((RelocInfo::IsJSReturn(mode) && IsPatchedReturnSequence()) || (RelocInfo::IsDebugBreakSlot(mode) && IsPatchedDebugBreakSlotSequence())) && - Isolate::Current()->debug()->has_break_points()) { + isolate->debug()->has_break_points()) { visitor->VisitDebugTarget(this); #endif } else if (RelocInfo::IsRuntimeEntry(mode)) { diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index a9db5a5994..bd8b0613eb 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -39,6 +39,7 @@ #if V8_TARGET_ARCH_ARM #include "arm/assembler-arm-inl.h" +#include "macro-assembler.h" #include "serialize.h" namespace v8 { @@ -152,7 +153,8 @@ void CpuFeatures::Probe() { #else // __arm__ // Probe for additional features not already known to be available. - if (!IsSupported(VFP3) && FLAG_enable_vfp3 && OS::ArmCpuHasFeature(VFP3)) { + CPU cpu; + if (!IsSupported(VFP3) && FLAG_enable_vfp3 && cpu.has_vfp3()) { // This implementation also sets the VFP flags if runtime // detection of VFP returns true. VFPv3 implies ARMv7, see ARM DDI // 0406B, page A1-6. @@ -161,38 +163,40 @@ void CpuFeatures::Probe() { static_cast<uint64_t>(1) << ARMv7; } - if (!IsSupported(NEON) && FLAG_enable_neon && OS::ArmCpuHasFeature(NEON)) { + if (!IsSupported(NEON) && FLAG_enable_neon && cpu.has_neon()) { found_by_runtime_probing_only_ |= 1u << NEON; } - if (!IsSupported(ARMv7) && FLAG_enable_armv7 && OS::ArmCpuHasFeature(ARMv7)) { + if (!IsSupported(ARMv7) && FLAG_enable_armv7 && cpu.architecture() >= 7) { found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << ARMv7; } - if (!IsSupported(SUDIV) && FLAG_enable_sudiv && OS::ArmCpuHasFeature(SUDIV)) { + if (!IsSupported(SUDIV) && FLAG_enable_sudiv && cpu.has_idiva()) { found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << SUDIV; } if (!IsSupported(UNALIGNED_ACCESSES) && FLAG_enable_unaligned_accesses - && OS::ArmCpuHasFeature(ARMv7)) { + && cpu.architecture() >= 7) { found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << UNALIGNED_ACCESSES; } - CpuImplementer implementer = OS::GetCpuImplementer(); - if (implementer == QUALCOMM_IMPLEMENTER && - FLAG_enable_movw_movt && OS::ArmCpuHasFeature(ARMv7)) { + // Use movw/movt for QUALCOMM ARMv7 cores. + if (cpu.implementer() == CPU::QUALCOMM && + cpu.architecture() >= 7 && + FLAG_enable_movw_movt) { found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << MOVW_MOVT_IMMEDIATE_LOADS; } - CpuPart part = OS::GetCpuPart(implementer); - if ((part == CORTEX_A9) || (part == CORTEX_A5)) { + // ARM Cortex-A9 and Cortex-A5 have 32 byte cachelines. + if (cpu.implementer() == CPU::ARM && + (cpu.part() == CPU::ARM_CORTEX_A5 || + cpu.part() == CPU::ARM_CORTEX_A9)) { cache_line_size_ = 32; } - if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs - && OS::ArmCpuHasFeature(VFP32DREGS)) { + if (!IsSupported(VFP32DREGS) && FLAG_enable_32dregs && cpu.has_vfp3_d32()) { found_by_runtime_probing_only_ |= static_cast<uint64_t>(1) << VFP32DREGS; } @@ -321,15 +325,12 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) { // See assembler-arm-inl.h for inlined constructors Operand::Operand(Handle<Object> handle) { -#ifdef DEBUG - Isolate* isolate = Isolate::Current(); -#endif AllowDeferredHandleDereference using_raw_address; rm_ = no_reg; // Verify all Objects referred by code are NOT in new space. Object* obj = *handle; - ASSERT(!isolate->heap()->InNewSpace(obj)); if (obj->IsHeapObject()) { + ASSERT(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj)); imm32_ = reinterpret_cast<intptr_t>(handle.location()); rmode_ = RelocInfo::EMBEDDED_OBJECT; } else { @@ -775,9 +776,9 @@ int Assembler::GetCmpImmediateRawImmediate(Instr instr) { int Assembler::target_at(int pos) { Instr instr = instr_at(pos); - if ((instr & ~kImm24Mask) == 0) { - // Emitted label constant, not part of a branch. - return instr - (Code::kHeaderSize - kHeapObjectTag); + if (is_uint24(instr)) { + // Emitted link to a label, not part of a branch. + return instr; } ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 int imm26 = ((instr & kImm24Mask) << 8) >> 6; @@ -792,11 +793,72 @@ int Assembler::target_at(int pos) { void Assembler::target_at_put(int pos, int target_pos) { Instr instr = instr_at(pos); - if ((instr & ~kImm24Mask) == 0) { + if (is_uint24(instr)) { ASSERT(target_pos == pos || target_pos >= 0); - // Emitted label constant, not part of a branch. - // Make label relative to Code* of generated Code object. - instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); + // Emitted link to a label, not part of a branch. + // Load the position of the label relative to the generated code object + // pointer in a register. + + // Here are the instructions we need to emit: + // For ARMv7: target24 => target16_1:target16_0 + // movw dst, #target16_0 + // movt dst, #target16_1 + // For ARMv6: target24 => target8_2:target8_1:target8_0 + // mov dst, #target8_0 + // orr dst, dst, #target8_1 << 8 + // orr dst, dst, #target8_2 << 16 + + // We extract the destination register from the emitted nop instruction. + Register dst = Register::from_code( + Instruction::RmValue(instr_at(pos + kInstrSize))); + ASSERT(IsNop(instr_at(pos + kInstrSize), dst.code())); + uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag); + ASSERT(is_uint24(target24)); + if (is_uint8(target24)) { + // If the target fits in a byte then only patch with a mov + // instruction. + CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), + 1, + CodePatcher::DONT_FLUSH); + patcher.masm()->mov(dst, Operand(target24)); + } else { + uint16_t target16_0 = target24 & kImm16Mask; + uint16_t target16_1 = target24 >> 16; + if (CpuFeatures::IsSupported(ARMv7)) { + // Patch with movw/movt. + if (target16_1 == 0) { + CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), + 1, + CodePatcher::DONT_FLUSH); + patcher.masm()->movw(dst, target16_0); + } else { + CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), + 2, + CodePatcher::DONT_FLUSH); + patcher.masm()->movw(dst, target16_0); + patcher.masm()->movt(dst, target16_1); + } + } else { + // Patch with a sequence of mov/orr/orr instructions. + uint8_t target8_0 = target16_0 & kImm8Mask; + uint8_t target8_1 = target16_0 >> 8; + uint8_t target8_2 = target16_1 & kImm8Mask; + if (target8_2 == 0) { + CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), + 2, + CodePatcher::DONT_FLUSH); + patcher.masm()->mov(dst, Operand(target8_0)); + patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); + } else { + CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos), + 3, + CodePatcher::DONT_FLUSH); + patcher.masm()->mov(dst, Operand(target8_0)); + patcher.masm()->orr(dst, dst, Operand(target8_1 << 8)); + patcher.masm()->orr(dst, dst, Operand(target8_2 << 16)); + } + } + } return; } int imm26 = target_pos - (pos + kPcLoadDelta); @@ -1229,21 +1291,6 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { } -void Assembler::label_at_put(Label* L, int at_offset) { - int target_pos; - ASSERT(!L->is_bound()); - if (L->is_linked()) { - // Point to previous instruction that uses the link. - target_pos = L->pos(); - } else { - // First entry of the link chain points to itself. - target_pos = at_offset; - } - L->link_to(at_offset); - instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); -} - - // Branch instructions. void Assembler::b(int branch_offset, Condition cond) { ASSERT((branch_offset & 3) == 0); @@ -1386,6 +1433,45 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) { } +void Assembler::mov_label_offset(Register dst, Label* label) { + if (label->is_bound()) { + mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag))); + } else { + // Emit the link to the label in the code stream followed by extra nop + // instructions. + // If the label is not linked, then start a new link chain by linking it to + // itself, emitting pc_offset(). + int link = label->is_linked() ? label->pos() : pc_offset(); + label->link_to(pc_offset()); + + // When the label is bound, these instructions will be patched with a + // sequence of movw/movt or mov/orr/orr instructions. They will load the + // destination register with the position of the label from the beginning + // of the code. + // + // The link will be extracted from the first instruction and the destination + // register from the second. + // For ARMv7: + // link + // mov dst, dst + // For ARMv6: + // link + // mov dst, dst + // mov dst, dst + // + // When the label gets bound: target_at extracts the link and target_at_put + // patches the instructions. + ASSERT(is_uint24(link)); + BlockConstPoolScope block_const_pool(this); + emit(link); + nop(dst.code()); + if (!CpuFeatures::IsSupported(ARMv7)) { + nop(dst.code()); + } + } +} + + void Assembler::movw(Register reg, uint32_t immediate, Condition cond) { ASSERT(immediate < 0x10000); // May use movw if supported, but on unsupported platforms will try to use diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index f647848de5..866b1c9024 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -748,10 +748,6 @@ class Assembler : public AssemblerBase { // Manages the jump elimination optimization if the second parameter is true. int branch_offset(Label* L, bool jump_elimination_allowed); - // Puts a labels target address at the given position. - // The high 8 bits are set to zero. - void label_at_put(Label* L, int at_offset); - // Return the address in the constant pool of the code target address used by // the branch/call instruction at pc, or the object in a mov. INLINE(static Address target_pointer_address_at(Address pc)); @@ -903,6 +899,10 @@ class Assembler : public AssemblerBase { mov(dst, Operand(src), s, cond); } + // Load the position of the label relative to the generated code object + // pointer in a register. + void mov_label_offset(Register dst, Label* label); + // ARMv7 instructions for loading a 32 bit immediate in two instructions. // This may actually emit a different mov instruction, but on an ARMv7 it // is guaranteed to only emit one instruction. @@ -1561,7 +1561,6 @@ class Assembler : public AssemblerBase { void RecordRelocInfo(double data); void RecordRelocInfoConstantPoolEntryHelper(const RelocInfo& rinfo); - friend class RegExpMacroAssemblerARM; friend class RelocInfo; friend class CodePatcher; friend class BlockConstPoolScope; diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc index 5f3a999f56..f60e1f8671 100644 --- a/deps/v8/src/arm/builtins-arm.cc +++ b/deps/v8/src/arm/builtins-arm.cc @@ -291,68 +291,55 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { } +static void CallRuntimePassFunction(MacroAssembler* masm, + Runtime::FunctionId function_id) { + FrameScope scope(masm, StackFrame::INTERNAL); + // Push a copy of the function onto the stack. + __ push(r1); + // Push call kind information. + __ push(r5); + // Function is also the parameter to the runtime call. + __ push(r1); + + __ CallRuntime(function_id, 1); + // Restore call kind information. + __ pop(r5); + // Restore receiver. + __ pop(r1); +} + + static void GenerateTailCallToSharedCode(MacroAssembler* masm) { __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset)); __ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ mov(pc, r2); + __ Jump(r2); } void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) { + // Checking whether the queued function is ready for install is optional, + // since we come across interrupts and stack checks elsewhere. However, + // not checking may delay installing ready functions, and always checking + // would be quite expensive. A good compromise is to first check against + // stack limit as a cue for an interrupt signal. + Label ok; + __ LoadRoot(ip, Heap::kStackLimitRootIndex); + __ cmp(sp, Operand(ip)); + __ b(hs, &ok); + + CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode); + // Tail call to returned code. + __ add(r0, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ Jump(r0); + + __ bind(&ok); GenerateTailCallToSharedCode(masm); } -void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) { - // Enter an internal frame. - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Preserve the function. - __ push(r1); - // Push call kind information. - __ push(r5); - - // Push the function on the stack as the argument to the runtime function. - __ push(r1); - __ CallRuntime(Runtime::kInstallRecompiledCode, 1); - // Calculate the entry point. - __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); - - // Restore call kind information. - __ pop(r5); - // Restore saved function. - __ pop(r1); - - // Tear down internal frame. - } - - // Do a tail-call of the compiled function. - __ Jump(r2); -} - - -void Builtins::Generate_ParallelRecompile(MacroAssembler* masm) { - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Push a copy of the function onto the stack. - __ push(r1); - // Push call kind information. - __ push(r5); - - __ push(r1); // Function is also the parameter to the runtime call. - __ CallRuntime(Runtime::kParallelRecompile, 1); - - // Restore call kind information. - __ pop(r5); - // Restore receiver. - __ pop(r1); - - // Tear down internal frame. - } - +void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) { + CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile); GenerateTailCallToSharedCode(masm); } @@ -795,59 +782,17 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { void Builtins::Generate_LazyCompile(MacroAssembler* masm) { - // Enter an internal frame. - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Preserve the function. - __ push(r1); - // Push call kind information. - __ push(r5); - - // Push the function on the stack as the argument to the runtime function. - __ push(r1); - __ CallRuntime(Runtime::kLazyCompile, 1); - // Calculate the entry point. - __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); - - // Restore call kind information. - __ pop(r5); - // Restore saved function. - __ pop(r1); - - // Tear down internal frame. - } - + CallRuntimePassFunction(masm, Runtime::kLazyCompile); // Do a tail-call of the compiled function. + __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); __ Jump(r2); } void Builtins::Generate_LazyRecompile(MacroAssembler* masm) { - // Enter an internal frame. - { - FrameScope scope(masm, StackFrame::INTERNAL); - - // Preserve the function. - __ push(r1); - // Push call kind information. - __ push(r5); - - // Push the function on the stack as the argument to the runtime function. - __ push(r1); - __ CallRuntime(Runtime::kLazyRecompile, 1); - // Calculate the entry point. - __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); - - // Restore call kind information. - __ pop(r5); - // Restore saved function. - __ pop(r1); - - // Tear down internal frame. - } - + CallRuntimePassFunction(masm, Runtime::kLazyRecompile); // Do a tail-call of the compiled function. + __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); __ Jump(r2); } @@ -966,31 +911,48 @@ void Builtins::Generate_NotifyOSR(MacroAssembler* masm) { void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { - // Lookup the function in the JavaScript frame and push it as an - // argument to the on-stack replacement function. + // Lookup the function in the JavaScript frame. __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); { FrameScope scope(masm, StackFrame::INTERNAL); + // Lookup and calculate pc offset. + __ ldr(r1, MemOperand(fp, StandardFrameConstants::kCallerPCOffset)); + __ ldr(r2, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); + __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset)); + __ sub(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ sub(r1, r1, r2); + __ SmiTag(r1); + + // Pass both function and pc offset as arguments. __ push(r0); - __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1); + __ push(r1); + __ CallRuntime(Runtime::kCompileForOnStackReplacement, 2); } - // If the result was -1 it means that we couldn't optimize the - // function. Just return and continue in the unoptimized version. + // If the code object is null, just return to the unoptimized code. Label skip; - __ cmp(r0, Operand(Smi::FromInt(-1))); + __ cmp(r0, Operand(Smi::FromInt(0))); __ b(ne, &skip); __ Ret(); __ bind(&skip); - // Untag the AST id and push it on the stack. - __ SmiUntag(r0); - __ push(r0); - - // Generate the code for doing the frame-to-frame translation using - // the deoptimizer infrastructure. - Deoptimizer::EntryGenerator generator(masm, Deoptimizer::OSR); - generator.Generate(); + + // Load deoptimization data from the code object. + // <deopt_data> = <code>[#deoptimization_data_offset] + __ ldr(r1, MemOperand(r0, Code::kDeoptimizationDataOffset - kHeapObjectTag)); + + // Load the OSR entrypoint offset from the deoptimization data. + // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset] + __ ldr(r1, MemOperand(r1, FixedArray::OffsetOfElementAt( + DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag)); + + // Compute the target address = code_obj + header_size + osr_offset + // <entry_addr> = <code_obj> + #header_size + <osr_offset> + __ add(r0, r0, Operand::SmiUntag(r1)); + __ add(lr, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); + + // And "return" to the OSR entry point of the function. + __ Ret(); } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 5858eac629..cd1809fb2a 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -38,6 +38,17 @@ namespace v8 { namespace internal { +void FastNewClosureStub::InitializeInterfaceDescriptor( + Isolate* isolate, + CodeStubInterfaceDescriptor* descriptor) { + static Register registers[] = { r2 }; + descriptor->register_param_count_ = 1; + descriptor->register_params_ = registers; + descriptor->deoptimization_handler_ = + Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; +} + + void ToNumberStub::InitializeInterfaceDescriptor( Isolate* isolate, CodeStubInterfaceDescriptor* descriptor) { @@ -309,134 +320,6 @@ void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { } -void FastNewClosureStub::Generate(MacroAssembler* masm) { - // Create a new closure from the given function info in new - // space. Set the context to the current context in cp. - Counters* counters = masm->isolate()->counters(); - - Label gc; - - // Pop the function info from the stack. - __ pop(r3); - - // Attempt to allocate new JSFunction in new space. - __ Allocate(JSFunction::kSize, r0, r1, r2, &gc, TAG_OBJECT); - - __ IncrementCounter(counters->fast_new_closure_total(), 1, r6, r7); - - int map_index = Context::FunctionMapIndex(language_mode_, is_generator_); - - // Compute the function map in the current native context and set that - // as the map of the allocated object. - __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); - __ ldr(r2, FieldMemOperand(r2, GlobalObject::kNativeContextOffset)); - __ ldr(r5, MemOperand(r2, Context::SlotOffset(map_index))); - __ str(r5, FieldMemOperand(r0, HeapObject::kMapOffset)); - - // Initialize the rest of the function. We don't have to update the - // write barrier because the allocated object is in new space. - __ LoadRoot(r1, Heap::kEmptyFixedArrayRootIndex); - __ LoadRoot(r5, Heap::kTheHoleValueRootIndex); - __ str(r1, FieldMemOperand(r0, JSObject::kPropertiesOffset)); - __ str(r1, FieldMemOperand(r0, JSObject::kElementsOffset)); - __ str(r5, FieldMemOperand(r0, JSFunction::kPrototypeOrInitialMapOffset)); - __ str(r3, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); - __ str(cp, FieldMemOperand(r0, JSFunction::kContextOffset)); - __ str(r1, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); - - // Initialize the code pointer in the function to be the one - // found in the shared function info object. - // But first check if there is an optimized version for our context. - Label check_optimized; - Label install_unoptimized; - if (FLAG_cache_optimized_code) { - __ ldr(r1, - FieldMemOperand(r3, SharedFunctionInfo::kOptimizedCodeMapOffset)); - __ tst(r1, r1); - __ b(ne, &check_optimized); - } - __ bind(&install_unoptimized); - __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); - __ str(r4, FieldMemOperand(r0, JSFunction::kNextFunctionLinkOffset)); - __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); - __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ str(r3, FieldMemOperand(r0, JSFunction::kCodeEntryOffset)); - - // Return result. The argument function info has been popped already. - __ Ret(); - - __ bind(&check_optimized); - - __ IncrementCounter(counters->fast_new_closure_try_optimized(), 1, r6, r7); - - // r2 holds native context, r1 points to fixed array of 3-element entries - // (native context, optimized code, literals). - // The optimized code map must never be empty, so check the first elements. - Label install_optimized; - // Speculatively move code object into r4. - __ ldr(r4, FieldMemOperand(r1, SharedFunctionInfo::kFirstCodeSlot)); - __ ldr(r5, FieldMemOperand(r1, SharedFunctionInfo::kFirstContextSlot)); - __ cmp(r2, r5); - __ b(eq, &install_optimized); - - // Iterate through the rest of map backwards. r4 holds an index as a Smi. - Label loop; - __ ldr(r4, FieldMemOperand(r1, FixedArray::kLengthOffset)); - __ bind(&loop); - // Do not double check first entry. - __ cmp(r4, Operand(Smi::FromInt(SharedFunctionInfo::kSecondEntryIndex))); - __ b(eq, &install_unoptimized); - __ sub(r4, r4, Operand(Smi::FromInt(SharedFunctionInfo::kEntryLength))); - __ add(r5, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(r5, r5, Operand::PointerOffsetFromSmiKey(r4)); - __ ldr(r5, MemOperand(r5)); - __ cmp(r2, r5); - __ b(ne, &loop); - // Hit: fetch the optimized code. - __ add(r5, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(r5, r5, Operand::PointerOffsetFromSmiKey(r4)); - __ add(r5, r5, Operand(kPointerSize)); - __ ldr(r4, MemOperand(r5)); - - __ bind(&install_optimized); - __ IncrementCounter(counters->fast_new_closure_install_optimized(), - 1, r6, r7); - - // TODO(fschneider): Idea: store proper code pointers in the map and either - // unmangle them on marking or do nothing as the whole map is discarded on - // major GC anyway. - __ add(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ str(r4, FieldMemOperand(r0, JSFunction::kCodeEntryOffset)); - - // Now link a function into a list of optimized functions. - __ ldr(r4, ContextOperand(r2, Context::OPTIMIZED_FUNCTIONS_LIST)); - - __ str(r4, FieldMemOperand(r0, JSFunction::kNextFunctionLinkOffset)); - // No need for write barrier as JSFunction (eax) is in the new space. - - __ str(r0, ContextOperand(r2, Context::OPTIMIZED_FUNCTIONS_LIST)); - // Store JSFunction (eax) into edx before issuing write barrier as - // it clobbers all the registers passed. - __ mov(r4, r0); - __ RecordWriteContextSlot( - r2, - Context::SlotOffset(Context::OPTIMIZED_FUNCTIONS_LIST), - r4, - r1, - kLRHasNotBeenSaved, - kDontSaveFPRegs); - - // Return result. The argument function info has been popped already. - __ Ret(); - - // Create a new closure through the slower runtime call. - __ bind(&gc); - __ LoadRoot(r4, Heap::kFalseValueRootIndex); - __ Push(cp, r3, r4); - __ TailCallRuntime(Runtime::kNewClosure, 3, 1); -} - - void FastNewContextStub::Generate(MacroAssembler* masm) { // Try to allocate the context in new space. Label gc; @@ -634,7 +517,112 @@ void ConvertToDoubleStub::Generate(MacroAssembler* masm) { } -bool WriteInt32ToHeapNumberStub::IsPregenerated() { +void DoubleToIStub::Generate(MacroAssembler* masm) { + Label out_of_range, only_low, negate, done; + Register input_reg = source(); + Register result_reg = destination(); + + int double_offset = offset(); + // Account for saved regs if input is sp. + if (input_reg.is(sp)) double_offset += 2 * kPointerSize; + + // Immediate values for this stub fit in instructions, so it's safe to use ip. + Register scratch = ip; + Register scratch_low = + GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch); + Register scratch_high = + GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low); + LowDwVfpRegister double_scratch = kScratchDoubleReg; + + __ Push(scratch_high, scratch_low); + + if (!skip_fastpath()) { + // Load double input. + __ vldr(double_scratch, MemOperand(input_reg, double_offset)); + __ vmov(scratch_low, scratch_high, double_scratch); + + // Do fast-path convert from double to int. + __ vcvt_s32_f64(double_scratch.low(), double_scratch); + __ vmov(result_reg, double_scratch.low()); + + // If result is not saturated (0x7fffffff or 0x80000000), we are done. + __ sub(scratch, result_reg, Operand(1)); + __ cmp(scratch, Operand(0x7ffffffe)); + __ b(lt, &done); + } else { + // We've already done MacroAssembler::TryFastTruncatedDoubleToILoad, so we + // know exponent > 31, so we can skip the vcvt_s32_f64 which will saturate. + if (double_offset == 0) { + __ ldm(ia, input_reg, scratch_low.bit() | scratch_high.bit()); + } else { + __ ldr(scratch_low, MemOperand(input_reg, double_offset)); + __ ldr(scratch_high, MemOperand(input_reg, double_offset + kIntSize)); + } + } + + __ Ubfx(scratch, scratch_high, + HeapNumber::kExponentShift, HeapNumber::kExponentBits); + // Load scratch with exponent - 1. This is faster than loading + // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value. + STATIC_ASSERT(HeapNumber::kExponentBias + 1 == 1024); + __ sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1)); + // If exponent is greater than or equal to 84, the 32 less significant + // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits), + // the result is 0. + // Compare exponent with 84 (compare exponent - 1 with 83). + __ cmp(scratch, Operand(83)); + __ b(ge, &out_of_range); + + // If we reach this code, 31 <= exponent <= 83. + // So, we don't have to handle cases where 0 <= exponent <= 20 for + // which we would need to shift right the high part of the mantissa. + // Scratch contains exponent - 1. + // Load scratch with 52 - exponent (load with 51 - (exponent - 1)). + __ rsb(scratch, scratch, Operand(51), SetCC); + __ b(ls, &only_low); + // 21 <= exponent <= 51, shift scratch_low and scratch_high + // to generate the result. + __ mov(scratch_low, Operand(scratch_low, LSR, scratch)); + // Scratch contains: 52 - exponent. + // We needs: exponent - 20. + // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20. + __ rsb(scratch, scratch, Operand(32)); + __ Ubfx(result_reg, scratch_high, + 0, HeapNumber::kMantissaBitsInTopWord); + // Set the implicit 1 before the mantissa part in scratch_high. + __ orr(result_reg, result_reg, + Operand(1 << HeapNumber::kMantissaBitsInTopWord)); + __ orr(result_reg, scratch_low, Operand(result_reg, LSL, scratch)); + __ b(&negate); + + __ bind(&out_of_range); + __ mov(result_reg, Operand::Zero()); + __ b(&done); + + __ bind(&only_low); + // 52 <= exponent <= 83, shift only scratch_low. + // On entry, scratch contains: 52 - exponent. + __ rsb(scratch, scratch, Operand::Zero()); + __ mov(result_reg, Operand(scratch_low, LSL, scratch)); + + __ bind(&negate); + // If input was positive, scratch_high ASR 31 equals 0 and + // scratch_high LSR 31 equals zero. + // New result = (result eor 0) + 0 = result. + // If the input was negative, we have to negate the result. + // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1. + // New result = (result eor 0xffffffff) + 1 = 0 - result. + __ eor(result_reg, result_reg, Operand(scratch_high, ASR, 31)); + __ add(result_reg, result_reg, Operand(scratch_high, LSR, 31)); + + __ bind(&done); + + __ Pop(scratch_high, scratch_low); + __ Ret(); +} + + +bool WriteInt32ToHeapNumberStub::IsPregenerated(Isolate* isolate) { // These variants are compiled ahead of time. See next method. if (the_int_.is(r1) && the_heap_number_.is(r0) && scratch_.is(r2)) { return true; @@ -1591,7 +1579,6 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, Register right = r0; Register scratch1 = r6; Register scratch2 = r7; - Register scratch3 = r4; ASSERT(smi_operands || (not_numbers != NULL)); if (smi_operands) { @@ -1689,12 +1676,8 @@ void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm, __ SmiUntag(r2, right); } else { // Convert operands to 32-bit integers. Right in r2 and left in r3. - __ ConvertNumberToInt32( - left, r3, heap_number_map, - scratch1, scratch2, scratch3, d0, d1, not_numbers); - __ ConvertNumberToInt32( - right, r2, heap_number_map, - scratch1, scratch2, scratch3, d0, d1, not_numbers); + __ TruncateNumberToI(left, r3, heap_number_map, scratch1, not_numbers); + __ TruncateNumberToI(right, r2, heap_number_map, scratch1, not_numbers); } Label result_not_a_smi; @@ -2508,16 +2491,6 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { } -void StackCheckStub::Generate(MacroAssembler* masm) { - __ TailCallRuntime(Runtime::kStackGuard, 0, 1); -} - - -void InterruptStub::Generate(MacroAssembler* masm) { - __ TailCallRuntime(Runtime::kInterrupt, 0, 1); -} - - void MathPowStub::Generate(MacroAssembler* masm) { const Register base = r1; const Register exponent = r2; @@ -2721,8 +2694,8 @@ bool CEntryStub::NeedsImmovableCode() { } -bool CEntryStub::IsPregenerated() { - return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && +bool CEntryStub::IsPregenerated(Isolate* isolate) { + return (!save_doubles_ || isolate->fp_stubs_generated()) && result_size_ == 1; } @@ -5817,7 +5790,6 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, __ b(lt, &done); // Check the number to string cache. - Label not_cached; __ bind(¬_string); // Puts the cached result into scratch1. NumberToStringStub::GenerateLookupNumberStringCache(masm, @@ -5826,26 +5798,9 @@ void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, scratch2, scratch3, scratch4, - ¬_cached); + slow); __ mov(arg, scratch1); __ str(arg, MemOperand(sp, stack_offset)); - __ jmp(&done); - - // Check if the argument is a safe string wrapper. - __ bind(¬_cached); - __ JumpIfSmi(arg, slow); - __ CompareObjectType( - arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1. - __ b(ne, slow); - __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); - __ and_(scratch2, - scratch2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ cmp(scratch2, - Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ b(ne, slow); - __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset)); - __ str(arg, MemOperand(sp, stack_offset)); - __ bind(&done); } @@ -6170,6 +6125,11 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) { void DirectCEntryStub::Generate(MacroAssembler* masm) { + // Place the return address on the stack, making the call + // GC safe. The RegExp backend also relies on this. + __ str(lr, MemOperand(sp, 0)); + __ blx(ip); // Call the C++ function. + __ VFPEnsureFPSCRState(r2); __ ldr(pc, MemOperand(sp, 0)); } @@ -6178,21 +6138,9 @@ void DirectCEntryStub::GenerateCall(MacroAssembler* masm, Register target) { intptr_t code = reinterpret_cast<intptr_t>(GetCode(masm->isolate()).location()); + __ Move(ip, target); __ mov(lr, Operand(code, RelocInfo::CODE_TARGET)); - - // Prevent literal pool emission during calculation of return address. - Assembler::BlockConstPoolScope block_const_pool(masm); - - // Push return address (accessible to GC through exit frame pc). - // Note that using pc with str is deprecated. - Label start; - __ bind(&start); - __ add(ip, pc, Operand(Assembler::kInstrSize)); - __ str(ip, MemOperand(sp, 0)); - __ Jump(target); // Call the C++ function. - ASSERT_EQ(Assembler::kInstrSize + Assembler::kPcLoadDelta, - masm->SizeOfCodeGeneratedSince(&start)); - __ VFPEnsureFPSCRState(r2); + __ blx(lr); // Call the stub. } @@ -6458,8 +6406,6 @@ static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. // Also used in KeyedStoreIC::GenerateGeneric. { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET }, - // Used in CompileStoreGlobal. - { REG(r4), REG(r1), REG(r2), OMIT_REMEMBERED_SET }, // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET }, { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET }, @@ -6491,7 +6437,7 @@ static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { #undef REG -bool RecordWriteStub::IsPregenerated() { +bool RecordWriteStub::IsPregenerated(Isolate* isolate) { for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; !entry->object.is(no_reg); entry++) { @@ -6870,6 +6816,9 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { #else // Under the simulator we need to indirect the entry hook through a // trampoline function at a known address. + // It additionally takes an isolate as a third parameter + __ mov(r2, Operand(ExternalReference::isolate_address(masm->isolate()))); + ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline)); __ mov(ip, Operand(ExternalReference(&dispatcher, ExternalReference::BUILTIN_CALL, @@ -6888,90 +6837,128 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) { template<class T> -static void CreateArrayDispatch(MacroAssembler* masm) { - int last_index = GetSequenceIndexFromFastElementsKind( - TERMINAL_FAST_ELEMENTS_KIND); - for (int i = 0; i <= last_index; ++i) { - Label next; - ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); - __ cmp(r3, Operand(kind)); - __ b(ne, &next); - T stub(kind); +static void CreateArrayDispatch(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (mode == DISABLE_ALLOCATION_SITES) { + T stub(GetInitialFastElementsKind(), + CONTEXT_CHECK_REQUIRED, + mode); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(r3, Operand(kind)); + __ b(ne, &next); + T stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } -static void CreateArrayDispatchOneArgument(MacroAssembler* masm) { - // r2 - type info cell - // r3 - kind +static void CreateArrayDispatchOneArgument(MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES) + // r3 - kind (if mode != DISABLE_ALLOCATION_SITES) // r0 - number of arguments // r1 - constructor? // sp[0] - last argument - ASSERT(FAST_SMI_ELEMENTS == 0); - ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); - ASSERT(FAST_ELEMENTS == 2); - ASSERT(FAST_HOLEY_ELEMENTS == 3); - ASSERT(FAST_DOUBLE_ELEMENTS == 4); - ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); - - // is the low bit set? If so, we are holey and that is good. - __ tst(r3, Operand(1)); Label normal_sequence; - __ b(ne, &normal_sequence); + if (mode == DONT_OVERRIDE) { + ASSERT(FAST_SMI_ELEMENTS == 0); + ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + ASSERT(FAST_ELEMENTS == 2); + ASSERT(FAST_HOLEY_ELEMENTS == 3); + ASSERT(FAST_DOUBLE_ELEMENTS == 4); + ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); + + // is the low bit set? If so, we are holey and that is good. + __ tst(r3, Operand(1)); + __ b(ne, &normal_sequence); + } // look at the first argument __ ldr(r5, MemOperand(sp, 0)); __ cmp(r5, Operand::Zero()); __ b(eq, &normal_sequence); - // We are going to create a holey array, but our kind is non-holey. - // Fix kind and retry (only if we have an allocation site in the cell). - __ add(r3, r3, Operand(1)); - __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); - __ b(eq, &normal_sequence); - __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); - __ ldr(r5, FieldMemOperand(r5, 0)); - __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); - __ b(ne, &normal_sequence); + if (mode == DISABLE_ALLOCATION_SITES) { + ElementsKind initial = GetInitialFastElementsKind(); + ElementsKind holey_initial = GetHoleyElementsKind(initial); - // Save the resulting elements kind in type info - __ SmiTag(r3); - __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); - __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); - __ SmiUntag(r3); + ArraySingleArgumentConstructorStub stub_holey(holey_initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); + __ TailCallStub(&stub_holey); - __ bind(&normal_sequence); - int last_index = GetSequenceIndexFromFastElementsKind( - TERMINAL_FAST_ELEMENTS_KIND); - for (int i = 0; i <= last_index; ++i) { - Label next; - ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); - __ cmp(r3, Operand(kind)); - __ b(ne, &next); - ArraySingleArgumentConstructorStub stub(kind); + __ bind(&normal_sequence); + ArraySingleArgumentConstructorStub stub(initial, + CONTEXT_CHECK_REQUIRED, + DISABLE_ALLOCATION_SITES); __ TailCallStub(&stub); - __ bind(&next); - } + } else if (mode == DONT_OVERRIDE) { + // We are going to create a holey array, but our kind is non-holey. + // Fix kind and retry (only if we have an allocation site in the cell). + __ add(r3, r3, Operand(1)); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); + + if (FLAG_debug_code) { + __ ldr(r5, FieldMemOperand(r5, 0)); + __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); + __ Assert(eq, kExpectedAllocationSiteInCell); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); + } - // If we reached this point there is a problem. - __ Abort(kUnexpectedElementsKindInArrayConstructor); + // Save the resulting elements kind in type info + __ SmiTag(r3); + __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset)); + __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); + __ SmiUntag(r3); + + __ bind(&normal_sequence); + int last_index = GetSequenceIndexFromFastElementsKind( + TERMINAL_FAST_ELEMENTS_KIND); + for (int i = 0; i <= last_index; ++i) { + Label next; + ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); + __ cmp(r3, Operand(kind)); + __ b(ne, &next); + ArraySingleArgumentConstructorStub stub(kind); + __ TailCallStub(&stub); + __ bind(&next); + } + + // If we reached this point there is a problem. + __ Abort(kUnexpectedElementsKindInArrayConstructor); + } else { + UNREACHABLE(); + } } template<class T> static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) { + ElementsKind initial_kind = GetInitialFastElementsKind(); + ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind); + int to_index = GetSequenceIndexFromFastElementsKind( TERMINAL_FAST_ELEMENTS_KIND); for (int i = 0; i <= to_index; ++i) { ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); T stub(kind); stub.GetCode(isolate)->set_is_pregenerated(true); - if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) { + if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE || + (!FLAG_track_allocation_sites && + (kind == initial_kind || kind == initial_holey_kind))) { T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES); stub1.GetCode(isolate)->set_is_pregenerated(true); } @@ -7004,6 +6991,34 @@ void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime( } +void ArrayConstructorStub::GenerateDispatchToArrayStub( + MacroAssembler* masm, + AllocationSiteOverrideMode mode) { + if (argument_count_ == ANY) { + Label not_zero_case, not_one_case; + __ tst(r0, r0); + __ b(ne, ¬_zero_case); + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); + + __ bind(¬_zero_case); + __ cmp(r0, Operand(1)); + __ b(gt, ¬_one_case); + CreateArrayDispatchOneArgument(masm, mode); + + __ bind(¬_one_case); + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); + } else if (argument_count_ == NONE) { + CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode); + } else if (argument_count_ == ONE) { + CreateArrayDispatchOneArgument(masm, mode); + } else if (argument_count_ == MORE_THAN_ONE) { + CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode); + } else { + UNREACHABLE(); + } +} + + void ArrayConstructorStub::Generate(MacroAssembler* masm) { // ----------- S t a t e ------------- // -- r0 : argc (only if argument_count_ == ANY) @@ -7035,50 +7050,24 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) { __ bind(&okay_here); } - Label no_info, switch_ready; + Label no_info; // Get the elements kind and case on that. __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); __ b(eq, &no_info); __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); - // The type cell may have undefined in its value. - __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); - __ b(eq, &no_info); - - // The type cell has either an AllocationSite or a JSFunction + // If the type cell is undefined, or contains anything other than an + // AllocationSite, call an array constructor that doesn't use AllocationSites. __ ldr(r4, FieldMemOperand(r3, 0)); __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex); __ b(ne, &no_info); __ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset)); __ SmiUntag(r3); - __ jmp(&switch_ready); - __ bind(&no_info); - __ mov(r3, Operand(GetInitialFastElementsKind())); - __ bind(&switch_ready); + GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); - if (argument_count_ == ANY) { - Label not_zero_case, not_one_case; - __ tst(r0, r0); - __ b(ne, ¬_zero_case); - CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); - - __ bind(¬_zero_case); - __ cmp(r0, Operand(1)); - __ b(gt, ¬_one_case); - CreateArrayDispatchOneArgument(masm); - - __ bind(¬_one_case); - CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); - } else if (argument_count_ == NONE) { - CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm); - } else if (argument_count_ == ONE) { - CreateArrayDispatchOneArgument(masm); - } else if (argument_count_ == MORE_THAN_ONE) { - CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm); - } else { - UNREACHABLE(); - } + __ bind(&no_info); + GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); } diff --git a/deps/v8/src/arm/code-stubs-arm.h b/deps/v8/src/arm/code-stubs-arm.h index 6eab8d128e..d05e9a1d84 100644 --- a/deps/v8/src/arm/code-stubs-arm.h +++ b/deps/v8/src/arm/code-stubs-arm.h @@ -68,7 +68,7 @@ class StoreBufferOverflowStub: public PlatformCodeStub { void Generate(MacroAssembler* masm); - virtual bool IsPregenerated() { return true; } + virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE { return true; } static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); virtual bool SometimesSetsUpAFrame() { return false; } @@ -232,7 +232,7 @@ class WriteInt32ToHeapNumberStub : public PlatformCodeStub { the_heap_number_(the_heap_number), scratch_(scratch) { } - bool IsPregenerated(); + virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE; static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); private: @@ -305,7 +305,7 @@ class RecordWriteStub: public PlatformCodeStub { INCREMENTAL_COMPACTION }; - virtual bool IsPregenerated(); + virtual bool IsPregenerated(Isolate* isolate) V8_OVERRIDE; static void GenerateFixedRegStubsAheadOfTime(Isolate* isolate); virtual bool SometimesSetsUpAFrame() { return false; } @@ -376,7 +376,7 @@ class RecordWriteStub: public PlatformCodeStub { address_(address), scratch0_(scratch0) { ASSERT(!AreAliased(scratch0, object, address, no_reg)); - scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_); + scratch1_ = GetRegisterThatIsNotOneOf(object_, address_, scratch0_); } void Save(MacroAssembler* masm) { @@ -419,19 +419,6 @@ class RecordWriteStub: public PlatformCodeStub { Register scratch0_; Register scratch1_; - Register GetRegThatIsNotOneOf(Register r1, - Register r2, - Register r3) { - for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { - Register candidate = Register::FromAllocationIndex(i); - if (candidate.is(r1)) continue; - if (candidate.is(r2)) continue; - if (candidate.is(r3)) continue; - return candidate; - } - UNREACHABLE(); - return no_reg; - } friend class RecordWriteStub; }; @@ -478,23 +465,6 @@ class RecordWriteStub: public PlatformCodeStub { }; -// Enter C code from generated RegExp code in a way that allows -// the C code to fix the return address in case of a GC. -// Currently only needed on ARM. -class RegExpCEntryStub: public PlatformCodeStub { - public: - RegExpCEntryStub() {} - virtual ~RegExpCEntryStub() {} - void Generate(MacroAssembler* masm); - - private: - Major MajorKey() { return RegExpCEntry; } - int MinorKey() { return 0; } - - bool NeedsImmovableCode() { return true; } -}; - - // Trampoline stub to call into native code. To call safely into native code // in the presence of compacting GC (which can move code objects) we need to // keep the code which called into native pinned in the memory. Currently the diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h index c020ab601c..54530d8726 100644 --- a/deps/v8/src/arm/codegen-arm.h +++ b/deps/v8/src/arm/codegen-arm.h @@ -44,8 +44,8 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; class CodeGenerator: public AstVisitor { public: - CodeGenerator() { - InitializeAstVisitor(); + explicit CodeGenerator(Isolate* isolate) { + InitializeAstVisitor(isolate); } static bool MakeCode(CompilationInfo* info); @@ -61,7 +61,7 @@ class CodeGenerator: public AstVisitor { // Print the code after compiling it. static void PrintCode(Handle<Code> code, CompilationInfo* info); - static bool ShouldGenerateLog(Expression* type); + static bool ShouldGenerateLog(Isolate* isolate, Expression* type); static void SetFunctionInfo(Handle<JSFunction> fun, FunctionLiteral* lit, diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h index 9bfccf822b..703613932c 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -220,6 +220,8 @@ enum { kCoprocessorMask = 15 << 8, kOpCodeMask = 15 << 21, // In data-processing instructions. kImm24Mask = (1 << 24) - 1, + kImm16Mask = (1 << 16) - 1, + kImm8Mask = (1 << 8) - 1, kOff12Mask = (1 << 12) - 1, kOff8Mask = (1 << 8) - 1 }; diff --git a/deps/v8/src/arm/cpu-arm.cc b/deps/v8/src/arm/cpu-arm.cc index 8766a24bb2..cf531e1292 100644 --- a/deps/v8/src/arm/cpu-arm.cc +++ b/deps/v8/src/arm/cpu-arm.cc @@ -106,15 +106,6 @@ void CPU::FlushICache(void* start, size_t size) { #endif } - -void CPU::DebugBreak() { -#if !defined (__arm__) - UNIMPLEMENTED(); // when building ARM emulator target -#else - asm volatile("bkpt 0"); -#endif -} - } } // namespace v8::internal #endif // V8_TARGET_ARCH_ARM diff --git a/deps/v8/src/arm/debug-arm.cc b/deps/v8/src/arm/debug-arm.cc index 108435f0a9..efd11069b3 100644 --- a/deps/v8/src/arm/debug-arm.cc +++ b/deps/v8/src/arm/debug-arm.cc @@ -55,7 +55,8 @@ void BreakLocationIterator::SetDebugBreakAtReturn() { CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); patcher.masm()->blx(v8::internal::ip); - patcher.Emit(Isolate::Current()->debug()->debug_break_return()->entry()); + patcher.Emit( + debug_info_->GetIsolate()->debug()->debug_break_return()->entry()); patcher.masm()->bkpt(0); } @@ -95,7 +96,8 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); patcher.masm()->blx(v8::internal::ip); - patcher.Emit(Isolate::Current()->debug()->debug_break_slot()->entry()); + patcher.Emit( + debug_info_->GetIsolate()->debug()->debug_break_slot()->entry()); } diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 5b42116ad4..3c57b64395 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -101,12 +101,7 @@ static const int32_t kBranchBeforeInterrupt = 0x5a000004; void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code, Address pc_after, - Code* interrupt_code, Code* replacement_code) { - ASSERT(!InterruptCodeIsPatched(unoptimized_code, - pc_after, - interrupt_code, - replacement_code)); static const int kInstrSize = Assembler::kInstrSize; // Turn the jump into nops. CodePatcher patcher(pc_after - 3 * kInstrSize, 1); @@ -125,12 +120,7 @@ void Deoptimizer::PatchInterruptCodeAt(Code* unoptimized_code, void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code, Address pc_after, - Code* interrupt_code, - Code* replacement_code) { - ASSERT(InterruptCodeIsPatched(unoptimized_code, - pc_after, - interrupt_code, - replacement_code)); + Code* interrupt_code) { static const int kInstrSize = Assembler::kInstrSize; // Restore the original jump. CodePatcher patcher(pc_after - 3 * kInstrSize, 1); @@ -150,10 +140,10 @@ void Deoptimizer::RevertInterruptCodeAt(Code* unoptimized_code, #ifdef DEBUG -bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code, - Address pc_after, - Code* interrupt_code, - Code* replacement_code) { +Deoptimizer::InterruptPatchState Deoptimizer::GetInterruptPatchState( + Isolate* isolate, + Code* unoptimized_code, + Address pc_after) { static const int kInstrSize = Assembler::kInstrSize; ASSERT(Memory::int32_at(pc_after - kInstrSize) == kBlxIp); @@ -164,185 +154,27 @@ bool Deoptimizer::InterruptCodeIsPatched(Code* unoptimized_code, if (Assembler::IsNop(Assembler::instr_at(pc_after - 3 * kInstrSize))) { ASSERT(Assembler::IsLdrPcImmediateOffset( Assembler::instr_at(pc_after - 2 * kInstrSize))); - ASSERT(reinterpret_cast<uint32_t>(replacement_code->entry()) == + Code* osr_builtin = + isolate->builtins()->builtin(Builtins::kOnStackReplacement); + ASSERT(reinterpret_cast<uint32_t>(osr_builtin->entry()) == Memory::uint32_at(interrupt_address_pointer)); - return true; + return PATCHED_FOR_OSR; } else { + // Get the interrupt stub code object to match against from cache. + Code* interrupt_builtin = + isolate->builtins()->builtin(Builtins::kInterruptCheck); ASSERT(Assembler::IsLdrPcImmediateOffset( Assembler::instr_at(pc_after - 2 * kInstrSize))); ASSERT_EQ(kBranchBeforeInterrupt, Memory::int32_at(pc_after - 3 * kInstrSize)); - ASSERT(reinterpret_cast<uint32_t>(interrupt_code->entry()) == + ASSERT(reinterpret_cast<uint32_t>(interrupt_builtin->entry()) == Memory::uint32_at(interrupt_address_pointer)); - return false; + return NOT_PATCHED; } } #endif // DEBUG -static int LookupBailoutId(DeoptimizationInputData* data, BailoutId ast_id) { - ByteArray* translations = data->TranslationByteArray(); - int length = data->DeoptCount(); - for (int i = 0; i < length; i++) { - if (data->AstId(i) == ast_id) { - TranslationIterator it(translations, data->TranslationIndex(i)->value()); - int value = it.Next(); - ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value)); - // Read the number of frames. - value = it.Next(); - if (value == 1) return i; - } - } - UNREACHABLE(); - return -1; -} - - -void Deoptimizer::DoComputeOsrOutputFrame() { - DeoptimizationInputData* data = DeoptimizationInputData::cast( - compiled_code_->deoptimization_data()); - unsigned ast_id = data->OsrAstId()->value(); - - int bailout_id = LookupBailoutId(data, BailoutId(ast_id)); - unsigned translation_index = data->TranslationIndex(bailout_id)->value(); - ByteArray* translations = data->TranslationByteArray(); - - TranslationIterator iterator(translations, translation_index); - Translation::Opcode opcode = - static_cast<Translation::Opcode>(iterator.Next()); - ASSERT(Translation::BEGIN == opcode); - USE(opcode); - int count = iterator.Next(); - iterator.Skip(1); // Drop JS frame count. - ASSERT(count == 1); - USE(count); - - opcode = static_cast<Translation::Opcode>(iterator.Next()); - USE(opcode); - ASSERT(Translation::JS_FRAME == opcode); - unsigned node_id = iterator.Next(); - USE(node_id); - ASSERT(node_id == ast_id); - int closure_id = iterator.Next(); - USE(closure_id); - ASSERT_EQ(Translation::kSelfLiteralId, closure_id); - unsigned height = iterator.Next(); - unsigned height_in_bytes = height * kPointerSize; - USE(height_in_bytes); - - unsigned fixed_size = ComputeFixedSize(function_); - unsigned input_frame_size = input_->GetFrameSize(); - ASSERT(fixed_size + height_in_bytes == input_frame_size); - - unsigned stack_slot_size = compiled_code_->stack_slots() * kPointerSize; - unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); - unsigned outgoing_size = outgoing_height * kPointerSize; - unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; - ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. - - if (FLAG_trace_osr) { - PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ", - reinterpret_cast<intptr_t>(function_)); - PrintFunctionName(); - PrintF(" => node=%u, frame=%d->%d]\n", - ast_id, - input_frame_size, - output_frame_size); - } - - // There's only one output frame in the OSR case. - output_count_ = 1; - output_ = new FrameDescription*[1]; - output_[0] = new(output_frame_size) FrameDescription( - output_frame_size, function_); - output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT); - - // Clear the incoming parameters in the optimized frame to avoid - // confusing the garbage collector. - unsigned output_offset = output_frame_size - kPointerSize; - int parameter_count = function_->shared()->formal_parameter_count() + 1; - for (int i = 0; i < parameter_count; ++i) { - output_[0]->SetFrameSlot(output_offset, 0); - output_offset -= kPointerSize; - } - - // Translate the incoming parameters. This may overwrite some of the - // incoming argument slots we've just cleared. - int input_offset = input_frame_size - kPointerSize; - bool ok = true; - int limit = input_offset - (parameter_count * kPointerSize); - while (ok && input_offset > limit) { - ok = DoOsrTranslateCommand(&iterator, &input_offset); - } - - // There are no translation commands for the caller's pc and fp, the - // context, and the function. Set them up explicitly. - for (int i = StandardFrameConstants::kCallerPCOffset; - ok && i >= StandardFrameConstants::kMarkerOffset; - i -= kPointerSize) { - uint32_t input_value = input_->GetFrameSlot(input_offset); - if (FLAG_trace_osr) { - const char* name = "UNKNOWN"; - switch (i) { - case StandardFrameConstants::kCallerPCOffset: - name = "caller's pc"; - break; - case StandardFrameConstants::kCallerFPOffset: - name = "fp"; - break; - case StandardFrameConstants::kContextOffset: - name = "context"; - break; - case StandardFrameConstants::kMarkerOffset: - name = "function"; - break; - } - PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n", - output_offset, - input_value, - input_offset, - name); - } - - output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset)); - input_offset -= kPointerSize; - output_offset -= kPointerSize; - } - - // Translate the rest of the frame. - while (ok && input_offset >= 0) { - ok = DoOsrTranslateCommand(&iterator, &input_offset); - } - - // If translation of any command failed, continue using the input frame. - if (!ok) { - delete output_[0]; - output_[0] = input_; - output_[0]->SetPc(reinterpret_cast<uint32_t>(from_)); - } else { - // Set up the frame pointer and the context pointer. - output_[0]->SetRegister(fp.code(), input_->GetRegister(fp.code())); - output_[0]->SetRegister(cp.code(), input_->GetRegister(cp.code())); - - unsigned pc_offset = data->OsrPcOffset()->value(); - uint32_t pc = reinterpret_cast<uint32_t>( - compiled_code_->entry() + pc_offset); - output_[0]->SetPc(pc); - } - Code* continuation = isolate_->builtins()->builtin(Builtins::kNotifyOSR); - output_[0]->SetContinuation( - reinterpret_cast<uint32_t>(continuation->entry())); - - if (FLAG_trace_osr) { - PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", - ok ? "finished" : "aborted", - reinterpret_cast<intptr_t>(function_)); - PrintFunctionName(); - PrintF(" => pc=0x%0x]\n", output_[0]->GetPc()); - } -} - - void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { // Set the register values. The values are not important as there are no // callee saved registers in JavaScript frames, so all registers are @@ -555,11 +387,8 @@ void Deoptimizer::EntryGenerator::Generate() { } // Push state, pc, and continuation from the last output frame. - if (type() != OSR) { - __ ldr(r6, MemOperand(r2, FrameDescription::state_offset())); - __ push(r6); - } - + __ ldr(r6, MemOperand(r2, FrameDescription::state_offset())); + __ push(r6); __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset())); __ push(r6); __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset())); diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index ecdf638a1d..acffaa3f23 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -50,9 +50,6 @@ #include <stdio.h> #include <stdarg.h> #include <string.h> -#ifndef WIN32 -#include <stdint.h> -#endif #include "v8.h" diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index b73006a17d..b6fb70b5df 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -296,8 +296,7 @@ void FullCodeGenerator::Generate() { __ cmp(sp, Operand(ip)); __ b(hs, &ok); PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); - StackCheckStub stub; - __ CallStub(&stub); + __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); __ bind(&ok); } @@ -366,8 +365,7 @@ void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, } EmitProfilingCounterDecrement(weight); __ b(pl, &ok); - InterruptStub stub; - __ CallStub(&stub); + __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); // Record a mapping of this PC offset to the OSR id. This is used to find // the AST id from the unoptimized code in order to use it as a key into @@ -416,8 +414,8 @@ void FullCodeGenerator::EmitReturnSequence() { __ push(r2); __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); } else { - InterruptStub stub; - __ CallStub(&stub); + __ Call(isolate()->builtins()->InterruptCheck(), + RelocInfo::CODE_TARGET); } __ pop(r0); EmitProfilingCounterReset(); @@ -1330,8 +1328,7 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, scope()->is_function_scope() && info->num_literals() == 0) { FastNewClosureStub stub(info->language_mode(), info->is_generator()); - __ mov(r0, Operand(info)); - __ push(r0); + __ mov(r2, Operand(info)); __ CallStub(&stub); } else { __ mov(r0, Operand(info)); @@ -3010,7 +3007,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( VisitForAccumulatorValue(args->at(0)); - Label materialize_true, materialize_false; + Label materialize_true, materialize_false, skip_lookup; Label* if_true = NULL; Label* if_false = NULL; Label* fall_through = NULL; @@ -3022,7 +3019,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset)); __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ b(ne, if_true); + __ b(ne, &skip_lookup); // Check for fast case object. Generate false result for slow case object. __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset)); @@ -3068,6 +3065,14 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ b(ne, &loop); __ bind(&done); + + // Set the bit in the map to indicate that there is no local valueOf field. + __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); + __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); + __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); + + __ bind(&skip_lookup); + // If a valueOf property is not found on the object check that its // prototype is the un-modified String prototype. If not result is false. __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset)); @@ -3077,16 +3082,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset)); __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); __ cmp(r2, r3); - __ b(ne, if_false); - - // Set the bit in the map to indicate that it has been checked safe for - // default valueOf and set true result. - __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); - __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); - __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset)); - __ jmp(if_true); - PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); + Split(eq, if_true, if_false, fall_through); + context()->Plug(if_true, if_false); } @@ -3320,7 +3318,7 @@ void FullCodeGenerator::EmitLog(CallRuntime* expr) { // 2 (array): Arguments to the format string. ZoneList<Expression*>* args = expr->arguments(); ASSERT_EQ(args->length(), 3); - if (CodeGenerator::ShouldGenerateLog(args->at(0))) { + if (CodeGenerator::ShouldGenerateLog(isolate(), args->at(0))) { VisitForStackValue(args->at(1)); VisitForStackValue(args->at(2)); __ CallRuntime(Runtime::kLog, 2); diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index 511a3c74f2..f15d4b11f8 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -354,7 +354,7 @@ void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, extra_state, Code::NORMAL, argc); - Isolate::Current()->stub_cache()->GenerateProbe( + masm->isolate()->stub_cache()->GenerateProbe( masm, flags, r1, r2, r3, r4, r5, r6); // If the stub cache probing failed, the receiver might be a value. @@ -393,7 +393,7 @@ void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, // Probe the stub cache for the value object. __ bind(&probe); - Isolate::Current()->stub_cache()->GenerateProbe( + masm->isolate()->stub_cache()->GenerateProbe( masm, flags, r1, r2, r3, r4, r5, r6); __ bind(&miss); @@ -658,7 +658,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { Code::Flags flags = Code::ComputeFlags( Code::STUB, MONOMORPHIC, Code::kNoExtraICState, Code::NORMAL, Code::LOAD_IC); - Isolate::Current()->stub_cache()->GenerateProbe( + masm->isolate()->stub_cache()->GenerateProbe( masm, flags, r0, r2, r3, r4, r5, r6); // Cache miss: Jump to runtime. @@ -1490,7 +1490,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm, Code::STUB, MONOMORPHIC, strict_mode, Code::NORMAL, Code::STORE_IC); - Isolate::Current()->stub_cache()->GenerateProbe( + masm->isolate()->stub_cache()->GenerateProbe( masm, flags, r1, r2, r3, r4, r5, r6); // Cache miss: Jump to runtime. diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index fe299abfe8..59a8818ac6 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -30,6 +30,7 @@ #include "lithium-allocator-inl.h" #include "arm/lithium-arm.h" #include "arm/lithium-codegen-arm.h" +#include "hydrogen-osr.h" namespace v8 { namespace internal { @@ -260,6 +261,14 @@ void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { } +void LStoreCodeEntry::PrintDataTo(StringStream* stream) { + stream->Add(" = "); + function()->PrintTo(stream); + stream->Add(".code_entry = "); + code_object()->PrintTo(stream); +} + + void LInnerAllocatedObject::PrintDataTo(StringStream* stream) { stream->Add(" = "); base_object()->PrintTo(stream); @@ -425,6 +434,15 @@ LPlatformChunk* LChunkBuilder::Build() { chunk_ = new(zone()) LPlatformChunk(info(), graph()); LPhase phase("L_Building chunk", chunk_); status_ = BUILDING; + + // If compiling for OSR, reserve space for the unoptimized frame, + // which will be subsumed into this frame. + if (graph()->has_osr()) { + for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) { + chunk_->GetNextSpillIndex(false); + } + } + const ZoneList<HBasicBlock*>* blocks = graph()->blocks(); for (int i = 0; i < blocks->length(); i++) { HBasicBlock* next = NULL; @@ -718,12 +736,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, // Left shifts can deoptimize if we shift by > 0 and the result cannot be // truncated to smi. if (instr->representation().IsSmi() && constant_value > 0) { - for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { - if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) { - does_deopt = true; - break; - } - } + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi); } } else { right = UseRegisterAtStart(right_value); @@ -735,12 +748,7 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op, if (FLAG_opt_safe_uint32_operations) { does_deopt = !instr->CheckFlag(HInstruction::kUint32); } else { - for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { - if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) { - does_deopt = true; - break; - } - } + does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32); } } @@ -1089,6 +1097,14 @@ LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { } +LInstruction* LChunkBuilder::DoStoreCodeEntry( + HStoreCodeEntry* store_code_entry) { + LOperand* function = UseRegister(store_code_entry->function()); + LOperand* code_object = UseTempRegister(store_code_entry->code_object()); + return new(zone()) LStoreCodeEntry(function, code_object); +} + + LInstruction* LChunkBuilder::DoInnerAllocatedObject( HInnerAllocatedObject* inner_object) { LOperand* base_object = UseRegisterAtStart(inner_object->base_object()); @@ -1505,20 +1521,39 @@ LInstruction* LChunkBuilder::DoMul(HMul* instr) { if (instr->representation().IsSmiOrInteger32()) { ASSERT(instr->left()->representation().Equals(instr->representation())); ASSERT(instr->right()->representation().Equals(instr->representation())); - LOperand* left; - LOperand* right = UseOrConstant(instr->BetterRightOperand()); - LOperand* temp = NULL; - if (instr->CheckFlag(HValue::kBailoutOnMinusZero) && - (instr->CheckFlag(HValue::kCanOverflow) || - !right->IsConstantOperand())) { - left = UseRegister(instr->BetterLeftOperand()); - temp = TempRegister(); + HValue* left = instr->BetterLeftOperand(); + HValue* right = instr->BetterRightOperand(); + LOperand* left_op; + LOperand* right_op; + bool can_overflow = instr->CheckFlag(HValue::kCanOverflow); + bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero); + + if (right->IsConstant()) { + HConstant* constant = HConstant::cast(right); + int32_t constant_value = constant->Integer32Value(); + // Constants -1, 0 and 1 can be optimized if the result can overflow. + // For other constants, it can be optimized only without overflow. + if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) { + left_op = UseRegisterAtStart(left); + right_op = UseConstant(right); + } else { + if (bailout_on_minus_zero) { + left_op = UseRegister(left); + } else { + left_op = UseRegisterAtStart(left); + } + right_op = UseRegister(right); + } } else { - left = UseRegisterAtStart(instr->BetterLeftOperand()); + if (bailout_on_minus_zero) { + left_op = UseRegister(left); + } else { + left_op = UseRegisterAtStart(left); + } + right_op = UseRegister(right); } - LMulI* mul = new(zone()) LMulI(left, right, temp); - if (instr->CheckFlag(HValue::kCanOverflow) || - instr->CheckFlag(HValue::kBailoutOnMinusZero)) { + LMulI* mul = new(zone()) LMulI(left_op, right_op); + if (can_overflow || bailout_on_minus_zero) { AssignEnvironment(mul); } return DefineAsRegister(mul); @@ -1689,9 +1724,13 @@ LInstruction* LChunkBuilder::DoPower(HPower* instr) { LInstruction* LChunkBuilder::DoRandom(HRandom* instr) { ASSERT(instr->representation().IsDouble()); ASSERT(instr->global_object()->representation().IsTagged()); - LOperand* global_object = UseFixed(instr->global_object(), r0); - LRandom* result = new(zone()) LRandom(global_object); - return MarkAsCall(DefineFixedDouble(result, d7), instr); + LOperand* global_object = UseTempRegister(instr->global_object()); + LOperand* scratch = TempRegister(); + LOperand* scratch2 = TempRegister(); + LOperand* scratch3 = TempRegister(); + LRandom* result = new(zone()) LRandom( + global_object, scratch, scratch2, scratch3); + return DefineFixedDouble(result, d7); } @@ -1912,19 +1951,17 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { ASSERT(to.IsInteger32()); LOperand* value = NULL; LInstruction* res = NULL; - if (instr->value()->type().IsSmi()) { - value = UseRegisterAtStart(instr->value()); + HValue* val = instr->value(); + if (val->type().IsSmi() || val->representation().IsSmi()) { + value = UseRegisterAtStart(val); res = DefineAsRegister(new(zone()) LSmiUntag(value, false)); } else { - value = UseRegister(instr->value()); + value = UseRegister(val); LOperand* temp1 = TempRegister(); - LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() - : NULL; - LOperand* temp3 = FixedTemp(d11); + LOperand* temp2 = FixedTemp(d11); res = DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, - temp2, - temp3)); + temp2)); res = AssignEnvironment(res); } return res; @@ -1944,14 +1981,12 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { return AssignPointerMap(result); } else if (to.IsSmi()) { LOperand* value = UseRegister(instr->value()); - return AssignEnvironment(DefineAsRegister(new(zone()) LDoubleToSmi(value, - TempRegister(), TempRegister()))); + return AssignEnvironment( + DefineAsRegister(new(zone()) LDoubleToSmi(value))); } else { ASSERT(to.IsInteger32()); LOperand* value = UseRegister(instr->value()); - LOperand* temp1 = TempRegister(); - LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; - LDoubleToI* res = new(zone()) LDoubleToI(value, temp1, temp2); + LDoubleToI* res = new(zone()) LDoubleToI(value); return AssignEnvironment(DefineAsRegister(res)); } } else if (from.IsInteger32()) { @@ -2018,9 +2053,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { } -LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { +LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) { LOperand* value = UseRegisterAtStart(instr->value()); - return AssignEnvironment(new(zone()) LCheckFunction(value)); + return AssignEnvironment(new(zone()) LCheckValue(value)); } @@ -2418,10 +2453,18 @@ LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { - int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. - if (spill_index > LUnallocated::kMaxFixedSlotIndex) { - Abort(kTooManySpillSlotsNeededForOSR); - spill_index = 0; + // Use an index that corresponds to the location in the unoptimized frame, + // which the optimized frame will subsume. + int env_index = instr->index(); + int spill_index = 0; + if (instr->environment()->is_parameter_index(env_index)) { + spill_index = chunk()->GetParameterStackSlot(env_index); + } else { + spill_index = env_index - instr->environment()->first_local_index(); + if (spill_index > LUnallocated::kMaxFixedSlotIndex) { + Abort(kTooManySpillSlotsNeededForOSR); + spill_index = 0; + } } return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); } @@ -2443,6 +2486,8 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { + instr->ReplayEnvironment(current_block_->last_environment()); + // There are no real uses of a captured object. return NULL; } @@ -2489,20 +2534,7 @@ LInstruction* LChunkBuilder::DoIsConstructCallAndBranch( LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { - HEnvironment* env = current_block_->last_environment(); - ASSERT(env != NULL); - - env->set_ast_id(instr->ast_id()); - - env->Drop(instr->pop_count()); - for (int i = instr->values()->length() - 1; i >= 0; --i) { - HValue* value = instr->values()->at(i); - if (instr->HasAssignedIndexAt(i)) { - env->Bind(instr->GetAssignedIndexAt(i), value); - } else { - env->Push(value); - } - } + instr->ReplayEnvironment(current_block_->last_environment()); // If there is an instruction pending deoptimization environment create a // lazy bailout instruction to capture the environment. diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index d81dc0f57c..98cacacae1 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -62,12 +62,12 @@ class LCodeGen; V(CallNewArray) \ V(CallRuntime) \ V(CallStub) \ - V(CheckFunction) \ V(CheckInstanceType) \ V(CheckNonSmi) \ V(CheckMaps) \ V(CheckMapValue) \ V(CheckSmi) \ + V(CheckValue) \ V(ClampDToUint8) \ V(ClampIToUint8) \ V(ClampTToUint8) \ @@ -162,6 +162,7 @@ class LCodeGen; V(SmiTag) \ V(SmiUntag) \ V(StackCheck) \ + V(StoreCodeEntry) \ V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ @@ -189,13 +190,17 @@ class LCodeGen; V(WrapReceiver) -#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ - virtual Opcode opcode() const { return LInstruction::k##type; } \ - virtual void CompileToNative(LCodeGen* generator); \ - virtual const char* Mnemonic() const { return mnemonic; } \ - static L##type* cast(LInstruction* instr) { \ - ASSERT(instr->Is##type()); \ - return reinterpret_cast<L##type*>(instr); \ +#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \ + virtual Opcode opcode() const V8_FINAL V8_OVERRIDE { \ + return LInstruction::k##type; \ + } \ + virtual void CompileToNative(LCodeGen* generator) V8_FINAL V8_OVERRIDE; \ + virtual const char* Mnemonic() const V8_FINAL V8_OVERRIDE { \ + return mnemonic; \ + } \ + static L##type* cast(LInstruction* instr) { \ + ASSERT(instr->Is##type()); \ + return reinterpret_cast<L##type*>(instr); \ } @@ -205,7 +210,7 @@ class LCodeGen; } -class LInstruction: public ZoneObject { +class LInstruction : public ZoneObject { public: LInstruction() : environment_(NULL), @@ -214,7 +219,7 @@ class LInstruction: public ZoneObject { set_position(RelocInfo::kNoPosition); } - virtual ~LInstruction() { } + virtual ~LInstruction() {} virtual void CompileToNative(LCodeGen* generator) = 0; virtual const char* Mnemonic() const = 0; @@ -313,11 +318,13 @@ class LInstruction: public ZoneObject { // I = number of input operands. // T = number of temporary operands. template<int R, int I, int T> -class LTemplateInstruction: public LInstruction { +class LTemplateInstruction : public LInstruction { public: // Allow 0 or 1 output operands. STATIC_ASSERT(R == 0 || R == 1); - virtual bool HasResult() const { return R != 0 && result() != NULL; } + virtual bool HasResult() const V8_FINAL V8_OVERRIDE { + return R != 0 && result() != NULL; + } void set_result(LOperand* operand) { results_[0] = operand; } LOperand* result() const { return results_[0]; } @@ -327,15 +334,15 @@ class LTemplateInstruction: public LInstruction { EmbeddedContainer<LOperand*, T> temps_; private: - virtual int InputCount() { return I; } - virtual LOperand* InputAt(int i) { return inputs_[i]; } + virtual int InputCount() V8_FINAL V8_OVERRIDE { return I; } + virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return inputs_[i]; } - virtual int TempCount() { return T; } - virtual LOperand* TempAt(int i) { return temps_[i]; } + virtual int TempCount() V8_FINAL V8_OVERRIDE { return T; } + virtual LOperand* TempAt(int i) V8_FINAL V8_OVERRIDE { return temps_[i]; } }; -class LGap: public LTemplateInstruction<0, 0, 0> { +class LGap : public LTemplateInstruction<0, 0, 0> { public: explicit LGap(HBasicBlock* block) : block_(block) { @@ -346,8 +353,8 @@ class LGap: public LTemplateInstruction<0, 0, 0> { } // Can't use the DECLARE-macro here because of sub-classes. - virtual bool IsGap() const { return true; } - virtual void PrintDataTo(StringStream* stream); + virtual bool IsGap() const V8_OVERRIDE { return true; } + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; static LGap* cast(LInstruction* instr) { ASSERT(instr->IsGap()); return reinterpret_cast<LGap*>(instr); @@ -383,11 +390,11 @@ class LGap: public LTemplateInstruction<0, 0, 0> { }; -class LInstructionGap: public LGap { +class LInstructionGap V8_FINAL : public LGap { public: explicit LInstructionGap(HBasicBlock* block) : LGap(block) { } - virtual bool HasInterestingComment(LCodeGen* gen) const { + virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE { return !IsRedundant(); } @@ -395,14 +402,14 @@ class LInstructionGap: public LGap { }; -class LGoto: public LTemplateInstruction<0, 0, 0> { +class LGoto V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: explicit LGoto(int block_id) : block_id_(block_id) { } - virtual bool HasInterestingComment(LCodeGen* gen) const; + virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE; DECLARE_CONCRETE_INSTRUCTION(Goto, "goto") - virtual void PrintDataTo(StringStream* stream); - virtual bool IsControl() const { return true; } + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; + virtual bool IsControl() const V8_OVERRIDE { return true; } int block_id() const { return block_id_; } @@ -411,7 +418,7 @@ class LGoto: public LTemplateInstruction<0, 0, 0> { }; -class LLazyBailout: public LTemplateInstruction<0, 0, 0> { +class LLazyBailout V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: LLazyBailout() : gap_instructions_size_(0) { } @@ -427,7 +434,7 @@ class LLazyBailout: public LTemplateInstruction<0, 0, 0> { }; -class LDummyUse: public LTemplateInstruction<1, 1, 0> { +class LDummyUse V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LDummyUse(LOperand* value) { inputs_[0] = value; @@ -436,22 +443,24 @@ class LDummyUse: public LTemplateInstruction<1, 1, 0> { }; -class LDeoptimize: public LTemplateInstruction<0, 0, 0> { +class LDeoptimize V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize") DECLARE_HYDROGEN_ACCESSOR(Deoptimize) }; -class LLabel: public LGap { +class LLabel V8_FINAL : public LGap { public: explicit LLabel(HBasicBlock* block) : LGap(block), replacement_(NULL) { } - virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } + virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE { + return false; + } DECLARE_CONCRETE_INSTRUCTION(Label, "label") - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int block_id() const { return block()->block_id(); } bool is_loop_header() const { return block()->IsLoopHeader(); } @@ -467,14 +476,14 @@ class LLabel: public LGap { }; -class LParameter: public LTemplateInstruction<1, 0, 0> { +class LParameter V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter") }; -class LCallStub: public LTemplateInstruction<1, 0, 0> { +class LCallStub V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub") DECLARE_HYDROGEN_ACCESSOR(CallStub) @@ -485,19 +494,21 @@ class LCallStub: public LTemplateInstruction<1, 0, 0> { }; -class LUnknownOSRValue: public LTemplateInstruction<1, 0, 0> { +class LUnknownOSRValue V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: - virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } + virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE { + return false; + } DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value") }; template<int I, int T> -class LControlInstruction: public LTemplateInstruction<0, I, T> { +class LControlInstruction : public LTemplateInstruction<0, I, T> { public: LControlInstruction() : false_label_(NULL), true_label_(NULL) { } - virtual bool IsControl() const { return true; } + virtual bool IsControl() const V8_FINAL V8_OVERRIDE { return true; } int SuccessorCount() { return hydrogen()->SuccessorCount(); } HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); } @@ -536,7 +547,7 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> { }; -class LWrapReceiver: public LTemplateInstruction<1, 2, 0> { +class LWrapReceiver V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LWrapReceiver(LOperand* receiver, LOperand* function) { inputs_[0] = receiver; @@ -550,7 +561,7 @@ class LWrapReceiver: public LTemplateInstruction<1, 2, 0> { }; -class LApplyArguments: public LTemplateInstruction<1, 4, 0> { +class LApplyArguments V8_FINAL : public LTemplateInstruction<1, 4, 0> { public: LApplyArguments(LOperand* function, LOperand* receiver, @@ -571,7 +582,7 @@ class LApplyArguments: public LTemplateInstruction<1, 4, 0> { }; -class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { +class LAccessArgumentsAt V8_FINAL : public LTemplateInstruction<1, 3, 0> { public: LAccessArgumentsAt(LOperand* arguments, LOperand* length, LOperand* index) { inputs_[0] = arguments; @@ -585,11 +596,11 @@ class LAccessArgumentsAt: public LTemplateInstruction<1, 3, 0> { LOperand* length() { return inputs_[1]; } LOperand* index() { return inputs_[2]; } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { +class LArgumentsLength V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LArgumentsLength(LOperand* elements) { inputs_[0] = elements; @@ -601,14 +612,14 @@ class LArgumentsLength: public LTemplateInstruction<1, 1, 0> { }; -class LArgumentsElements: public LTemplateInstruction<1, 0, 0> { +class LArgumentsElements V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements") DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements) }; -class LModI: public LTemplateInstruction<1, 2, 2> { +class LModI V8_FINAL : public LTemplateInstruction<1, 2, 2> { public: LModI(LOperand* left, LOperand* right, @@ -630,7 +641,7 @@ class LModI: public LTemplateInstruction<1, 2, 2> { }; -class LDivI: public LTemplateInstruction<1, 2, 1> { +class LDivI V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: LDivI(LOperand* left, LOperand* right, LOperand* temp) { inputs_[0] = left; @@ -647,7 +658,7 @@ class LDivI: public LTemplateInstruction<1, 2, 1> { }; -class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { +class LMathFloorOfDiv V8_FINAL : public LTemplateInstruction<1, 2, 1> { public: LMathFloorOfDiv(LOperand* left, LOperand* right, @@ -666,17 +677,15 @@ class LMathFloorOfDiv: public LTemplateInstruction<1, 2, 1> { }; -class LMulI: public LTemplateInstruction<1, 2, 1> { +class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: - LMulI(LOperand* left, LOperand* right, LOperand* temp) { + LMulI(LOperand* left, LOperand* right) { inputs_[0] = left; inputs_[1] = right; - temps_[0] = temp; } LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } - LOperand* temp() { return temps_[0]; } DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i") DECLARE_HYDROGEN_ACCESSOR(Mul) @@ -684,7 +693,7 @@ class LMulI: public LTemplateInstruction<1, 2, 1> { // Instruction for computing multiplier * multiplicand + addend. -class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> { +class LMultiplyAddD V8_FINAL : public LTemplateInstruction<1, 3, 0> { public: LMultiplyAddD(LOperand* addend, LOperand* multiplier, LOperand* multiplicand) { @@ -702,7 +711,7 @@ class LMultiplyAddD: public LTemplateInstruction<1, 3, 0> { // Instruction for computing minuend - multiplier * multiplicand. -class LMultiplySubD: public LTemplateInstruction<1, 3, 0> { +class LMultiplySubD V8_FINAL : public LTemplateInstruction<1, 3, 0> { public: LMultiplySubD(LOperand* minuend, LOperand* multiplier, LOperand* multiplicand) { @@ -719,13 +728,13 @@ class LMultiplySubD: public LTemplateInstruction<1, 3, 0> { }; -class LDebugBreak: public LTemplateInstruction<0, 0, 0> { +class LDebugBreak V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break") }; -class LCompareNumericAndBranch: public LControlInstruction<2, 0> { +class LCompareNumericAndBranch V8_FINAL : public LControlInstruction<2, 0> { public: LCompareNumericAndBranch(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -744,11 +753,11 @@ class LCompareNumericAndBranch: public LControlInstruction<2, 0> { return hydrogen()->representation().IsDouble(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LMathFloor: public LTemplateInstruction<1, 1, 0> { +class LMathFloor V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathFloor(LOperand* value) { inputs_[0] = value; @@ -761,7 +770,7 @@ class LMathFloor: public LTemplateInstruction<1, 1, 0> { }; -class LMathRound: public LTemplateInstruction<1, 1, 1> { +class LMathRound V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LMathRound(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -776,7 +785,7 @@ class LMathRound: public LTemplateInstruction<1, 1, 1> { }; -class LMathAbs: public LTemplateInstruction<1, 1, 0> { +class LMathAbs V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathAbs(LOperand* value) { inputs_[0] = value; @@ -789,7 +798,7 @@ class LMathAbs: public LTemplateInstruction<1, 1, 0> { }; -class LMathLog: public LTemplateInstruction<1, 1, 0> { +class LMathLog V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathLog(LOperand* value) { inputs_[0] = value; @@ -801,7 +810,7 @@ class LMathLog: public LTemplateInstruction<1, 1, 0> { }; -class LMathSin: public LTemplateInstruction<1, 1, 0> { +class LMathSin V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathSin(LOperand* value) { inputs_[0] = value; @@ -813,7 +822,7 @@ class LMathSin: public LTemplateInstruction<1, 1, 0> { }; -class LMathCos: public LTemplateInstruction<1, 1, 0> { +class LMathCos V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathCos(LOperand* value) { inputs_[0] = value; @@ -825,7 +834,7 @@ class LMathCos: public LTemplateInstruction<1, 1, 0> { }; -class LMathTan: public LTemplateInstruction<1, 1, 0> { +class LMathTan V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathTan(LOperand* value) { inputs_[0] = value; @@ -837,7 +846,7 @@ class LMathTan: public LTemplateInstruction<1, 1, 0> { }; -class LMathExp: public LTemplateInstruction<1, 1, 3> { +class LMathExp V8_FINAL : public LTemplateInstruction<1, 1, 3> { public: LMathExp(LOperand* value, LOperand* double_temp, @@ -859,7 +868,7 @@ class LMathExp: public LTemplateInstruction<1, 1, 3> { }; -class LMathSqrt: public LTemplateInstruction<1, 1, 0> { +class LMathSqrt V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMathSqrt(LOperand* value) { inputs_[0] = value; @@ -871,7 +880,7 @@ class LMathSqrt: public LTemplateInstruction<1, 1, 0> { }; -class LMathPowHalf: public LTemplateInstruction<1, 1, 1> { +class LMathPowHalf V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LMathPowHalf(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -885,7 +894,7 @@ class LMathPowHalf: public LTemplateInstruction<1, 1, 1> { }; -class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { +class LCmpObjectEqAndBranch V8_FINAL : public LControlInstruction<2, 0> { public: LCmpObjectEqAndBranch(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -900,7 +909,7 @@ class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> { }; -class LCmpHoleAndBranch: public LControlInstruction<1, 0> { +class LCmpHoleAndBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LCmpHoleAndBranch(LOperand* object) { inputs_[0] = object; @@ -913,7 +922,7 @@ class LCmpHoleAndBranch: public LControlInstruction<1, 0> { }; -class LIsObjectAndBranch: public LControlInstruction<1, 1> { +class LIsObjectAndBranch V8_FINAL : public LControlInstruction<1, 1> { public: LIsObjectAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -926,11 +935,11 @@ class LIsObjectAndBranch: public LControlInstruction<1, 1> { DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LIsNumberAndBranch: public LControlInstruction<1, 0> { +class LIsNumberAndBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LIsNumberAndBranch(LOperand* value) { inputs_[0] = value; @@ -943,7 +952,7 @@ class LIsNumberAndBranch: public LControlInstruction<1, 0> { }; -class LIsStringAndBranch: public LControlInstruction<1, 1> { +class LIsStringAndBranch V8_FINAL : public LControlInstruction<1, 1> { public: LIsStringAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -956,11 +965,11 @@ class LIsStringAndBranch: public LControlInstruction<1, 1> { DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LIsSmiAndBranch: public LControlInstruction<1, 0> { +class LIsSmiAndBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LIsSmiAndBranch(LOperand* value) { inputs_[0] = value; @@ -971,11 +980,11 @@ class LIsSmiAndBranch: public LControlInstruction<1, 0> { DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { +class LIsUndetectableAndBranch V8_FINAL : public LControlInstruction<1, 1> { public: explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -989,11 +998,11 @@ class LIsUndetectableAndBranch: public LControlInstruction<1, 1> { "is-undetectable-and-branch") DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LStringCompareAndBranch: public LControlInstruction<2, 0> { +class LStringCompareAndBranch V8_FINAL : public LControlInstruction<2, 0> { public: LStringCompareAndBranch(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1009,11 +1018,11 @@ class LStringCompareAndBranch: public LControlInstruction<2, 0> { Token::Value op() const { return hydrogen()->token(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { +class LHasInstanceTypeAndBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LHasInstanceTypeAndBranch(LOperand* value) { inputs_[0] = value; @@ -1025,11 +1034,11 @@ class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> { "has-instance-type-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { +class LGetCachedArrayIndex V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LGetCachedArrayIndex(LOperand* value) { inputs_[0] = value; @@ -1042,7 +1051,8 @@ class LGetCachedArrayIndex: public LTemplateInstruction<1, 1, 0> { }; -class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { +class LHasCachedArrayIndexAndBranch V8_FINAL + : public LControlInstruction<1, 0> { public: explicit LHasCachedArrayIndexAndBranch(LOperand* value) { inputs_[0] = value; @@ -1054,11 +1064,11 @@ class LHasCachedArrayIndexAndBranch: public LControlInstruction<1, 0> { "has-cached-array-index-and-branch") DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LClassOfTestAndBranch: public LControlInstruction<1, 1> { +class LClassOfTestAndBranch V8_FINAL : public LControlInstruction<1, 1> { public: LClassOfTestAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -1072,11 +1082,11 @@ class LClassOfTestAndBranch: public LControlInstruction<1, 1> { "class-of-test-and-branch") DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LCmpT: public LTemplateInstruction<1, 2, 0> { +class LCmpT V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LCmpT(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1093,7 +1103,7 @@ class LCmpT: public LTemplateInstruction<1, 2, 0> { }; -class LInstanceOf: public LTemplateInstruction<1, 2, 0> { +class LInstanceOf V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LInstanceOf(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1107,7 +1117,7 @@ class LInstanceOf: public LTemplateInstruction<1, 2, 0> { }; -class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { +class LInstanceOfKnownGlobal V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LInstanceOfKnownGlobal(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -1125,7 +1135,8 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { LEnvironment* GetDeferredLazyDeoptimizationEnvironment() { return lazy_deopt_env_; } - virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { + virtual void SetDeferredLazyDeoptimizationEnvironment( + LEnvironment* env) V8_OVERRIDE { lazy_deopt_env_ = env; } @@ -1134,7 +1145,7 @@ class LInstanceOfKnownGlobal: public LTemplateInstruction<1, 1, 1> { }; -class LInstanceSize: public LTemplateInstruction<1, 1, 0> { +class LInstanceSize V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LInstanceSize(LOperand* object) { inputs_[0] = object; @@ -1147,7 +1158,7 @@ class LInstanceSize: public LTemplateInstruction<1, 1, 0> { }; -class LBoundsCheck: public LTemplateInstruction<0, 2, 0> { +class LBoundsCheck V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: LBoundsCheck(LOperand* index, LOperand* length) { inputs_[0] = index; @@ -1162,7 +1173,7 @@ class LBoundsCheck: public LTemplateInstruction<0, 2, 0> { }; -class LBitI: public LTemplateInstruction<1, 2, 0> { +class LBitI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LBitI(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1179,7 +1190,7 @@ class LBitI: public LTemplateInstruction<1, 2, 0> { }; -class LShiftI: public LTemplateInstruction<1, 2, 0> { +class LShiftI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt) : op_(op), can_deopt_(can_deopt) { @@ -1200,7 +1211,7 @@ class LShiftI: public LTemplateInstruction<1, 2, 0> { }; -class LSubI: public LTemplateInstruction<1, 2, 0> { +class LSubI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LSubI(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1215,7 +1226,7 @@ class LSubI: public LTemplateInstruction<1, 2, 0> { }; -class LRSubI: public LTemplateInstruction<1, 2, 0> { +class LRSubI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LRSubI(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1230,7 +1241,7 @@ class LRSubI: public LTemplateInstruction<1, 2, 0> { }; -class LConstantI: public LTemplateInstruction<1, 0, 0> { +class LConstantI V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -1239,7 +1250,7 @@ class LConstantI: public LTemplateInstruction<1, 0, 0> { }; -class LConstantS: public LTemplateInstruction<1, 0, 0> { +class LConstantS V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -1248,7 +1259,7 @@ class LConstantS: public LTemplateInstruction<1, 0, 0> { }; -class LConstantD: public LTemplateInstruction<1, 0, 0> { +class LConstantD V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -1257,7 +1268,7 @@ class LConstantD: public LTemplateInstruction<1, 0, 0> { }; -class LConstantE: public LTemplateInstruction<1, 0, 0> { +class LConstantE V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e") DECLARE_HYDROGEN_ACCESSOR(Constant) @@ -1268,16 +1279,18 @@ class LConstantE: public LTemplateInstruction<1, 0, 0> { }; -class LConstantT: public LTemplateInstruction<1, 0, 0> { +class LConstantT V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t") DECLARE_HYDROGEN_ACCESSOR(Constant) - Handle<Object> value() const { return hydrogen()->handle(); } + Handle<Object> value(Isolate* isolate) const { + return hydrogen()->handle(isolate); + } }; -class LBranch: public LControlInstruction<1, 0> { +class LBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LBranch(LOperand* value) { inputs_[0] = value; @@ -1288,11 +1301,11 @@ class LBranch: public LControlInstruction<1, 0> { DECLARE_CONCRETE_INSTRUCTION(Branch, "branch") DECLARE_HYDROGEN_ACCESSOR(Branch) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LCmpMapAndBranch: public LControlInstruction<1, 1> { +class LCmpMapAndBranch V8_FINAL : public LControlInstruction<1, 1> { public: LCmpMapAndBranch(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -1309,7 +1322,7 @@ class LCmpMapAndBranch: public LControlInstruction<1, 1> { }; -class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { +class LMapEnumLength V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LMapEnumLength(LOperand* value) { inputs_[0] = value; @@ -1321,7 +1334,7 @@ class LMapEnumLength: public LTemplateInstruction<1, 1, 0> { }; -class LElementsKind: public LTemplateInstruction<1, 1, 0> { +class LElementsKind V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LElementsKind(LOperand* value) { inputs_[0] = value; @@ -1334,7 +1347,7 @@ class LElementsKind: public LTemplateInstruction<1, 1, 0> { }; -class LValueOf: public LTemplateInstruction<1, 1, 1> { +class LValueOf V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LValueOf(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -1349,7 +1362,7 @@ class LValueOf: public LTemplateInstruction<1, 1, 1> { }; -class LDateField: public LTemplateInstruction<1, 1, 1> { +class LDateField V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LDateField(LOperand* date, LOperand* temp, Smi* index) : index_(index) { inputs_[0] = date; @@ -1368,7 +1381,7 @@ class LDateField: public LTemplateInstruction<1, 1, 1> { }; -class LSeqStringSetChar: public LTemplateInstruction<1, 3, 0> { +class LSeqStringSetChar V8_FINAL : public LTemplateInstruction<1, 3, 0> { public: LSeqStringSetChar(String::Encoding encoding, LOperand* string, @@ -1392,7 +1405,7 @@ class LSeqStringSetChar: public LTemplateInstruction<1, 3, 0> { }; -class LThrow: public LTemplateInstruction<0, 1, 0> { +class LThrow V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: explicit LThrow(LOperand* value) { inputs_[0] = value; @@ -1404,7 +1417,7 @@ class LThrow: public LTemplateInstruction<0, 1, 0> { }; -class LAddI: public LTemplateInstruction<1, 2, 0> { +class LAddI V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LAddI(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1419,7 +1432,7 @@ class LAddI: public LTemplateInstruction<1, 2, 0> { }; -class LMathMinMax: public LTemplateInstruction<1, 2, 0> { +class LMathMinMax V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LMathMinMax(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1434,7 +1447,7 @@ class LMathMinMax: public LTemplateInstruction<1, 2, 0> { }; -class LPower: public LTemplateInstruction<1, 2, 0> { +class LPower V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LPower(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -1449,20 +1462,29 @@ class LPower: public LTemplateInstruction<1, 2, 0> { }; -class LRandom: public LTemplateInstruction<1, 1, 0> { +class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> { public: - explicit LRandom(LOperand* global_object) { + LRandom(LOperand* global_object, + LOperand* scratch, + LOperand* scratch2, + LOperand* scratch3) { inputs_[0] = global_object; + temps_[0] = scratch; + temps_[1] = scratch2; + temps_[2] = scratch3; } - LOperand* global_object() { return inputs_[0]; } + LOperand* global_object() const { return inputs_[0]; } + LOperand* scratch() const { return temps_[0]; } + LOperand* scratch2() const { return temps_[1]; } + LOperand* scratch3() const { return temps_[2]; } DECLARE_CONCRETE_INSTRUCTION(Random, "random") DECLARE_HYDROGEN_ACCESSOR(Random) }; -class LArithmeticD: public LTemplateInstruction<1, 2, 0> { +class LArithmeticD V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LArithmeticD(Token::Value op, LOperand* left, LOperand* right) : op_(op) { @@ -1474,16 +1496,18 @@ class LArithmeticD: public LTemplateInstruction<1, 2, 0> { LOperand* left() { return inputs_[0]; } LOperand* right() { return inputs_[1]; } - virtual Opcode opcode() const { return LInstruction::kArithmeticD; } - virtual void CompileToNative(LCodeGen* generator); - virtual const char* Mnemonic() const; + virtual Opcode opcode() const V8_OVERRIDE { + return LInstruction::kArithmeticD; + } + virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE; + virtual const char* Mnemonic() const V8_OVERRIDE; private: Token::Value op_; }; -class LArithmeticT: public LTemplateInstruction<1, 2, 0> { +class LArithmeticT V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LArithmeticT(Token::Value op, LOperand* left, LOperand* right) : op_(op) { @@ -1495,16 +1519,18 @@ class LArithmeticT: public LTemplateInstruction<1, 2, 0> { LOperand* right() { return inputs_[1]; } Token::Value op() const { return op_; } - virtual Opcode opcode() const { return LInstruction::kArithmeticT; } - virtual void CompileToNative(LCodeGen* generator); - virtual const char* Mnemonic() const; + virtual Opcode opcode() const V8_OVERRIDE { + return LInstruction::kArithmeticT; + } + virtual void CompileToNative(LCodeGen* generator) V8_OVERRIDE; + virtual const char* Mnemonic() const V8_OVERRIDE; private: Token::Value op_; }; -class LReturn: public LTemplateInstruction<0, 2, 0> { +class LReturn V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: explicit LReturn(LOperand* value, LOperand* parameter_count) { inputs_[0] = value; @@ -1526,7 +1552,7 @@ class LReturn: public LTemplateInstruction<0, 2, 0> { }; -class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { +class LLoadNamedField V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadNamedField(LOperand* object) { inputs_[0] = object; @@ -1539,7 +1565,7 @@ class LLoadNamedField: public LTemplateInstruction<1, 1, 0> { }; -class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { +class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadNamedGeneric(LOperand* object) { inputs_[0] = object; @@ -1554,7 +1580,7 @@ class LLoadNamedGeneric: public LTemplateInstruction<1, 1, 0> { }; -class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 0> { +class LLoadFunctionPrototype V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadFunctionPrototype(LOperand* function) { inputs_[0] = function; @@ -1567,7 +1593,8 @@ class LLoadFunctionPrototype: public LTemplateInstruction<1, 1, 0> { }; -class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { +class LLoadExternalArrayPointer V8_FINAL + : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadExternalArrayPointer(LOperand* object) { inputs_[0] = object; @@ -1580,7 +1607,7 @@ class LLoadExternalArrayPointer: public LTemplateInstruction<1, 1, 0> { }; -class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LLoadKeyed(LOperand* elements, LOperand* key) { inputs_[0] = elements; @@ -1599,12 +1626,12 @@ class LLoadKeyed: public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; uint32_t additional_index() const { return hydrogen()->index_offset(); } }; -class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { +class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LLoadKeyedGeneric(LOperand* object, LOperand* key) { inputs_[0] = object; @@ -1618,14 +1645,14 @@ class LLoadKeyedGeneric: public LTemplateInstruction<1, 2, 0> { }; -class LLoadGlobalCell: public LTemplateInstruction<1, 0, 0> { +class LLoadGlobalCell V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell") DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell) }; -class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> { +class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadGlobalGeneric(LOperand* global_object) { inputs_[0] = global_object; @@ -1641,7 +1668,7 @@ class LLoadGlobalGeneric: public LTemplateInstruction<1, 1, 0> { }; -class LStoreGlobalCell: public LTemplateInstruction<0, 1, 1> { +class LStoreGlobalCell V8_FINAL : public LTemplateInstruction<0, 1, 1> { public: LStoreGlobalCell(LOperand* value, LOperand* temp) { inputs_[0] = value; @@ -1656,7 +1683,7 @@ class LStoreGlobalCell: public LTemplateInstruction<0, 1, 1> { }; -class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> { +class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: explicit LStoreGlobalGeneric(LOperand* global_object, LOperand* value) { @@ -1675,7 +1702,7 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> { }; -class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { +class LLoadContextSlot V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LLoadContextSlot(LOperand* context) { inputs_[0] = context; @@ -1688,11 +1715,11 @@ class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> { int slot_index() { return hydrogen()->slot_index(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> { +class LStoreContextSlot V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: LStoreContextSlot(LOperand* context, LOperand* value) { inputs_[0] = context; @@ -1707,11 +1734,11 @@ class LStoreContextSlot: public LTemplateInstruction<0, 2, 0> { int slot_index() { return hydrogen()->slot_index(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LPushArgument: public LTemplateInstruction<0, 1, 0> { +class LPushArgument V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: explicit LPushArgument(LOperand* value) { inputs_[0] = value; @@ -1723,7 +1750,7 @@ class LPushArgument: public LTemplateInstruction<0, 1, 0> { }; -class LDrop: public LTemplateInstruction<0, 0, 0> { +class LDrop V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: explicit LDrop(int count) : count_(count) { } @@ -1736,7 +1763,24 @@ class LDrop: public LTemplateInstruction<0, 0, 0> { }; -class LInnerAllocatedObject: public LTemplateInstruction<1, 1, 0> { +class LStoreCodeEntry V8_FINAL: public LTemplateInstruction<0, 1, 1> { + public: + LStoreCodeEntry(LOperand* function, LOperand* code_object) { + inputs_[0] = function; + temps_[0] = code_object; + } + + LOperand* function() { return inputs_[0]; } + LOperand* code_object() { return temps_[0]; } + + virtual void PrintDataTo(StringStream* stream); + + DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry") + DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry) +}; + + +class LInnerAllocatedObject V8_FINAL: public LTemplateInstruction<1, 1, 0> { public: explicit LInnerAllocatedObject(LOperand* base_object) { inputs_[0] = base_object; @@ -1745,28 +1789,28 @@ class LInnerAllocatedObject: public LTemplateInstruction<1, 1, 0> { LOperand* base_object() { return inputs_[0]; } int offset() { return hydrogen()->offset(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "sub-allocated-object") DECLARE_HYDROGEN_ACCESSOR(InnerAllocatedObject) }; -class LThisFunction: public LTemplateInstruction<1, 0, 0> { +class LThisFunction V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function") DECLARE_HYDROGEN_ACCESSOR(ThisFunction) }; -class LContext: public LTemplateInstruction<1, 0, 0> { +class LContext V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(Context, "context") DECLARE_HYDROGEN_ACCESSOR(Context) }; -class LOuterContext: public LTemplateInstruction<1, 1, 0> { +class LOuterContext V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LOuterContext(LOperand* context) { inputs_[0] = context; @@ -1778,14 +1822,14 @@ class LOuterContext: public LTemplateInstruction<1, 1, 0> { }; -class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> { +class LDeclareGlobals V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals") DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals) }; -class LGlobalObject: public LTemplateInstruction<1, 1, 0> { +class LGlobalObject V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LGlobalObject(LOperand* context) { inputs_[0] = context; @@ -1797,7 +1841,7 @@ class LGlobalObject: public LTemplateInstruction<1, 1, 0> { }; -class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { +class LGlobalReceiver V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LGlobalReceiver(LOperand* global_object) { inputs_[0] = global_object; @@ -1809,19 +1853,19 @@ class LGlobalReceiver: public LTemplateInstruction<1, 1, 0> { }; -class LCallConstantFunction: public LTemplateInstruction<1, 0, 0> { +class LCallConstantFunction V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction, "call-constant-function") DECLARE_HYDROGEN_ACCESSOR(CallConstantFunction) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<JSFunction> function() { return hydrogen()->function(); } int arity() const { return hydrogen()->argument_count() - 1; } }; -class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { +class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LInvokeFunction(LOperand* function) { inputs_[0] = function; @@ -1832,13 +1876,13 @@ class LInvokeFunction: public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function") DECLARE_HYDROGEN_ACCESSOR(InvokeFunction) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallKeyed: public LTemplateInstruction<1, 1, 0> { +class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LCallKeyed(LOperand* key) { inputs_[0] = key; @@ -1849,26 +1893,26 @@ class LCallKeyed: public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed") DECLARE_HYDROGEN_ACCESSOR(CallKeyed) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallNamed: public LTemplateInstruction<1, 0, 0> { +class LCallNamed V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named") DECLARE_HYDROGEN_ACCESSOR(CallNamed) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<String> name() const { return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallFunction: public LTemplateInstruction<1, 1, 0> { +class LCallFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LCallFunction(LOperand* function) { inputs_[0] = function; @@ -1883,30 +1927,30 @@ class LCallFunction: public LTemplateInstruction<1, 1, 0> { }; -class LCallGlobal: public LTemplateInstruction<1, 0, 0> { +class LCallGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global") DECLARE_HYDROGEN_ACCESSOR(CallGlobal) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallKnownGlobal: public LTemplateInstruction<1, 0, 0> { +class LCallKnownGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal, "call-known-global") DECLARE_HYDROGEN_ACCESSOR(CallKnownGlobal) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallNew: public LTemplateInstruction<1, 1, 0> { +class LCallNew V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LCallNew(LOperand* constructor) { inputs_[0] = constructor; @@ -1917,13 +1961,13 @@ class LCallNew: public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new") DECLARE_HYDROGEN_ACCESSOR(CallNew) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallNewArray: public LTemplateInstruction<1, 1, 0> { +class LCallNewArray V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LCallNewArray(LOperand* constructor) { inputs_[0] = constructor; @@ -1934,13 +1978,13 @@ class LCallNewArray: public LTemplateInstruction<1, 1, 0> { DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array") DECLARE_HYDROGEN_ACCESSOR(CallNewArray) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; int arity() const { return hydrogen()->argument_count() - 1; } }; -class LCallRuntime: public LTemplateInstruction<1, 0, 0> { +class LCallRuntime V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime") DECLARE_HYDROGEN_ACCESSOR(CallRuntime) @@ -1950,7 +1994,7 @@ class LCallRuntime: public LTemplateInstruction<1, 0, 0> { }; -class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { +class LInteger32ToDouble V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LInteger32ToDouble(LOperand* value) { inputs_[0] = value; @@ -1962,7 +2006,7 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> { }; -class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> { +class LInteger32ToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LInteger32ToSmi(LOperand* value) { inputs_[0] = value; @@ -1975,7 +2019,7 @@ class LInteger32ToSmi: public LTemplateInstruction<1, 1, 0> { }; -class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> { +class LUint32ToDouble V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LUint32ToDouble(LOperand* value) { inputs_[0] = value; @@ -1987,7 +2031,7 @@ class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> { }; -class LNumberTagI: public LTemplateInstruction<1, 1, 0> { +class LNumberTagI V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LNumberTagI(LOperand* value) { inputs_[0] = value; @@ -1999,7 +2043,7 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> { }; -class LNumberTagU: public LTemplateInstruction<1, 1, 0> { +class LNumberTagU V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LNumberTagU(LOperand* value) { inputs_[0] = value; @@ -2011,7 +2055,7 @@ class LNumberTagU: public LTemplateInstruction<1, 1, 0> { }; -class LNumberTagD: public LTemplateInstruction<1, 1, 2> { +class LNumberTagD V8_FINAL : public LTemplateInstruction<1, 1, 2> { public: LNumberTagD(LOperand* value, LOperand* temp, LOperand* temp2) { inputs_[0] = value; @@ -2028,17 +2072,13 @@ class LNumberTagD: public LTemplateInstruction<1, 1, 2> { }; -class LDoubleToSmi: public LTemplateInstruction<1, 1, 2> { +class LDoubleToSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: - LDoubleToSmi(LOperand* value, LOperand* temp, LOperand* temp2) { + explicit LDoubleToSmi(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; } LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } DECLARE_CONCRETE_INSTRUCTION(DoubleToSmi, "double-to-smi") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -2048,17 +2088,13 @@ class LDoubleToSmi: public LTemplateInstruction<1, 1, 2> { // Sometimes truncating conversion from a tagged value to an int32. -class LDoubleToI: public LTemplateInstruction<1, 1, 2> { +class LDoubleToI V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: - LDoubleToI(LOperand* value, LOperand* temp, LOperand* temp2) { + explicit LDoubleToI(LOperand* value) { inputs_[0] = value; - temps_[0] = temp; - temps_[1] = temp2; } LOperand* value() { return inputs_[0]; } - LOperand* temp() { return temps_[0]; } - LOperand* temp2() { return temps_[1]; } DECLARE_CONCRETE_INSTRUCTION(DoubleToI, "double-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -2068,22 +2104,19 @@ class LDoubleToI: public LTemplateInstruction<1, 1, 2> { // Truncating conversion from a tagged value to an int32. -class LTaggedToI: public LTemplateInstruction<1, 1, 3> { +class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 2> { public: LTaggedToI(LOperand* value, LOperand* temp, - LOperand* temp2, - LOperand* temp3) { + LOperand* temp2) { inputs_[0] = value; temps_[0] = temp; temps_[1] = temp2; - temps_[2] = temp3; } LOperand* value() { return inputs_[0]; } LOperand* temp() { return temps_[0]; } LOperand* temp2() { return temps_[1]; } - LOperand* temp3() { return temps_[2]; } DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i") DECLARE_HYDROGEN_ACCESSOR(UnaryOperation) @@ -2092,7 +2125,7 @@ class LTaggedToI: public LTemplateInstruction<1, 1, 3> { }; -class LSmiTag: public LTemplateInstruction<1, 1, 0> { +class LSmiTag V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LSmiTag(LOperand* value) { inputs_[0] = value; @@ -2104,7 +2137,7 @@ class LSmiTag: public LTemplateInstruction<1, 1, 0> { }; -class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { +class LNumberUntagD V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LNumberUntagD(LOperand* value) { inputs_[0] = value; @@ -2117,7 +2150,7 @@ class LNumberUntagD: public LTemplateInstruction<1, 1, 0> { }; -class LSmiUntag: public LTemplateInstruction<1, 1, 0> { +class LSmiUntag V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: LSmiUntag(LOperand* value, bool needs_check) : needs_check_(needs_check) { @@ -2134,7 +2167,7 @@ class LSmiUntag: public LTemplateInstruction<1, 1, 0> { }; -class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { +class LStoreNamedField V8_FINAL : public LTemplateInstruction<0, 2, 1> { public: LStoreNamedField(LOperand* object, LOperand* value, LOperand* temp) { inputs_[0] = object; @@ -2149,7 +2182,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field") DECLARE_HYDROGEN_ACCESSOR(StoreNamedField) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<Map> transition() const { return hydrogen()->transition_map(); } Representation representation() const { @@ -2158,7 +2191,7 @@ class LStoreNamedField: public LTemplateInstruction<0, 2, 1> { }; -class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { +class LStoreNamedGeneric V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: LStoreNamedGeneric(LOperand* object, LOperand* value) { inputs_[0] = object; @@ -2171,14 +2204,14 @@ class LStoreNamedGeneric: public LTemplateInstruction<0, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic") DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<Object> name() const { return hydrogen()->name(); } StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyed V8_FINAL : public LTemplateInstruction<0, 3, 0> { public: LStoreKeyed(LOperand* object, LOperand* key, LOperand* value) { inputs_[0] = object; @@ -2197,7 +2230,7 @@ class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreKeyed, "store-keyed") DECLARE_HYDROGEN_ACCESSOR(StoreKeyed) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; bool NeedsCanonicalization() { if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() || hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) { @@ -2209,7 +2242,7 @@ class LStoreKeyed: public LTemplateInstruction<0, 3, 0> { }; -class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { +class LStoreKeyedGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> { public: LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* value) { inputs_[0] = obj; @@ -2224,13 +2257,13 @@ class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> { DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic") DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); } }; -class LTransitionElementsKind: public LTemplateInstruction<0, 1, 1> { +class LTransitionElementsKind V8_FINAL : public LTemplateInstruction<0, 1, 1> { public: LTransitionElementsKind(LOperand* object, LOperand* new_map_temp) { @@ -2245,7 +2278,7 @@ class LTransitionElementsKind: public LTemplateInstruction<0, 1, 1> { "transition-elements-kind") DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind) - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; Handle<Map> original_map() { return hydrogen()->original_map(); } Handle<Map> transitioned_map() { return hydrogen()->transitioned_map(); } @@ -2254,7 +2287,7 @@ class LTransitionElementsKind: public LTemplateInstruction<0, 1, 1> { }; -class LTrapAllocationMemento : public LTemplateInstruction<0, 1, 1> { +class LTrapAllocationMemento V8_FINAL : public LTemplateInstruction<0, 1, 1> { public: LTrapAllocationMemento(LOperand* object, LOperand* temp) { @@ -2270,7 +2303,7 @@ class LTrapAllocationMemento : public LTemplateInstruction<0, 1, 1> { }; -class LStringAdd: public LTemplateInstruction<1, 2, 0> { +class LStringAdd V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LStringAdd(LOperand* left, LOperand* right) { inputs_[0] = left; @@ -2286,7 +2319,7 @@ class LStringAdd: public LTemplateInstruction<1, 2, 0> { -class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> { +class LStringCharCodeAt V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LStringCharCodeAt(LOperand* string, LOperand* index) { inputs_[0] = string; @@ -2301,7 +2334,7 @@ class LStringCharCodeAt: public LTemplateInstruction<1, 2, 0> { }; -class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> { +class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LStringCharFromCode(LOperand* char_code) { inputs_[0] = char_code; @@ -2314,20 +2347,20 @@ class LStringCharFromCode: public LTemplateInstruction<1, 1, 0> { }; -class LCheckFunction: public LTemplateInstruction<0, 1, 0> { +class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: - explicit LCheckFunction(LOperand* value) { + explicit LCheckValue(LOperand* value) { inputs_[0] = value; } LOperand* value() { return inputs_[0]; } - DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function") - DECLARE_HYDROGEN_ACCESSOR(CheckFunction) + DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value") + DECLARE_HYDROGEN_ACCESSOR(CheckValue) }; -class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { +class LCheckInstanceType V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: explicit LCheckInstanceType(LOperand* value) { inputs_[0] = value; @@ -2340,7 +2373,7 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> { }; -class LCheckMaps: public LTemplateInstruction<0, 1, 0> { +class LCheckMaps V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: explicit LCheckMaps(LOperand* value) { inputs_[0] = value; @@ -2353,7 +2386,7 @@ class LCheckMaps: public LTemplateInstruction<0, 1, 0> { }; -class LCheckSmi: public LTemplateInstruction<1, 1, 0> { +class LCheckSmi V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LCheckSmi(LOperand* value) { inputs_[0] = value; @@ -2365,7 +2398,7 @@ class LCheckSmi: public LTemplateInstruction<1, 1, 0> { }; -class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { +class LCheckNonSmi V8_FINAL : public LTemplateInstruction<0, 1, 0> { public: explicit LCheckNonSmi(LOperand* value) { inputs_[0] = value; @@ -2378,7 +2411,7 @@ class LCheckNonSmi: public LTemplateInstruction<0, 1, 0> { }; -class LClampDToUint8: public LTemplateInstruction<1, 1, 0> { +class LClampDToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LClampDToUint8(LOperand* unclamped) { inputs_[0] = unclamped; @@ -2390,7 +2423,7 @@ class LClampDToUint8: public LTemplateInstruction<1, 1, 0> { }; -class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { +class LClampIToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LClampIToUint8(LOperand* unclamped) { inputs_[0] = unclamped; @@ -2402,7 +2435,7 @@ class LClampIToUint8: public LTemplateInstruction<1, 1, 0> { }; -class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { +class LClampTToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 1> { public: LClampTToUint8(LOperand* unclamped, LOperand* temp) { inputs_[0] = unclamped; @@ -2416,7 +2449,7 @@ class LClampTToUint8: public LTemplateInstruction<1, 1, 1> { }; -class LAllocate: public LTemplateInstruction<1, 2, 2> { +class LAllocate V8_FINAL : public LTemplateInstruction<1, 2, 2> { public: LAllocate(LOperand* size, LOperand* temp1, LOperand* temp2) { inputs_[1] = size; @@ -2433,21 +2466,21 @@ class LAllocate: public LTemplateInstruction<1, 2, 2> { }; -class LRegExpLiteral: public LTemplateInstruction<1, 0, 0> { +class LRegExpLiteral V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal") DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral) }; -class LFunctionLiteral: public LTemplateInstruction<1, 0, 0> { +class LFunctionLiteral V8_FINAL : public LTemplateInstruction<1, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal") DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral) }; -class LToFastProperties: public LTemplateInstruction<1, 1, 0> { +class LToFastProperties V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LToFastProperties(LOperand* value) { inputs_[0] = value; @@ -2460,7 +2493,7 @@ class LToFastProperties: public LTemplateInstruction<1, 1, 0> { }; -class LTypeof: public LTemplateInstruction<1, 1, 0> { +class LTypeof V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LTypeof(LOperand* value) { inputs_[0] = value; @@ -2472,7 +2505,7 @@ class LTypeof: public LTemplateInstruction<1, 1, 0> { }; -class LTypeofIsAndBranch: public LControlInstruction<1, 0> { +class LTypeofIsAndBranch V8_FINAL : public LControlInstruction<1, 0> { public: explicit LTypeofIsAndBranch(LOperand* value) { inputs_[0] = value; @@ -2485,11 +2518,11 @@ class LTypeofIsAndBranch: public LControlInstruction<1, 0> { Handle<String> type_literal() { return hydrogen()->type_literal(); } - virtual void PrintDataTo(StringStream* stream); + virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE; }; -class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { +class LIsConstructCallAndBranch V8_FINAL : public LControlInstruction<0, 1> { public: explicit LIsConstructCallAndBranch(LOperand* temp) { temps_[0] = temp; @@ -2502,16 +2535,18 @@ class LIsConstructCallAndBranch: public LControlInstruction<0, 1> { }; -class LOsrEntry: public LTemplateInstruction<0, 0, 0> { +class LOsrEntry V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: LOsrEntry() {} - virtual bool HasInterestingComment(LCodeGen* gen) const { return false; } + virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE { + return false; + } DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry") }; -class LStackCheck: public LTemplateInstruction<0, 0, 0> { +class LStackCheck V8_FINAL : public LTemplateInstruction<0, 0, 0> { public: DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check") DECLARE_HYDROGEN_ACCESSOR(StackCheck) @@ -2523,7 +2558,7 @@ class LStackCheck: public LTemplateInstruction<0, 0, 0> { }; -class LForInPrepareMap: public LTemplateInstruction<1, 1, 0> { +class LForInPrepareMap V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LForInPrepareMap(LOperand* object) { inputs_[0] = object; @@ -2535,7 +2570,7 @@ class LForInPrepareMap: public LTemplateInstruction<1, 1, 0> { }; -class LForInCacheArray: public LTemplateInstruction<1, 1, 0> { +class LForInCacheArray V8_FINAL : public LTemplateInstruction<1, 1, 0> { public: explicit LForInCacheArray(LOperand* map) { inputs_[0] = map; @@ -2551,7 +2586,7 @@ class LForInCacheArray: public LTemplateInstruction<1, 1, 0> { }; -class LCheckMapValue: public LTemplateInstruction<0, 2, 0> { +class LCheckMapValue V8_FINAL : public LTemplateInstruction<0, 2, 0> { public: LCheckMapValue(LOperand* value, LOperand* map) { inputs_[0] = value; @@ -2565,7 +2600,7 @@ class LCheckMapValue: public LTemplateInstruction<0, 2, 0> { }; -class LLoadFieldByIndex: public LTemplateInstruction<1, 2, 0> { +class LLoadFieldByIndex V8_FINAL : public LTemplateInstruction<1, 2, 0> { public: LLoadFieldByIndex(LOperand* object, LOperand* index) { inputs_[0] = object; @@ -2580,7 +2615,7 @@ class LLoadFieldByIndex: public LTemplateInstruction<1, 2, 0> { class LChunkBuilder; -class LPlatformChunk: public LChunk { +class LPlatformChunk V8_FINAL : public LChunk { public: LPlatformChunk(CompilationInfo* info, HGraph* graph) : LChunk(info, graph) { } @@ -2590,7 +2625,7 @@ class LPlatformChunk: public LChunk { }; -class LChunkBuilder BASE_EMBEDDED { +class LChunkBuilder V8_FINAL BASE_EMBEDDED { public: LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) : chunk_(NULL), diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 12fce439f2..7f65023ed0 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -31,12 +31,13 @@ #include "arm/lithium-gap-resolver-arm.h" #include "code-stubs.h" #include "stub-cache.h" +#include "hydrogen-osr.h" namespace v8 { namespace internal { -class SafepointGenerator : public CallWrapper { +class SafepointGenerator V8_FINAL : public CallWrapper { public: SafepointGenerator(LCodeGen* codegen, LPointerMap* pointers, @@ -44,11 +45,11 @@ class SafepointGenerator : public CallWrapper { : codegen_(codegen), pointers_(pointers), deopt_mode_(mode) { } - virtual ~SafepointGenerator() { } + virtual ~SafepointGenerator() {} - virtual void BeforeCall(int call_size) const { } + virtual void BeforeCall(int call_size) const V8_OVERRIDE {} - virtual void AfterCall() const { + virtual void AfterCall() const V8_OVERRIDE { codegen_->RecordSafepoint(pointers_, deopt_mode_); } @@ -253,6 +254,21 @@ bool LCodeGen::GeneratePrologue() { } +void LCodeGen::GenerateOsrPrologue() { + // Generate the OSR entry prologue at the first unknown OSR value, or if there + // are none, at the OSR entrypoint instruction. + if (osr_pc_offset_ >= 0) return; + + osr_pc_offset_ = masm()->pc_offset(); + + // Adjust the frame size, subsuming the unoptimized frame into the + // optimized frame. + int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); + ASSERT(slots >= 0); + __ sub(sp, sp, Operand(slots * kPointerSize)); +} + + bool LCodeGen::GenerateBody() { ASSERT(is_generating()); bool emit_instructions = true; @@ -423,7 +439,7 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { } else if (op->IsConstantOperand()) { LConstantOperand* const_op = LConstantOperand::cast(op); HConstant* constant = chunk_->LookupConstant(const_op); - Handle<Object> literal = constant->handle(); + Handle<Object> literal = constant->handle(isolate()); Representation r = chunk_->LookupLiteralRepresentation(const_op); if (r.IsInteger32()) { ASSERT(literal->IsNumber()); @@ -431,7 +447,7 @@ Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { } else if (r.IsDouble()) { Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); } else { - ASSERT(r.IsTagged()); + ASSERT(r.IsSmiOrTagged()); __ LoadObject(scratch, literal); } return scratch; @@ -458,7 +474,7 @@ DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, } else if (op->IsConstantOperand()) { LConstantOperand* const_op = LConstantOperand::cast(op); HConstant* constant = chunk_->LookupConstant(const_op); - Handle<Object> literal = constant->handle(); + Handle<Object> literal = constant->handle(isolate()); Representation r = chunk_->LookupLiteralRepresentation(const_op); if (r.IsInteger32()) { ASSERT(literal->IsNumber()); @@ -486,7 +502,7 @@ DwVfpRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { HConstant* constant = chunk_->LookupConstant(op); ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged()); - return constant->handle(); + return constant->handle(isolate()); } @@ -543,7 +559,7 @@ Operand LCodeGen::ToOperand(LOperand* op) { Abort(kToOperandUnsupportedDoubleImmediate); } ASSERT(r.IsTagged()); - return Operand(constant->handle()); + return Operand(constant->handle(isolate())); } else if (op->IsRegister()) { return Operand(ToRegister(op)); } else if (op->IsDoubleRegister()) { @@ -690,7 +706,7 @@ void LCodeGen::AddToTranslation(LEnvironment* environment, translation->StoreDoubleRegister(reg); } else if (op->IsConstantOperand()) { HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op)); - int src_index = DefineDeoptimizationLiteral(constant->handle()); + int src_index = DefineDeoptimizationLiteral(constant->handle(isolate())); translation->StoreLiteral(src_index); } else { UNREACHABLE(); @@ -1098,8 +1114,7 @@ void LCodeGen::DoCallStub(LCallStub* instr) { void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { - // Record the address of the first unknown OSR value as the place to enter. - if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); + GenerateOsrPrologue(); } @@ -1573,21 +1588,17 @@ void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { void LCodeGen::DoMulI(LMulI* instr) { - Register scratch = scratch0(); Register result = ToRegister(instr->result()); // Note that result may alias left. Register left = ToRegister(instr->left()); LOperand* right_op = instr->right(); - bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); bool bailout_on_minus_zero = instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); + bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); - if (right_op->IsConstantOperand() && !can_overflow) { - // Use optimized code for specific constants. - int32_t constant = ToRepresentation( - LConstantOperand::cast(right_op), - instr->hydrogen()->right()->representation()); + if (right_op->IsConstantOperand()) { + int32_t constant = ToInteger32(LConstantOperand::cast(right_op)); if (bailout_on_minus_zero && (constant < 0)) { // The case of a null constant will be handled separately. @@ -1598,7 +1609,12 @@ void LCodeGen::DoMulI(LMulI* instr) { switch (constant) { case -1: - __ rsb(result, left, Operand::Zero()); + if (overflow) { + __ rsb(result, left, Operand::Zero(), SetCC); + DeoptimizeIf(vs, instr->environment()); + } else { + __ rsb(result, left, Operand::Zero()); + } break; case 0: if (bailout_on_minus_zero) { @@ -1619,23 +1635,21 @@ void LCodeGen::DoMulI(LMulI* instr) { int32_t mask = constant >> 31; uint32_t constant_abs = (constant + mask) ^ mask; - if (IsPowerOf2(constant_abs) || - IsPowerOf2(constant_abs - 1) || - IsPowerOf2(constant_abs + 1)) { - if (IsPowerOf2(constant_abs)) { - int32_t shift = WhichPowerOf2(constant_abs); - __ mov(result, Operand(left, LSL, shift)); - } else if (IsPowerOf2(constant_abs - 1)) { - int32_t shift = WhichPowerOf2(constant_abs - 1); - __ add(result, left, Operand(left, LSL, shift)); - } else if (IsPowerOf2(constant_abs + 1)) { - int32_t shift = WhichPowerOf2(constant_abs + 1); - __ rsb(result, left, Operand(left, LSL, shift)); - } - + if (IsPowerOf2(constant_abs)) { + int32_t shift = WhichPowerOf2(constant_abs); + __ mov(result, Operand(left, LSL, shift)); + // Correct the sign of the result is the constant is negative. + if (constant < 0) __ rsb(result, result, Operand::Zero()); + } else if (IsPowerOf2(constant_abs - 1)) { + int32_t shift = WhichPowerOf2(constant_abs - 1); + __ add(result, left, Operand(left, LSL, shift)); + // Correct the sign of the result is the constant is negative. + if (constant < 0) __ rsb(result, result, Operand::Zero()); + } else if (IsPowerOf2(constant_abs + 1)) { + int32_t shift = WhichPowerOf2(constant_abs + 1); + __ rsb(result, left, Operand(left, LSL, shift)); // Correct the sign of the result is the constant is negative. if (constant < 0) __ rsb(result, result, Operand::Zero()); - } else { // Generate standard code. __ mov(ip, Operand(constant)); @@ -1644,12 +1658,11 @@ void LCodeGen::DoMulI(LMulI* instr) { } } else { - Register right = EmitLoadRegister(right_op, scratch); - if (bailout_on_minus_zero) { - __ orr(ToRegister(instr->temp()), left, right); - } + ASSERT(right_op->IsRegister()); + Register right = ToRegister(right_op); - if (can_overflow) { + if (overflow) { + Register scratch = scratch0(); // scratch:result = left * right. if (instr->hydrogen()->representation().IsSmi()) { __ SmiUntag(result, left); @@ -1669,12 +1682,12 @@ void LCodeGen::DoMulI(LMulI* instr) { } if (bailout_on_minus_zero) { - // Bail out if the result is supposed to be negative zero. Label done; + __ teq(left, Operand(right)); + __ b(pl, &done); + // Bail out if the result is minus zero. __ cmp(result, Operand::Zero()); - __ b(ne, &done); - __ cmp(ToRegister(instr->temp()), Operand::Zero()); - DeoptimizeIf(mi, instr->environment()); + DeoptimizeIf(eq, instr->environment()); __ bind(&done); } } @@ -1871,7 +1884,7 @@ void LCodeGen::DoConstantE(LConstantE* instr) { void LCodeGen::DoConstantT(LConstantT* instr) { - Handle<Object> value = instr->value(); + Handle<Object> value = instr->value(isolate()); AllowDeferredHandleDereference smi_check; __ LoadObject(ToRegister(instr->result()), value); } @@ -2735,15 +2748,15 @@ void LCodeGen::DoInstanceOf(LInstanceOf* instr) { void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { - class DeferredInstanceOfKnownGlobal: public LDeferredCode { + class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode { public: DeferredInstanceOfKnownGlobal(LCodeGen* codegen, LInstanceOfKnownGlobal* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { + virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); } - virtual LInstruction* instr() { return instr_; } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } Label* map_check() { return &map_check_; } private: LInstanceOfKnownGlobal* instr_; @@ -3722,14 +3735,14 @@ void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { void LCodeGen::DoMathAbs(LMathAbs* instr) { // Class for deferred case. - class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { + class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode { public: DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { + virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LMathAbs* instr_; }; @@ -3878,80 +3891,64 @@ void LCodeGen::DoPower(LPower* instr) { void LCodeGen::DoRandom(LRandom* instr) { - class DeferredDoRandom: public LDeferredCode { - public: - DeferredDoRandom(LCodeGen* codegen, LRandom* instr) - : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredRandom(instr_); } - virtual LInstruction* instr() { return instr_; } - private: - LRandom* instr_; - }; - - DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr); - - // Having marked this instruction as a call we can use any - // registers. - ASSERT(ToDoubleRegister(instr->result()).is(d7)); - ASSERT(ToRegister(instr->global_object()).is(r0)); - + // Assert that the register size is indeed the size of each seed. static const int kSeedSize = sizeof(uint32_t); STATIC_ASSERT(kPointerSize == kSeedSize); - __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset)); + // Load native context + Register global_object = ToRegister(instr->global_object()); + Register native_context = global_object; + __ ldr(native_context, FieldMemOperand( + global_object, GlobalObject::kNativeContextOffset)); + + // Load state (FixedArray of the native context's random seeds) static const int kRandomSeedOffset = FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; - __ ldr(r2, FieldMemOperand(r0, kRandomSeedOffset)); - // r2: FixedArray of the native context's random seeds + Register state = native_context; + __ ldr(state, FieldMemOperand(native_context, kRandomSeedOffset)); // Load state[0]. - __ ldr(r1, FieldMemOperand(r2, ByteArray::kHeaderSize)); - __ cmp(r1, Operand::Zero()); - __ b(eq, deferred->entry()); + Register state0 = ToRegister(instr->scratch()); + __ ldr(state0, FieldMemOperand(state, ByteArray::kHeaderSize)); // Load state[1]. - __ ldr(r0, FieldMemOperand(r2, ByteArray::kHeaderSize + kSeedSize)); - // r1: state[0]. - // r0: state[1]. + Register state1 = ToRegister(instr->scratch2()); + __ ldr(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize)); // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) - __ and_(r3, r1, Operand(0xFFFF)); - __ mov(r4, Operand(18273)); - __ mul(r3, r3, r4); - __ add(r1, r3, Operand(r1, LSR, 16)); + Register scratch3 = ToRegister(instr->scratch3()); + Register scratch4 = scratch0(); + __ and_(scratch3, state0, Operand(0xFFFF)); + __ mov(scratch4, Operand(18273)); + __ mul(scratch3, scratch3, scratch4); + __ add(state0, scratch3, Operand(state0, LSR, 16)); // Save state[0]. - __ str(r1, FieldMemOperand(r2, ByteArray::kHeaderSize)); + __ str(state0, FieldMemOperand(state, ByteArray::kHeaderSize)); // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) - __ and_(r3, r0, Operand(0xFFFF)); - __ mov(r4, Operand(36969)); - __ mul(r3, r3, r4); - __ add(r0, r3, Operand(r0, LSR, 16)); + __ and_(scratch3, state1, Operand(0xFFFF)); + __ mov(scratch4, Operand(36969)); + __ mul(scratch3, scratch3, scratch4); + __ add(state1, scratch3, Operand(state1, LSR, 16)); // Save state[1]. - __ str(r0, FieldMemOperand(r2, ByteArray::kHeaderSize + kSeedSize)); + __ str(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize)); // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF) - __ and_(r0, r0, Operand(0x3FFFF)); - __ add(r0, r0, Operand(r1, LSL, 14)); + Register random = scratch4; + __ and_(random, state1, Operand(0x3FFFF)); + __ add(random, random, Operand(state0, LSL, 14)); - __ bind(deferred->exit()); // 0x41300000 is the top half of 1.0 x 2^20 as a double. // Create this constant using mov/orr to avoid PC relative load. - __ mov(r1, Operand(0x41000000)); - __ orr(r1, r1, Operand(0x300000)); + __ mov(scratch3, Operand(0x41000000)); + __ orr(scratch3, scratch3, Operand(0x300000)); // Move 0x41300000xxxxxxxx (x = random bits) to VFP. - __ vmov(d7, r0, r1); + DwVfpRegister result = ToDoubleRegister(instr->result()); + __ vmov(result, random, scratch3); // Move 0x4130000000000000 to VFP. - __ mov(r0, Operand::Zero()); - __ vmov(d8, r0, r1); - // Subtract and store the result in the heap number. - __ vsub(d7, d7, d8); -} - - -void LCodeGen::DoDeferredRandom(LRandom* instr) { - __ PrepareCallCFunction(1, scratch0()); - __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); - // Return value is in r0. + __ mov(scratch4, Operand::Zero()); + DwVfpRegister scratch5 = double_scratch0(); + __ vmov(scratch5, scratch4, scratch3); + __ vsub(result, result, scratch5); } @@ -4146,6 +4143,15 @@ void LCodeGen::DoCallRuntime(LCallRuntime* instr) { } +void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { + Register function = ToRegister(instr->function()); + Register code_object = ToRegister(instr->code_object()); + __ add(code_object, code_object, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ str(code_object, + FieldMemOperand(function, JSFunction::kCodeEntryOffset)); +} + + void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) { Register result = ToRegister(instr->result()); Register base = ToRegister(instr->base_object()); @@ -4520,12 +4526,14 @@ void LCodeGen::DoStringAdd(LStringAdd* instr) { void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { - class DeferredStringCharCodeAt: public LDeferredCode { + class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode { public: DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredStringCharCodeAt(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LStringCharCodeAt* instr_; }; @@ -4573,12 +4581,14 @@ void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { - class DeferredStringCharFromCode: public LDeferredCode { + class DeferredStringCharFromCode V8_FINAL : public LDeferredCode { public: DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredStringCharFromCode(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LStringCharFromCode* instr_; }; @@ -4661,16 +4671,16 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { void LCodeGen::DoNumberTagI(LNumberTagI* instr) { - class DeferredNumberTagI: public LDeferredCode { + class DeferredNumberTagI V8_FINAL : public LDeferredCode { public: DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { + virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32); } - virtual LInstruction* instr() { return instr_; } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LNumberTagI* instr_; }; @@ -4686,16 +4696,16 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) { void LCodeGen::DoNumberTagU(LNumberTagU* instr) { - class DeferredNumberTagU: public LDeferredCode { + class DeferredNumberTagU V8_FINAL : public LDeferredCode { public: DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { + virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32); } - virtual LInstruction* instr() { return instr_; } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LNumberTagU* instr_; }; @@ -4768,12 +4778,14 @@ void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, void LCodeGen::DoNumberTagD(LNumberTagD* instr) { - class DeferredNumberTagD: public LDeferredCode { + class DeferredNumberTagD V8_FINAL : public LDeferredCode { public: DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredNumberTagD(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LNumberTagD* instr_; }; @@ -4902,7 +4914,7 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { Register scratch1 = scratch0(); Register scratch2 = ToRegister(instr->temp()); LowDwVfpRegister double_scratch = double_scratch0(); - DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp3()); + DwVfpRegister double_scratch2 = ToDoubleRegister(instr->temp2()); ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); @@ -4913,18 +4925,14 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // The carry flag is set when we reach this deferred code as we just executed // SmiUntag(heap_object, SetCC) STATIC_ASSERT(kHeapObjectTag == 1); - __ adc(input_reg, input_reg, Operand(input_reg)); + __ adc(scratch2, input_reg, Operand(input_reg)); // Heap number map check. - __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset)); + __ ldr(scratch1, FieldMemOperand(scratch2, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); __ cmp(scratch1, Operand(ip)); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - ASSERT(!scratch3.is(input_reg) && - !scratch3.is(scratch1) && - !scratch3.is(scratch2)); // Performs a truncating conversion of a floating point number as used by // the JS bitwise operations. Label heap_number; @@ -4932,23 +4940,18 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { // Check for undefined. Undefined is converted to zero for truncating // conversions. __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); - __ cmp(input_reg, Operand(ip)); + __ cmp(scratch2, Operand(ip)); DeoptimizeIf(ne, instr->environment()); __ mov(input_reg, Operand::Zero()); __ b(&done); __ bind(&heap_number); - __ sub(scratch1, input_reg, Operand(kHeapObjectTag)); - __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset); - - __ ECMAToInt32(input_reg, double_scratch2, - scratch1, scratch2, scratch3, double_scratch); - + __ TruncateHeapNumberToI(input_reg, scratch2); } else { // Deoptimize if we don't have a heap number. DeoptimizeIf(ne, instr->environment()); - __ sub(ip, input_reg, Operand(kHeapObjectTag)); + __ sub(ip, scratch2, Operand(kHeapObjectTag)); __ vldr(double_scratch2, ip, HeapNumber::kValueOffset); __ TryDoubleToInt32Exact(input_reg, double_scratch2, double_scratch); DeoptimizeIf(ne, instr->environment()); @@ -4966,12 +4969,14 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { void LCodeGen::DoTaggedToI(LTaggedToI* instr) { - class DeferredTaggedToI: public LDeferredCode { + class DeferredTaggedToI V8_FINAL : public LDeferredCode { public: DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredTaggedToI(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LTaggedToI* instr_; }; @@ -5018,14 +5023,11 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { void LCodeGen::DoDoubleToI(LDoubleToI* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_input = ToDoubleRegister(instr->value()); LowDwVfpRegister double_scratch = double_scratch0(); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - __ ECMAToInt32(result_reg, double_input, - scratch1, scratch2, scratch3, double_scratch); + __ TruncateDoubleToI(result_reg, double_input); } else { __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); // Deoptimize if the input wasn't a int32 (inside a double). @@ -5046,14 +5048,11 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { Register result_reg = ToRegister(instr->result()); Register scratch1 = scratch0(); - Register scratch2 = ToRegister(instr->temp()); DwVfpRegister double_input = ToDoubleRegister(instr->value()); LowDwVfpRegister double_scratch = double_scratch0(); if (instr->truncating()) { - Register scratch3 = ToRegister(instr->temp2()); - __ ECMAToInt32(result_reg, double_input, - scratch1, scratch2, scratch3, double_scratch); + __ TruncateDoubleToI(result_reg, double_input); } else { __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); // Deoptimize if the input wasn't a int32 (inside a double). @@ -5132,18 +5131,18 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { } -void LCodeGen::DoCheckFunction(LCheckFunction* instr) { +void LCodeGen::DoCheckValue(LCheckValue* instr) { Register reg = ToRegister(instr->value()); - Handle<JSFunction> target = instr->hydrogen()->target(); + Handle<HeapObject> object = instr->hydrogen()->object(); AllowDeferredHandleDereference smi_check; - if (isolate()->heap()->InNewSpace(*target)) { + if (isolate()->heap()->InNewSpace(*object)) { Register reg = ToRegister(instr->value()); - Handle<Cell> cell = isolate()->factory()->NewCell(target); + Handle<Cell> cell = isolate()->factory()->NewCell(object); __ mov(ip, Operand(Handle<Object>(cell))); __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset)); __ cmp(reg, ip); } else { - __ cmp(reg, Operand(target)); + __ cmp(reg, Operand(object)); } DeoptimizeIf(ne, instr->environment()); } @@ -5162,17 +5161,17 @@ void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { void LCodeGen::DoCheckMaps(LCheckMaps* instr) { - class DeferredCheckMaps: public LDeferredCode { + class DeferredCheckMaps V8_FINAL : public LDeferredCode { public: DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) : LDeferredCode(codegen), instr_(instr), object_(object) { SetExit(check_maps()); } - virtual void Generate() { + virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredInstanceMigration(instr_, object_); } Label* check_maps() { return &check_maps_; } - virtual LInstruction* instr() { return instr_; } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LCheckMaps* instr_; Label check_maps_; @@ -5265,12 +5264,14 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { void LCodeGen::DoAllocate(LAllocate* instr) { - class DeferredAllocate: public LDeferredCode { + class DeferredAllocate V8_FINAL : public LDeferredCode { public: DeferredAllocate(LCodeGen* codegen, LAllocate* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredAllocate(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LAllocate* instr_; }; @@ -5422,8 +5423,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { if (!pretenure && instr->hydrogen()->has_no_literals()) { FastNewClosureStub stub(instr->hydrogen()->language_mode(), instr->hydrogen()->is_generator()); - __ mov(r1, Operand(instr->hydrogen()->shared_info())); - __ push(r1); + __ mov(r2, Operand(instr->hydrogen()->shared_info())); CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); } else { __ mov(r2, Operand(instr->hydrogen()->shared_info())); @@ -5621,12 +5621,14 @@ void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { void LCodeGen::DoStackCheck(LStackCheck* instr) { - class DeferredStackCheck: public LDeferredCode { + class DeferredStackCheck V8_FINAL : public LDeferredCode { public: DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) : LDeferredCode(codegen), instr_(instr) { } - virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } - virtual LInstruction* instr() { return instr_; } + virtual void Generate() V8_OVERRIDE { + codegen()->DoDeferredStackCheck(instr_); + } + virtual LInstruction* instr() V8_OVERRIDE { return instr_; } private: LStackCheck* instr_; }; @@ -5641,9 +5643,10 @@ void LCodeGen::DoStackCheck(LStackCheck* instr) { __ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(ip)); __ b(hs, &done); - StackCheckStub stub; PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize); - CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); + CallCode(isolate()->builtins()->StackCheck(), + RelocInfo::CODE_TARGET, + instr); EnsureSpaceForLazyDeopt(); last_lazy_deopt_pc_ = masm()->pc_offset(); __ bind(&done); @@ -5680,9 +5683,7 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { ASSERT(!environment->HasBeenRegistered()); RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); - // Normally we record the first unknown OSR value as the entrypoint to the OSR - // code, but if there were none, record the entrypoint here. - if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); + GenerateOsrPrologue(); } diff --git a/deps/v8/src/arm/lithium-codegen-arm.h b/deps/v8/src/arm/lithium-codegen-arm.h index d0bfcbbb94..4b6b5ca8e3 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.h +++ b/deps/v8/src/arm/lithium-codegen-arm.h @@ -43,7 +43,7 @@ namespace internal { class LDeferredCode; class SafepointGenerator; -class LCodeGen BASE_EMBEDDED { +class LCodeGen V8_FINAL BASE_EMBEDDED { public: LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info) : zone_(info->zone()), @@ -149,7 +149,6 @@ class LCodeGen BASE_EMBEDDED { void DoDeferredTaggedToI(LTaggedToI* instr); void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr); void DoDeferredStackCheck(LStackCheck* instr); - void DoDeferredRandom(LRandom* instr); void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr); void DoDeferredStringCharFromCode(LStringCharFromCode* instr); void DoDeferredAllocate(LAllocate* instr); @@ -227,6 +226,9 @@ class LCodeGen BASE_EMBEDDED { bool GenerateDeoptJumpTable(); bool GenerateSafepointTable(); + // Generates the custom OSR entrypoint and sets the osr_pc_offset. + void GenerateOsrPrologue(); + enum SafepointMode { RECORD_SIMPLE_SAFEPOINT, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS @@ -420,7 +422,7 @@ class LCodeGen BASE_EMBEDDED { int old_position_; - class PushSafepointRegistersScope BASE_EMBEDDED { + class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED { public: PushSafepointRegistersScope(LCodeGen* codegen, Safepoint::Kind kind) @@ -468,7 +470,7 @@ class LCodeGen BASE_EMBEDDED { }; -class LDeferredCode: public ZoneObject { +class LDeferredCode : public ZoneObject { public: explicit LDeferredCode(LCodeGen* codegen) : codegen_(codegen), @@ -477,7 +479,7 @@ class LDeferredCode: public ZoneObject { codegen->AddDeferredCode(this); } - virtual ~LDeferredCode() { } + virtual ~LDeferredCode() {} virtual void Generate() = 0; virtual LInstruction* instr() = 0; diff --git a/deps/v8/src/arm/lithium-gap-resolver-arm.h b/deps/v8/src/arm/lithium-gap-resolver-arm.h index 9dd09c8d03..044c2864a4 100644 --- a/deps/v8/src/arm/lithium-gap-resolver-arm.h +++ b/deps/v8/src/arm/lithium-gap-resolver-arm.h @@ -38,7 +38,7 @@ namespace internal { class LCodeGen; class LGapResolver; -class LGapResolver BASE_EMBEDDED { +class LGapResolver V8_FINAL BASE_EMBEDDED { public: explicit LGapResolver(LCodeGen* owner); diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 974b56959f..7df785776d 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -829,26 +829,6 @@ void MacroAssembler::VmovLow(DwVfpRegister dst, Register src) { } -void MacroAssembler::ConvertNumberToInt32(Register object, - Register dst, - Register heap_number_map, - Register scratch1, - Register scratch2, - Register scratch3, - DwVfpRegister double_scratch1, - LowDwVfpRegister double_scratch2, - Label* not_number) { - Label done; - UntagAndJumpIfSmi(dst, object, &done); - JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); - vldr(double_scratch1, FieldMemOperand(object, HeapNumber::kValueOffset)); - ECMAToInt32(dst, double_scratch1, - scratch1, scratch2, scratch3, double_scratch2); - - bind(&done); -} - - void MacroAssembler::LoadNumber(Register object, LowDwVfpRegister dst, Register heap_number_map, @@ -1702,15 +1682,9 @@ void MacroAssembler::Allocate(int object_size, ASSERT((limit - top) == kPointerSize); ASSERT(result.code() < ip.code()); - // Set up allocation top address and object size registers. + // Set up allocation top address register. Register topaddr = scratch1; - Register obj_size_reg = scratch2; mov(topaddr, Operand(allocation_top)); - Operand obj_size_operand = Operand(object_size); - if (!obj_size_operand.is_single_instruction(this)) { - // We are about to steal IP, so we need to load this value first - mov(obj_size_reg, obj_size_operand); - } // This code stores a temporary value in ip. This is OK, as the code below // does not need ip for implicit literal generation. @@ -1734,7 +1708,7 @@ void MacroAssembler::Allocate(int object_size, // Align the next allocation. Storing the filler map without checking top is // safe in new-space because the limit of the heap is aligned there. ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0); - ASSERT(kPointerAlignment * 2 == kDoubleAlignment); + STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment); and_(scratch2, result, Operand(kDoubleAlignmentMask), SetCC); Label aligned; b(eq, &aligned); @@ -1748,13 +1722,25 @@ void MacroAssembler::Allocate(int object_size, } // Calculate new top and bail out if new space is exhausted. Use result - // to calculate the new top. - if (obj_size_operand.is_single_instruction(this)) { - // We can add the size as an immediate - add(scratch2, result, obj_size_operand, SetCC); - } else { - // Doesn't fit in an immediate, we have to use the register - add(scratch2, result, obj_size_reg, SetCC); + // to calculate the new top. We must preserve the ip register at this + // point, so we cannot just use add(). + ASSERT(object_size > 0); + Register source = result; + Condition cond = al; + int shift = 0; + while (object_size != 0) { + if (((object_size >> shift) & 0x03) == 0) { + shift += 2; + } else { + int bits = object_size & (0xff << shift); + object_size -= bits; + shift += 8; + Operand bits_operand(bits); + ASSERT(bits_operand.is_single_instruction(this)); + add(scratch2, source, bits_operand, SetCC, cond); + source = scratch2; + cond = cc; + } } b(cs, gc_required); cmp(scratch2, Operand(ip)); @@ -2299,7 +2285,6 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, ExternalReference thunk_ref, Register thunk_last_arg, int stack_space, - bool returns_handle, int return_value_offset) { ExternalReference next_address = ExternalReference::handle_scope_next_address(isolate()); @@ -2368,15 +2353,6 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function, Label leave_exit_frame; Label return_value_loaded; - if (returns_handle) { - Label load_return_value; - cmp(r0, Operand::Zero()); - b(eq, &load_return_value); - // derefernce returned value - ldr(r0, MemOperand(r0)); - b(&return_value_loaded); - bind(&load_return_value); - } // load value from ReturnValue ldr(r0, MemOperand(fp, return_value_offset*kPointerSize)); bind(&return_value_loaded); @@ -2532,84 +2508,76 @@ void MacroAssembler::TryInt32Floor(Register result, bind(&exception); } - -void MacroAssembler::ECMAToInt32(Register result, - DwVfpRegister double_input, - Register scratch, - Register scratch_high, - Register scratch_low, - LowDwVfpRegister double_scratch) { - ASSERT(!scratch_high.is(result)); - ASSERT(!scratch_low.is(result)); - ASSERT(!scratch_low.is(scratch_high)); - ASSERT(!scratch.is(result) && - !scratch.is(scratch_high) && - !scratch.is(scratch_low)); - ASSERT(!double_input.is(double_scratch)); - - Label out_of_range, only_low, negate, done; - +void MacroAssembler::TryInlineTruncateDoubleToI(Register result, + DwVfpRegister double_input, + Label* done) { + LowDwVfpRegister double_scratch = kScratchDoubleReg; vcvt_s32_f64(double_scratch.low(), double_input); vmov(result, double_scratch.low()); // If result is not saturated (0x7fffffff or 0x80000000), we are done. - sub(scratch, result, Operand(1)); - cmp(scratch, Operand(0x7ffffffe)); - b(lt, &done); + sub(ip, result, Operand(1)); + cmp(ip, Operand(0x7ffffffe)); + b(lt, done); +} - vmov(scratch_low, scratch_high, double_input); - Ubfx(scratch, scratch_high, - HeapNumber::kExponentShift, HeapNumber::kExponentBits); - // Load scratch with exponent - 1. This is faster than loading - // with exponent because Bias + 1 = 1024 which is an *ARM* immediate value. - sub(scratch, scratch, Operand(HeapNumber::kExponentBias + 1)); - // If exponent is greater than or equal to 84, the 32 less significant - // bits are 0s (2^84 = 1, 52 significant bits, 32 uncoded bits), - // the result is 0. - // Compare exponent with 84 (compare exponent - 1 with 83). - cmp(scratch, Operand(83)); - b(ge, &out_of_range); - - // If we reach this code, 31 <= exponent <= 83. - // So, we don't have to handle cases where 0 <= exponent <= 20 for - // which we would need to shift right the high part of the mantissa. - // Scratch contains exponent - 1. - // Load scratch with 52 - exponent (load with 51 - (exponent - 1)). - rsb(scratch, scratch, Operand(51), SetCC); - b(ls, &only_low); - // 21 <= exponent <= 51, shift scratch_low and scratch_high - // to generate the result. - mov(scratch_low, Operand(scratch_low, LSR, scratch)); - // Scratch contains: 52 - exponent. - // We needs: exponent - 20. - // So we use: 32 - scratch = 32 - 52 + exponent = exponent - 20. - rsb(scratch, scratch, Operand(32)); - Ubfx(result, scratch_high, - 0, HeapNumber::kMantissaBitsInTopWord); - // Set the implicit 1 before the mantissa part in scratch_high. - orr(result, result, Operand(1 << HeapNumber::kMantissaBitsInTopWord)); - orr(result, scratch_low, Operand(result, LSL, scratch)); - b(&negate); - - bind(&out_of_range); - mov(result, Operand::Zero()); - b(&done); - bind(&only_low); - // 52 <= exponent <= 83, shift only scratch_low. - // On entry, scratch contains: 52 - exponent. - rsb(scratch, scratch, Operand::Zero()); - mov(result, Operand(scratch_low, LSL, scratch)); - - bind(&negate); - // If input was positive, scratch_high ASR 31 equals 0 and - // scratch_high LSR 31 equals zero. - // New result = (result eor 0) + 0 = result. - // If the input was negative, we have to negate the result. - // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1. - // New result = (result eor 0xffffffff) + 1 = 0 - result. - eor(result, result, Operand(scratch_high, ASR, 31)); - add(result, result, Operand(scratch_high, LSR, 31)); +void MacroAssembler::TruncateDoubleToI(Register result, + DwVfpRegister double_input) { + Label done; + + TryInlineTruncateDoubleToI(result, double_input, &done); + + // If we fell through then inline version didn't succeed - call stub instead. + push(lr); + sub(sp, sp, Operand(kDoubleSize)); // Put input on stack. + vstr(double_input, MemOperand(sp, 0)); + + DoubleToIStub stub(sp, result, 0, true, true); + CallStub(&stub); + + add(sp, sp, Operand(kDoubleSize)); + pop(lr); + + bind(&done); +} + + +void MacroAssembler::TruncateHeapNumberToI(Register result, + Register object) { + Label done; + LowDwVfpRegister double_scratch = kScratchDoubleReg; + ASSERT(!result.is(object)); + + vldr(double_scratch, + MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag)); + TryInlineTruncateDoubleToI(result, double_scratch, &done); + + // If we fell through then inline version didn't succeed - call stub instead. + push(lr); + DoubleToIStub stub(object, + result, + HeapNumber::kValueOffset - kHeapObjectTag, + true, + true); + CallStub(&stub); + pop(lr); + + bind(&done); +} + + +void MacroAssembler::TruncateNumberToI(Register object, + Register result, + Register heap_number_map, + Register scratch1, + Label* not_number) { + Label done; + ASSERT(!result.is(object)); + + UntagAndJumpIfSmi(result, object, &done); + JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); + TruncateHeapNumberToI(result, object); bind(&done); } @@ -2841,6 +2809,11 @@ void MacroAssembler::Abort(BailoutReason reason) { RecordComment("Abort message: "); RecordComment(msg); } + + if (FLAG_trap_on_abort) { + stop(msg); + return; + } #endif mov(r0, Operand(p0)); @@ -3824,6 +3797,30 @@ void MacroAssembler::TestJSArrayForAllocationMemento( } +Register GetRegisterThatIsNotOneOf(Register reg1, + Register reg2, + Register reg3, + Register reg4, + Register reg5, + Register reg6) { + RegList regs = 0; + if (reg1.is_valid()) regs |= reg1.bit(); + if (reg2.is_valid()) regs |= reg2.bit(); + if (reg3.is_valid()) regs |= reg3.bit(); + if (reg4.is_valid()) regs |= reg4.bit(); + if (reg5.is_valid()) regs |= reg5.bit(); + if (reg6.is_valid()) regs |= reg6.bit(); + + for (int i = 0; i < Register::NumAllocatableRegisters(); i++) { + Register candidate = Register::FromAllocationIndex(i); + if (regs & candidate.bit()) continue; + return candidate; + } + UNREACHABLE(); + return no_reg; +} + + #ifdef DEBUG bool AreAliased(Register reg1, Register reg2, @@ -3848,10 +3845,13 @@ bool AreAliased(Register reg1, #endif -CodePatcher::CodePatcher(byte* address, int instructions) +CodePatcher::CodePatcher(byte* address, + int instructions, + FlushICache flush_cache) : address_(address), size_(instructions * Assembler::kInstrSize), - masm_(NULL, address, size_ + Assembler::kGap) { + masm_(NULL, address, size_ + Assembler::kGap), + flush_cache_(flush_cache) { // Create a new macro assembler pointing to the address of the code to patch. // The size is adjusted with kGap on order for the assembler to generate size // bytes of instructions without failing with buffer size constraints. @@ -3861,7 +3861,9 @@ CodePatcher::CodePatcher(byte* address, int instructions) CodePatcher::~CodePatcher() { // Indicate that code has changed. - CPU::FlushICache(address_, size_); + if (flush_cache_ == FLUSH) { + CPU::FlushICache(address_, size_); + } // Check that the code was patched as expected. ASSERT(masm_.pc_ == address_ + size_); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index 8b9fa2b221..9abd5a0c3d 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -62,6 +62,14 @@ enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK }; enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; +Register GetRegisterThatIsNotOneOf(Register reg1, + Register reg2 = no_reg, + Register reg3 = no_reg, + Register reg4 = no_reg, + Register reg5 = no_reg, + Register reg6 = no_reg); + + #ifdef DEBUG bool AreAliased(Register reg1, Register reg2, @@ -491,19 +499,6 @@ class MacroAssembler: public Assembler { void VmovLow(Register dst, DwVfpRegister src); void VmovLow(DwVfpRegister dst, Register src); - // Converts the smi or heap number in object to an int32 using the rules - // for ToInt32 as described in ECMAScript 9.5.: the value is truncated - // and brought into the range -2^31 .. +2^31 - 1. - void ConvertNumberToInt32(Register object, - Register dst, - Register heap_number_map, - Register scratch1, - Register scratch2, - Register scratch3, - DwVfpRegister double_scratch1, - LowDwVfpRegister double_scratch2, - Label* not_int32); - // Loads the number from object into dst register. // If |object| is neither smi nor heap number, |not_number| is jumped to // with |object| still intact. @@ -989,15 +984,34 @@ class MacroAssembler: public Assembler { Label* exact); // Performs a truncating conversion of a floating point number as used by + // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it + // succeeds, otherwise falls through if result is saturated. On return + // 'result' either holds answer, or is clobbered on fall through. + // + // Only public for the test code in test-code-stubs-arm.cc. + void TryInlineTruncateDoubleToI(Register result, + DwVfpRegister input, + Label* done); + + // Performs a truncating conversion of a floating point number as used by // the JS bitwise operations. See ECMA-262 9.5: ToInt32. - // Double_scratch must be between d0 and d15. - // Exits with 'result' holding the answer and all other registers clobbered. - void ECMAToInt32(Register result, - DwVfpRegister double_input, - Register scratch, - Register scratch_high, - Register scratch_low, - LowDwVfpRegister double_scratch); + // Exits with 'result' holding the answer. + void TruncateDoubleToI(Register result, DwVfpRegister double_input); + + // Performs a truncating conversion of a heap number as used by + // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input' + // must be different registers. Exits with 'result' holding the answer. + void TruncateHeapNumberToI(Register result, Register object); + + // Converts the smi or heap number in object to an int32 using the rules + // for ToInt32 as described in ECMAScript 9.5.: the value is truncated + // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be + // different registers. + void TruncateNumberToI(Register object, + Register result, + Register heap_number_map, + Register scratch1, + Label* not_int32); // Check whether d16-d31 are available on the CPU. The result is given by the // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise. @@ -1097,7 +1111,6 @@ class MacroAssembler: public Assembler { ExternalReference thunk_ref, Register thunk_last_arg, int stack_space, - bool returns_handle, int return_value_offset_from_fp); // Jump to a runtime routine. @@ -1416,7 +1429,14 @@ class MacroAssembler: public Assembler { // an assertion to fail. class CodePatcher { public: - CodePatcher(byte* address, int instructions); + enum FlushICache { + FLUSH, + DONT_FLUSH + }; + + CodePatcher(byte* address, + int instructions, + FlushICache flush_cache = FLUSH); virtual ~CodePatcher(); // Macro assembler to emit code. @@ -1436,6 +1456,7 @@ class CodePatcher { byte* address_; // The address of the code being patched. int size_; // Number of bytes of the expected patch size. MacroAssembler masm_; // Macro assembler used to generate the code. + FlushICache flush_cache_; // Whether to flush the I cache after patching. }; diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.cc b/deps/v8/src/arm/regexp-macro-assembler-arm.cc index 189ea8d777..cbc34e10b9 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.cc +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.cc @@ -134,7 +134,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM( exit_label_() { ASSERT_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code later. - EmitBacktrackConstantPool(); __ bind(&start_label_); // And then continue from here. } @@ -872,7 +871,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { masm_->GetCode(&code_desc); Handle<Code> code = isolate()->factory()->NewCode( code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject()); - PROFILE(Isolate::Current(), RegExpCodeCreateEvent(*code, *source)); + PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source)); return Handle<HeapObject>::cast(code); } @@ -938,37 +937,8 @@ void RegExpMacroAssemblerARM::PopRegister(int register_index) { } -static bool is_valid_memory_offset(int value) { - if (value < 0) value = -value; - return value < (1<<12); -} - - void RegExpMacroAssemblerARM::PushBacktrack(Label* label) { - if (label->is_bound()) { - int target = label->pos(); - __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag)); - } else { - int constant_offset = GetBacktrackConstantPoolEntry(); - masm_->label_at_put(label, constant_offset); - // Reading pc-relative is based on the address 8 bytes ahead of - // the current opcode. - unsigned int offset_of_pc_register_read = - masm_->pc_offset() + Assembler::kPcLoadDelta; - int pc_offset_of_constant = - constant_offset - offset_of_pc_register_read; - ASSERT(pc_offset_of_constant < 0); - if (is_valid_memory_offset(pc_offset_of_constant)) { - Assembler::BlockConstPoolScope block_const_pool(masm_); - __ ldr(r0, MemOperand(pc, pc_offset_of_constant)); - } else { - // Not a 12-bit offset, so it needs to be loaded from the constant - // pool. - Assembler::BlockConstPoolScope block_const_pool(masm_); - __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize)); - __ ldr(r0, MemOperand(pc, r0)); - } - } + __ mov_label_offset(r0, label); Push(r0); CheckStackLimit(); } @@ -1055,16 +1025,34 @@ void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { // Private methods: void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) { - static const int num_arguments = 3; - __ PrepareCallCFunction(num_arguments, scratch); + __ PrepareCallCFunction(3, scratch); + // RegExp code frame pointer. __ mov(r2, frame_pointer()); // Code* of self. __ mov(r1, Operand(masm_->CodeObject())); - // r0 becomes return address pointer. + + // We need to make room for the return address on the stack. + int stack_alignment = OS::ActivationFrameAlignment(); + ASSERT(IsAligned(stack_alignment, kPointerSize)); + __ sub(sp, sp, Operand(stack_alignment)); + + // r0 will point to the return address, placed by DirectCEntry. + __ mov(r0, sp); + ExternalReference stack_guard_check = ExternalReference::re_check_stack_guard_state(isolate()); - CallCFunctionUsingStub(stack_guard_check, num_arguments); + __ mov(ip, Operand(stack_guard_check)); + DirectCEntryStub stub; + stub.GenerateCall(masm_, ip); + + // Drop the return address from the stack. + __ add(sp, sp, Operand(stack_alignment)); + + ASSERT(stack_alignment != 0); + __ ldr(sp, MemOperand(sp, 0)); + + __ mov(code_pointer(), Operand(masm_->CodeObject())); } @@ -1079,7 +1067,6 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, Code* re_code, Address re_frame) { Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate); - ASSERT(isolate == Isolate::Current()); if (isolate->stack_guard()->IsStackOverflow()) { isolate->StackOverflow(); return EXCEPTION; @@ -1262,53 +1249,6 @@ void RegExpMacroAssemblerARM::CheckStackLimit() { } -void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() { - __ CheckConstPool(false, false); - Assembler::BlockConstPoolScope block_const_pool(masm_); - backtrack_constant_pool_offset_ = masm_->pc_offset(); - for (int i = 0; i < kBacktrackConstantPoolSize; i++) { - __ emit(0); - } - - backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize; -} - - -int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() { - while (backtrack_constant_pool_capacity_ > 0) { - int offset = backtrack_constant_pool_offset_; - backtrack_constant_pool_offset_ += kPointerSize; - backtrack_constant_pool_capacity_--; - if (masm_->pc_offset() - offset < 2 * KB) { - return offset; - } - } - Label new_pool_skip; - __ jmp(&new_pool_skip); - EmitBacktrackConstantPool(); - __ bind(&new_pool_skip); - int offset = backtrack_constant_pool_offset_; - backtrack_constant_pool_offset_ += kPointerSize; - backtrack_constant_pool_capacity_--; - return offset; -} - - -void RegExpMacroAssemblerARM::CallCFunctionUsingStub( - ExternalReference function, - int num_arguments) { - // Must pass all arguments in registers. The stub pushes on the stack. - ASSERT(num_arguments <= 4); - __ mov(code_pointer(), Operand(function)); - RegExpCEntryStub stub; - __ CallStub(&stub); - if (OS::ActivationFrameAlignment() != 0) { - __ ldr(sp, MemOperand(sp, 0)); - } - __ mov(code_pointer(), Operand(masm_->CodeObject())); -} - - bool RegExpMacroAssemblerARM::CanReadUnaligned() { return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe(); } @@ -1351,17 +1291,6 @@ void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset, } -void RegExpCEntryStub::Generate(MacroAssembler* masm_) { - int stack_alignment = OS::ActivationFrameAlignment(); - if (stack_alignment < kPointerSize) stack_alignment = kPointerSize; - // Stack is already aligned for call, so decrement by alignment - // to make room for storing the link register. - __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex)); - __ mov(r0, sp); - __ Call(r5); - __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex)); -} - #undef __ #endif // V8_INTERPRETED_REGEXP diff --git a/deps/v8/src/arm/regexp-macro-assembler-arm.h b/deps/v8/src/arm/regexp-macro-assembler-arm.h index 1825752ebc..9f07489e1f 100644 --- a/deps/v8/src/arm/regexp-macro-assembler-arm.h +++ b/deps/v8/src/arm/regexp-macro-assembler-arm.h @@ -160,9 +160,6 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { // Check whether we are exceeding the stack limit on the backtrack stack. void CheckStackLimit(); - void EmitBacktrackConstantPool(); - int GetBacktrackConstantPoolEntry(); - // Generate a call to CheckStackGuardState. void CallCheckStackGuardState(Register scratch); @@ -212,14 +209,6 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { // and increments it by a word size. inline void Pop(Register target); - // Calls a C function and cleans up the frame alignment done by - // by FrameAlign. The called function *is* allowed to trigger a garbage - // collection, but may not take more than four arguments (no arguments - // passed on the stack), and the first argument will be a pointer to the - // return address. - inline void CallCFunctionUsingStub(ExternalReference function, - int num_arguments); - Isolate* isolate() const { return masm_->isolate(); } MacroAssembler* masm_; diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index c9e3616d9d..def1818630 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -1686,20 +1686,12 @@ typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0); // This signature supports direct call in to API function native callback // (refer to InvocationCallback in v8.h). -typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0); -typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0); -typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)( - int32_t arg0, int32_t arg1); -typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1); +typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0); +typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, int32_t arg1); // This signature supports direct call to accessor getter callback. -typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, - int32_t arg1); -typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0, - int32_t arg1); -typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)( - int32_t arg0, int32_t arg1, int32_t arg2); -typedef void (*SimulatorRuntimeProfilingGetterCallNew)( +typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t arg1); +typedef void (*SimulatorRuntimeProfilingGetterCall)( int32_t arg0, int32_t arg1, int32_t arg2); // Software interrupt instructions are used by the simulator to call into the @@ -1839,9 +1831,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { break; } } - } else if ( - redirection->type() == ExternalReference::DIRECT_API_CALL || - redirection->type() == ExternalReference::DIRECT_API_CALL_NEW) { + } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF("Call to host function at %p args %08x", reinterpret_cast<void*>(external), arg0); @@ -1851,22 +1841,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintF("\n"); } CHECK(stack_aligned); - if (redirection->type() == ExternalReference::DIRECT_API_CALL) { - SimulatorRuntimeDirectApiCall target = - reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); - v8::Handle<v8::Value> result = target(arg0); - if (::v8::internal::FLAG_trace_sim) { - PrintF("Returned %p\n", reinterpret_cast<void *>(*result)); - } - set_register(r0, reinterpret_cast<int32_t>(*result)); - } else { - SimulatorRuntimeDirectApiCallNew target = - reinterpret_cast<SimulatorRuntimeDirectApiCallNew>(external); - target(arg0); - } + SimulatorRuntimeDirectApiCall target = + reinterpret_cast<SimulatorRuntimeDirectApiCall>(external); + target(arg0); } else if ( - redirection->type() == ExternalReference::PROFILING_API_CALL || - redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) { + redirection->type() == ExternalReference::PROFILING_API_CALL) { if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF("Call to host function at %p args %08x %08x", reinterpret_cast<void*>(external), arg0, arg1); @@ -1876,22 +1855,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintF("\n"); } CHECK(stack_aligned); - if (redirection->type() == ExternalReference::PROFILING_API_CALL) { - SimulatorRuntimeProfilingApiCall target = - reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external); - v8::Handle<v8::Value> result = target(arg0, arg1); - if (::v8::internal::FLAG_trace_sim) { - PrintF("Returned %p\n", reinterpret_cast<void *>(*result)); - } - set_register(r0, reinterpret_cast<int32_t>(*result)); - } else { - SimulatorRuntimeProfilingApiCallNew target = - reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external); - target(arg0, arg1); - } + SimulatorRuntimeProfilingApiCall target = + reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external); + target(arg0, arg1); } else if ( - redirection->type() == ExternalReference::DIRECT_GETTER_CALL || - redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) { + redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF("Call to host function at %p args %08x %08x", reinterpret_cast<void*>(external), arg0, arg1); @@ -1901,22 +1869,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintF("\n"); } CHECK(stack_aligned); - if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { - SimulatorRuntimeDirectGetterCall target = - reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); - v8::Handle<v8::Value> result = target(arg0, arg1); - if (::v8::internal::FLAG_trace_sim) { - PrintF("Returned %p\n", reinterpret_cast<void *>(*result)); - } - set_register(r0, reinterpret_cast<int32_t>(*result)); - } else { - SimulatorRuntimeDirectGetterCallNew target = - reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external); - target(arg0, arg1); - } + SimulatorRuntimeDirectGetterCall target = + reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external); + target(arg0, arg1); } else if ( - redirection->type() == ExternalReference::PROFILING_GETTER_CALL || - redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) { + redirection->type() == ExternalReference::PROFILING_GETTER_CALL) { if (::v8::internal::FLAG_trace_sim || !stack_aligned) { PrintF("Call to host function at %p args %08x %08x %08x", reinterpret_cast<void*>(external), arg0, arg1, arg2); @@ -1926,20 +1883,10 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintF("\n"); } CHECK(stack_aligned); - if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) { - SimulatorRuntimeProfilingGetterCall target = - reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external); - v8::Handle<v8::Value> result = target(arg0, arg1, arg2); - if (::v8::internal::FLAG_trace_sim) { - PrintF("Returned %p\n", reinterpret_cast<void *>(*result)); - } - set_register(r0, reinterpret_cast<int32_t>(*result)); - } else { - SimulatorRuntimeProfilingGetterCallNew target = - reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>( - external); - target(arg0, arg1, arg2); - } + SimulatorRuntimeProfilingGetterCall target = + reinterpret_cast<SimulatorRuntimeProfilingGetterCall>( + external); + target(arg0, arg1, arg2); } else { // builtin call. ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index 06bd66e92a..085af3f2b7 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -785,6 +785,11 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register holder, Register name, Handle<JSObject> holder_obj) { + STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0); + STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1); + STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2); + STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3); + STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4); __ push(name); Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor()); ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor)); @@ -793,10 +798,6 @@ static void PushInterceptorArguments(MacroAssembler* masm, __ push(scratch); __ push(receiver); __ push(holder); - __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset)); - __ push(scratch); - __ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate()))); - __ push(scratch); } @@ -811,7 +812,7 @@ static void CompileCallLoadPropertyWithInterceptor( ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly), masm->isolate()); - __ mov(r0, Operand(6)); + __ mov(r0, Operand(StubCache::kInterceptorArgsLength)); __ mov(r1, Operand(ref)); CEntryStub stub(1); @@ -903,23 +904,13 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, const int kStackUnwindSpace = argc + kFastApiCallArguments + 1; Address function_address = v8::ToCData<Address>(api_call_info->callback()); - bool returns_handle = - !CallbackTable::ReturnsVoid(masm->isolate(), function_address); ApiFunction fun(function_address); - ExternalReference::Type type = - returns_handle ? - ExternalReference::DIRECT_API_CALL : - ExternalReference::DIRECT_API_CALL_NEW; + ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); - Address thunk_address = returns_handle - ? FUNCTION_ADDR(&InvokeInvocationCallback) - : FUNCTION_ADDR(&InvokeFunctionCallback); - ExternalReference::Type thunk_type = - returns_handle ? - ExternalReference::PROFILING_API_CALL : - ExternalReference::PROFILING_API_CALL_NEW; + Address thunk_address = FUNCTION_ADDR(&InvokeFunctionCallback); + ExternalReference::Type thunk_type = ExternalReference::PROFILING_API_CALL; ApiFunction thunk_fun(thunk_address); ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type, masm->isolate()); @@ -930,11 +921,39 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, thunk_ref, r1, kStackUnwindSpace, - returns_handle, kFastApiCallArguments + 1); } +// Generate call to api function. +static void GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + Register receiver, + Register scratch, + int argc, + Register* values) { + ASSERT(optimization.is_simple_api_call()); + ASSERT(!receiver.is(scratch)); + + const int stack_space = kFastApiCallArguments + argc + 1; + // Assign stack space for the call arguments. + __ sub(sp, sp, Operand(stack_space * kPointerSize)); + // Write holder to stack frame. + __ str(receiver, MemOperand(sp, 0)); + // Write receiver to stack frame. + int index = stack_space - 1; + __ str(receiver, MemOperand(sp, index * kPointerSize)); + // Write the arguments to stack frame. + for (int i = 0; i < argc; i++) { + ASSERT(!receiver.is(values[i])); + ASSERT(!scratch.is(values[i])); + __ str(receiver, MemOperand(sp, index-- * kPointerSize)); + } + + GenerateFastApiDirectCall(masm, optimization, argc); +} + + class CallInterceptorCompiler BASE_EMBEDDED { public: CallInterceptorCompiler(StubCompiler* stub_compiler, @@ -1092,7 +1111,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { __ CallExternalReference( ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall), masm->isolate()), - 6); + StubCache::kInterceptorArgsLength); // Restore the name_ register. __ pop(name_); // Leave the internal frame. @@ -1150,21 +1169,6 @@ static void GenerateCheckPropertyCells(MacroAssembler* masm, } -// Convert and store int passed in register ival to IEEE 754 single precision -// floating point value at memory location (dst + 4 * wordoffset) -// If VFP3 is available use it for conversion. -static void StoreIntAsFloat(MacroAssembler* masm, - Register dst, - Register wordoffset, - Register ival, - Register scratch1) { - __ vmov(s0, ival); - __ add(scratch1, dst, Operand(wordoffset, LSL, 2)); - __ vcvt_f32_s32(s0, s0); - __ vstr(s0, scratch1, 0); -} - - void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { __ Jump(code, RelocInfo::CODE_TARGET); } @@ -1318,7 +1322,7 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend( Handle<JSObject> holder, Handle<Name> name, Label* success, - Handle<ExecutableAccessorInfo> callback) { + Handle<Object> callback) { Label miss; Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); @@ -1406,10 +1410,26 @@ void BaseLoadStubCompiler::GenerateLoadConstant(Handle<Object> value) { void BaseLoadStubCompiler::GenerateLoadCallback( + const CallOptimization& call_optimization) { + GenerateFastApiCall( + masm(), call_optimization, receiver(), scratch3(), 0, NULL); +} + + +void BaseLoadStubCompiler::GenerateLoadCallback( Register reg, Handle<ExecutableAccessorInfo> callback) { // Build AccessorInfo::args_ list on the stack and push property name below // the exit frame to make GC aware of them and store pointers to them. + STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 0); + STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == -1); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == -2); + STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == -3); + STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == -4); + STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == -5); + ASSERT(!scratch2().is(reg)); + ASSERT(!scratch3().is(reg)); + ASSERT(!scratch4().is(reg)); __ push(receiver()); __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_ if (heap()->InNewSpace(callback->data())) { @@ -1419,13 +1439,13 @@ void BaseLoadStubCompiler::GenerateLoadCallback( } else { __ Move(scratch3(), Handle<Object>(callback->data(), isolate())); } - __ Push(reg, scratch3()); + __ push(scratch3()); __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); __ mov(scratch4(), scratch3()); __ Push(scratch3(), scratch4()); __ mov(scratch4(), Operand(ExternalReference::isolate_address(isolate()))); - __ Push(scratch4(), name()); + __ Push(scratch4(), reg, name()); __ mov(r0, sp); // r0 = Handle<Name> const int kApiStackSpace = 1; @@ -1439,23 +1459,14 @@ void BaseLoadStubCompiler::GenerateLoadCallback( const int kStackUnwindSpace = kFastApiCallArguments + 1; Address getter_address = v8::ToCData<Address>(callback->getter()); - bool returns_handle = - !CallbackTable::ReturnsVoid(isolate(), getter_address); ApiFunction fun(getter_address); - ExternalReference::Type type = - returns_handle ? - ExternalReference::DIRECT_GETTER_CALL : - ExternalReference::DIRECT_GETTER_CALL_NEW; + ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; ExternalReference ref = ExternalReference(&fun, type, isolate()); - Address thunk_address = returns_handle - ? FUNCTION_ADDR(&InvokeAccessorGetter) - : FUNCTION_ADDR(&InvokeAccessorGetterCallback); + Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); ExternalReference::Type thunk_type = - returns_handle ? - ExternalReference::PROFILING_GETTER_CALL : - ExternalReference::PROFILING_GETTER_CALL_NEW; + ExternalReference::PROFILING_GETTER_CALL; ApiFunction thunk_fun(thunk_address); ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type, isolate()); @@ -1464,8 +1475,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback( thunk_ref, r2, kStackUnwindSpace, - returns_handle, - 5); + 6); } @@ -1553,7 +1563,7 @@ void BaseLoadStubCompiler::GenerateLoadInterceptor( ExternalReference ref = ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); - __ TailCallExternalReference(ref, 6, 1); + __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); } } @@ -2811,6 +2821,24 @@ Handle<Code> StoreStubCompiler::CompileStoreCallback( } +Handle<Code> StoreStubCompiler::CompileStoreCallback( + Handle<JSObject> object, + Handle<JSObject> holder, + Handle<Name> name, + const CallOptimization& call_optimization) { + Label success; + HandlerFrontend(object, receiver(), holder, name, &success); + __ bind(&success); + + Register values[] = { value() }; + GenerateFastApiCall( + masm(), call_optimization, receiver(), scratch3(), 1, values); + + // Return the generated code. + return GetCode(kind(), Code::CALLBACKS, name); +} + + #undef __ #define __ ACCESS_MASM(masm) @@ -2894,47 +2922,6 @@ Handle<Code> StoreStubCompiler::CompileStoreInterceptor( } -Handle<Code> StoreStubCompiler::CompileStoreGlobal( - Handle<GlobalObject> object, - Handle<PropertyCell> cell, - Handle<Name> name) { - Label miss; - - // Check that the map of the global has not changed. - __ ldr(scratch1(), FieldMemOperand(receiver(), HeapObject::kMapOffset)); - __ cmp(scratch1(), Operand(Handle<Map>(object->map()))); - __ b(ne, &miss); - - // Check that the value in the cell is not the hole. If it is, this - // cell could have been deleted and reintroducing the global needs - // to update the property details in the property dictionary of the - // global object. We bail out to the runtime system to do that. - __ mov(scratch1(), Operand(cell)); - __ LoadRoot(scratch2(), Heap::kTheHoleValueRootIndex); - __ ldr(scratch3(), FieldMemOperand(scratch1(), Cell::kValueOffset)); - __ cmp(scratch3(), scratch2()); - __ b(eq, &miss); - - // Store the value in the cell. - __ str(value(), FieldMemOperand(scratch1(), Cell::kValueOffset)); - // Cells are always rescanned, so no write barrier here. - - Counters* counters = isolate()->counters(); - __ IncrementCounter( - counters->named_store_global_inline(), 1, scratch1(), scratch2()); - __ Ret(); - - // Handle store cache miss. - __ bind(&miss); - __ IncrementCounter( - counters->named_store_global_inline_miss(), 1, scratch1(), scratch2()); - TailCallBuiltin(masm(), MissBuiltin(kind())); - - // Return the generated code. - return GetICCode(kind(), Code::NORMAL, name); -} - - Handle<Code> LoadStubCompiler::CompileLoadNonexistent( Handle<JSObject> object, Handle<JSObject> last, @@ -3190,509 +3177,6 @@ void KeyedLoadStubCompiler::GenerateLoadDictionaryElement( } -static void GenerateSmiKeyCheck(MacroAssembler* masm, - Register key, - Register scratch0, - DwVfpRegister double_scratch0, - LowDwVfpRegister double_scratch1, - Label* fail) { - Label key_ok; - // Check for smi or a smi inside a heap number. We convert the heap - // number and check if the conversion is exact and fits into the smi - // range. - __ JumpIfSmi(key, &key_ok); - __ CheckMap(key, - scratch0, - Heap::kHeapNumberMapRootIndex, - fail, - DONT_DO_SMI_CHECK); - __ sub(ip, key, Operand(kHeapObjectTag)); - __ vldr(double_scratch0, ip, HeapNumber::kValueOffset); - __ TryDoubleToInt32Exact(scratch0, double_scratch0, double_scratch1); - __ b(ne, fail); - __ TrySmiTag(key, scratch0, fail); - __ bind(&key_ok); -} - - -void KeyedStoreStubCompiler::GenerateStoreExternalArray( - MacroAssembler* masm, - ElementsKind elements_kind) { - // ---------- S t a t e -------------- - // -- r0 : value - // -- r1 : key - // -- r2 : receiver - // -- lr : return address - // ----------------------------------- - Label slow, check_heap_number, miss_force_generic; - - // Register usage. - Register value = r0; - Register key = r1; - Register receiver = r2; - // r3 mostly holds the elements array or the destination external array. - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - - // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key, r4, d1, d2, &miss_force_generic); - - __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset)); - - // Check that the index is in range - __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset)); - __ cmp(key, ip); - // Unsigned comparison catches both negative and too-large values. - __ b(hs, &miss_force_generic); - - // Handle both smis and HeapNumbers in the fast path. Go to the - // runtime for all other kinds of values. - // r3: external array. - if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { - // Double to pixel conversion is only implemented in the runtime for now. - __ UntagAndJumpIfNotSmi(r5, value, &slow); - } else { - __ UntagAndJumpIfNotSmi(r5, value, &check_heap_number); - } - __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); - - // r3: base pointer of external storage. - // r5: value (integer). - switch (elements_kind) { - case EXTERNAL_PIXEL_ELEMENTS: - // Clamp the value to [0..255]. - __ Usat(r5, 8, Operand(r5)); - __ strb(r5, MemOperand(r3, key, LSR, 1)); - break; - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ strb(r5, MemOperand(r3, key, LSR, 1)); - break; - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ strh(r5, MemOperand(r3, key, LSL, 0)); - break; - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ str(r5, MemOperand(r3, key, LSL, 1)); - break; - case EXTERNAL_FLOAT_ELEMENTS: - // Perform int-to-float conversion and store to memory. - __ SmiUntag(r4, key); - StoreIntAsFloat(masm, r3, r4, r5, r7); - break; - case EXTERNAL_DOUBLE_ELEMENTS: - __ vmov(s2, r5); - __ vcvt_f64_s32(d0, s2); - __ add(r3, r3, Operand(key, LSL, 2)); - // r3: effective address of the double element - __ vstr(d0, r3, 0); - break; - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - - // Entry registers are intact, r0 holds the value which is the return value. - __ Ret(); - - if (elements_kind != EXTERNAL_PIXEL_ELEMENTS) { - // r3: external array. - __ bind(&check_heap_number); - __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE); - __ b(ne, &slow); - - __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset)); - - // r3: base pointer of external storage. - - // The WebGL specification leaves the behavior of storing NaN and - // +/-Infinity into integer arrays basically undefined. For more - // reproducible behavior, convert these to zero. - - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { - // vldr requires offset to be a multiple of 4 so we can not - // include -kHeapObjectTag into it. - __ sub(r5, r0, Operand(kHeapObjectTag)); - __ vldr(d0, r5, HeapNumber::kValueOffset); - __ add(r5, r3, Operand(key, LSL, 1)); - __ vcvt_f32_f64(s0, d0); - __ vstr(s0, r5, 0); - } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - __ sub(r5, r0, Operand(kHeapObjectTag)); - __ vldr(d0, r5, HeapNumber::kValueOffset); - __ add(r5, r3, Operand(key, LSL, 2)); - __ vstr(d0, r5, 0); - } else { - // Hoisted load. vldr requires offset to be a multiple of 4 so we can - // not include -kHeapObjectTag into it. - __ sub(r5, value, Operand(kHeapObjectTag)); - __ vldr(d0, r5, HeapNumber::kValueOffset); - __ ECMAToInt32(r5, d0, r6, r7, r9, d1); - - switch (elements_kind) { - case EXTERNAL_BYTE_ELEMENTS: - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: - __ strb(r5, MemOperand(r3, key, LSR, 1)); - break; - case EXTERNAL_SHORT_ELEMENTS: - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: - __ strh(r5, MemOperand(r3, key, LSL, 0)); - break; - case EXTERNAL_INT_ELEMENTS: - case EXTERNAL_UNSIGNED_INT_ELEMENTS: - __ str(r5, MemOperand(r3, key, LSL, 1)); - break; - case EXTERNAL_PIXEL_ELEMENTS: - case EXTERNAL_FLOAT_ELEMENTS: - case EXTERNAL_DOUBLE_ELEMENTS: - case FAST_ELEMENTS: - case FAST_SMI_ELEMENTS: - case FAST_DOUBLE_ELEMENTS: - case FAST_HOLEY_ELEMENTS: - case FAST_HOLEY_SMI_ELEMENTS: - case FAST_HOLEY_DOUBLE_ELEMENTS: - case DICTIONARY_ELEMENTS: - case NON_STRICT_ARGUMENTS_ELEMENTS: - UNREACHABLE(); - break; - } - } - - // Entry registers are intact, r0 holds the value which is the return - // value. - __ Ret(); - } - - // Slow case, key and receiver still in r0 and r1. - __ bind(&slow); - __ IncrementCounter( - masm->isolate()->counters()->keyed_load_external_array_slow(), - 1, r2, r3); - - // ---------- S t a t e -------------- - // -- lr : return address - // -- r0 : key - // -- r1 : receiver - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); - - // Miss case, call the runtime. - __ bind(&miss_force_generic); - - // ---------- S t a t e -------------- - // -- lr : return address - // -- r0 : key - // -- r1 : receiver - // ----------------------------------- - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); -} - - -void KeyedStoreStubCompiler::GenerateStoreFastElement( - MacroAssembler* masm, - bool is_js_array, - ElementsKind elements_kind, - KeyedAccessStoreMode store_mode) { - // ----------- S t a t e ------------- - // -- r0 : value - // -- r1 : key - // -- r2 : receiver - // -- lr : return address - // -- r3 : scratch - // -- r4 : scratch (elements) - // ----------------------------------- - Label miss_force_generic, transition_elements_kind, grow, slow; - Label finish_store, check_capacity; - - Register value_reg = r0; - Register key_reg = r1; - Register receiver_reg = r2; - Register scratch = r4; - Register elements_reg = r3; - Register length_reg = r5; - Register scratch2 = r6; - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - - // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key_reg, r4, d1, d2, &miss_force_generic); - - if (IsFastSmiElementsKind(elements_kind)) { - __ JumpIfNotSmi(value_reg, &transition_elements_kind); - } - - // Check that the key is within bounds. - __ ldr(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - if (is_js_array) { - __ ldr(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - } else { - __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); - } - // Compare smis. - __ cmp(key_reg, scratch); - if (is_js_array && IsGrowStoreMode(store_mode)) { - __ b(hs, &grow); - } else { - __ b(hs, &miss_force_generic); - } - - // Make sure elements is a fast element array, not 'cow'. - __ CheckMap(elements_reg, - scratch, - Heap::kFixedArrayMapRootIndex, - &miss_force_generic, - DONT_DO_SMI_CHECK); - - __ bind(&finish_store); - if (IsFastSmiElementsKind(elements_kind)) { - __ add(scratch, - elements_reg, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(scratch, scratch, Operand::PointerOffsetFromSmiKey(key_reg)); - __ str(value_reg, MemOperand(scratch)); - } else { - ASSERT(IsFastObjectElementsKind(elements_kind)); - __ add(scratch, - elements_reg, - Operand(FixedArray::kHeaderSize - kHeapObjectTag)); - __ add(scratch, scratch, Operand::PointerOffsetFromSmiKey(key_reg)); - __ str(value_reg, MemOperand(scratch)); - __ mov(receiver_reg, value_reg); - __ RecordWrite(elements_reg, // Object. - scratch, // Address. - receiver_reg, // Value. - kLRHasNotBeenSaved, - kDontSaveFPRegs); - } - // value_reg (r0) is preserved. - // Done. - __ Ret(); - - __ bind(&miss_force_generic); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); - - __ bind(&transition_elements_kind); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); - - if (is_js_array && IsGrowStoreMode(store_mode)) { - // Grow the array by a single element if possible. - __ bind(&grow); - - // Make sure the array is only growing by a single element, anything else - // must be handled by the runtime. Flags already set by previous compare. - __ b(ne, &miss_force_generic); - - // Check for the empty array, and preallocate a small backing store if - // possible. - __ ldr(length_reg, - FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ ldr(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex); - __ b(ne, &check_capacity); - - int size = FixedArray::SizeFor(JSArray::kPreallocatedArrayElements); - __ Allocate(size, elements_reg, scratch, scratch2, &slow, TAG_OBJECT); - - __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); - __ str(scratch, FieldMemOperand(elements_reg, JSObject::kMapOffset)); - __ mov(scratch, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); - __ str(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); - __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); - for (int i = 1; i < JSArray::kPreallocatedArrayElements; ++i) { - __ str(scratch, FieldMemOperand(elements_reg, FixedArray::SizeFor(i))); - } - - // Store the element at index zero. - __ str(value_reg, FieldMemOperand(elements_reg, FixedArray::SizeFor(0))); - - // Install the new backing store in the JSArray. - __ str(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, - scratch, kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - - // Increment the length of the array. - __ mov(length_reg, Operand(Smi::FromInt(1))); - __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ Ret(); - - __ bind(&check_capacity); - // Check for cow elements, in general they are not handled by this stub - __ CheckMap(elements_reg, - scratch, - Heap::kFixedCOWArrayMapRootIndex, - &miss_force_generic, - DONT_DO_SMI_CHECK); - - __ ldr(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); - __ cmp(length_reg, scratch); - __ b(hs, &slow); - - // Grow the array and finish the store. - __ add(length_reg, length_reg, Operand(Smi::FromInt(1))); - __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ jmp(&finish_store); - - __ bind(&slow); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); - } -} - - -void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement( - MacroAssembler* masm, - bool is_js_array, - KeyedAccessStoreMode store_mode) { - // ----------- S t a t e ------------- - // -- r0 : value - // -- r1 : key - // -- r2 : receiver - // -- lr : return address - // -- r3 : scratch (elements backing store) - // -- r4 : scratch - // -- r5 : scratch - // ----------------------------------- - Label miss_force_generic, transition_elements_kind, grow, slow; - Label finish_store, check_capacity; - - Register value_reg = r0; - Register key_reg = r1; - Register receiver_reg = r2; - Register elements_reg = r3; - Register scratch1 = r4; - Register scratch2 = r5; - Register length_reg = r7; - - // This stub is meant to be tail-jumped to, the receiver must already - // have been verified by the caller to not be a smi. - - // Check that the key is a smi or a heap number convertible to a smi. - GenerateSmiKeyCheck(masm, key_reg, r4, d1, d2, &miss_force_generic); - - __ ldr(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - - // Check that the key is within bounds. - if (is_js_array) { - __ ldr(scratch1, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - } else { - __ ldr(scratch1, - FieldMemOperand(elements_reg, FixedArray::kLengthOffset)); - } - // Compare smis, unsigned compare catches both negative and out-of-bound - // indexes. - __ cmp(key_reg, scratch1); - if (IsGrowStoreMode(store_mode)) { - __ b(hs, &grow); - } else { - __ b(hs, &miss_force_generic); - } - - __ bind(&finish_store); - __ StoreNumberToDoubleElements(value_reg, key_reg, elements_reg, - scratch1, d0, &transition_elements_kind); - __ Ret(); - - // Handle store cache miss, replacing the ic with the generic stub. - __ bind(&miss_force_generic); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_MissForceGeneric); - - __ bind(&transition_elements_kind); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Miss); - - if (is_js_array && IsGrowStoreMode(store_mode)) { - // Grow the array by a single element if possible. - __ bind(&grow); - - // Make sure the array is only growing by a single element, anything else - // must be handled by the runtime. Flags already set by previous compare. - __ b(ne, &miss_force_generic); - - // Transition on values that can't be stored in a FixedDoubleArray. - Label value_is_smi; - __ JumpIfSmi(value_reg, &value_is_smi); - __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset)); - __ CompareRoot(scratch1, Heap::kHeapNumberMapRootIndex); - __ b(ne, &transition_elements_kind); - __ bind(&value_is_smi); - - // Check for the empty array, and preallocate a small backing store if - // possible. - __ ldr(length_reg, - FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ ldr(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ CompareRoot(elements_reg, Heap::kEmptyFixedArrayRootIndex); - __ b(ne, &check_capacity); - - int size = FixedDoubleArray::SizeFor(JSArray::kPreallocatedArrayElements); - __ Allocate(size, elements_reg, scratch1, scratch2, &slow, TAG_OBJECT); - - // Initialize the new FixedDoubleArray. - __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex); - __ str(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset)); - __ mov(scratch1, - Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements))); - __ str(scratch1, - FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); - - __ mov(scratch1, elements_reg); - __ StoreNumberToDoubleElements(value_reg, key_reg, scratch1, - scratch2, d0, &transition_elements_kind); - - __ mov(scratch1, Operand(kHoleNanLower32)); - __ mov(scratch2, Operand(kHoleNanUpper32)); - for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) { - int offset = FixedDoubleArray::OffsetOfElementAt(i); - __ str(scratch1, FieldMemOperand(elements_reg, offset)); - __ str(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize)); - } - - // Install the new backing store in the JSArray. - __ str(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ RecordWriteField(receiver_reg, JSObject::kElementsOffset, elements_reg, - scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs, - EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); - - // Increment the length of the array. - __ mov(length_reg, Operand(Smi::FromInt(1))); - __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ ldr(elements_reg, - FieldMemOperand(receiver_reg, JSObject::kElementsOffset)); - __ Ret(); - - __ bind(&check_capacity); - // Make sure that the backing store can hold additional elements. - __ ldr(scratch1, - FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset)); - __ cmp(length_reg, scratch1); - __ b(hs, &slow); - - // Grow the array and finish the store. - __ add(length_reg, length_reg, Operand(Smi::FromInt(1))); - __ str(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset)); - __ jmp(&finish_store); - - __ bind(&slow); - TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); - } -} - - #undef __ } } // namespace v8::internal |