From 9891a057e152d903514d7caeb0f718db422dc7a6 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Tue, 24 May 2011 07:23:32 +0000 Subject: [PATCH] MIPS: Update for 23-May commits, and a few older ones. Make mips-specifc changes for r7999, r8001, r8002. Also bring in changes for older commits 7203, 7279, 7693, 7715, 7788. Mips changes for 7715 (Arm: Support hardfloat in SCons build), and 7693 (Implement hardfloat calling convention in macro assembler and simulator) resulted in changes to SConstruct. BUG= TEST= Review URL: http://codereview.chromium.org//6966031 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8022 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- SConstruct | 37 ++++-- src/mips/code-stubs-mips.cc | 179 +++++++++++++++----------- src/mips/codegen-mips.h | 12 -- src/mips/constants-mips.h | 13 ++ src/mips/debug-mips.cc | 2 +- src/mips/frames-mips.h | 37 ++++++ src/mips/full-codegen-mips.cc | 14 +-- src/mips/macro-assembler-mips.cc | 166 +++++++++++++++++++++--- src/mips/macro-assembler-mips.h | 79 +++++++----- src/mips/simulator-mips.cc | 208 ++++++++++++++++++++++++++----- src/mips/simulator-mips.h | 9 +- src/mips/stub-cache-mips.cc | 19 ++- 12 files changed, 592 insertions(+), 183 deletions(-) diff --git a/SConstruct b/SConstruct index 0d01e7e52..4a7e18257 100644 --- a/SConstruct +++ b/SConstruct @@ -210,6 +210,9 @@ LIBRARY_FLAGS = { 'LINKFLAGS': ['-m32'], 'mipsabi:softfloat': { 'CPPDEFINES': ['__mips_soft_float=1'], + }, + 'mipsabi:hardfloat': { + 'CPPDEFINES': ['__mips_hard_float=1'], } }, 'arch:x64': { @@ -511,10 +514,29 @@ SAMPLE_FLAGS = { }, 'arch:mips': { 'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'], + 'mips_arch_variant:mips32r2': { + 'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2'] + }, 'simulator:none': { - 'CCFLAGS': ['-EL', '-mips32r2', '-Wa,-mips32r2', '-fno-inline'], + 'CCFLAGS': ['-EL'], 'LINKFLAGS': ['-EL'], - 'LDFLAGS': ['-EL'] + 'mips_arch_variant:mips32r2': { + 'CCFLAGS': ['-mips32r2', '-Wa,-mips32r2'] + }, + 'mips_arch_variant:mips32r1': { + 'CCFLAGS': ['-mips32', '-Wa,-mips32'] + }, + 'library:static': { + 'LINKFLAGS': ['-static', '-static-libgcc'] + }, + 'mipsabi:softfloat': { + 'CCFLAGS': ['-msoft-float'], + 'LINKFLAGS': ['-msoft-float'] + }, + 'mipsabi:hardfloat': { + 'CCFLAGS': ['-mhard-float'], + 'LINKFLAGS': ['-mhard-float'] + } } }, 'simulator:arm': { @@ -678,6 +700,9 @@ PREPARSER_FLAGS = { 'LINKFLAGS': ['-m32'], 'mipsabi:softfloat': { 'CPPDEFINES': ['__mips_soft_float=1'], + }, + 'mipsabi:hardfloat': { + 'CPPDEFINES': ['__mips_hard_float=1'], } }, 'mode:release': { @@ -1238,12 +1263,8 @@ def PostprocessOptions(options, os): if 'msvcltcg' in ARGUMENTS: print "Warning: forcing msvcltcg on as it is required for pgo (%s)" % options['pgo'] options['msvcltcg'] = 'on' - if (options['simulator'] == 'mips' and options['mipsabi'] != 'softfloat'): - # Print a warning if soft-float ABI is not selected for mips simulator - print "Warning: forcing soft-float mips ABI when running on simulator" - options['mipsabi'] = 'softfloat' - if (options['mipsabi'] != 'none') and (options['arch'] != 'mips') and (options['simulator'] != 'mips'): - options['mipsabi'] = 'none' + if (options['mipsabi'] != 'none') and (options['arch'] != 'mips') and (options['simulator'] != 'mips'): + options['mipsabi'] = 'none' if options['liveobjectlist'] == 'on': if (options['debuggersupport'] != 'on') or (options['mode'] == 'release'): # Print a warning that liveobjectlist will implicitly enable the debugger diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index bb009218d..4b5e0e6c4 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -388,11 +388,8 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm, __ mtc1(scratch1, f12); __ cvt_d_w(f12, f12); if (destination == kCoreRegisters) { - __ mfc1(a2, f14); - __ mfc1(a3, f15); - - __ mfc1(a0, f12); - __ mfc1(a1, f13); + __ Move(a2, a3, f14); + __ Move(a0, a1, f12); } } else { ASSERT(destination == kCoreRegisters); @@ -478,8 +475,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, __ cvt_d_w(dst, dst); if (destination == kCoreRegisters) { // Load the converted smi to dst1 and dst2 in double format. - __ mfc1(dst1, dst); - __ mfc1(dst2, FPURegister::from_code(dst.code() + 1)); + __ Move(dst1, dst2, dst); } } else { ASSERT(destination == kCoreRegisters); @@ -550,6 +546,8 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, Register scratch2, FPURegister single_scratch) { ASSERT(!int_scratch.is(scratch2)); + ASSERT(!int_scratch.is(dst1)); + ASSERT(!int_scratch.is(dst2)); Label done; @@ -558,8 +556,7 @@ void FloatingPointHelper::ConvertIntToDouble(MacroAssembler* masm, __ mtc1(int_scratch, single_scratch); __ cvt_d_w(double_dst, single_scratch); if (destination == kCoreRegisters) { - __ mfc1(dst1, double_dst); - __ mfc1(dst2, FPURegister::from_code(double_dst.code() + 1)); + __ Move(dst1, dst2, double_dst); } } else { Label fewer_than_20_useful_bits; @@ -683,8 +680,7 @@ void FloatingPointHelper::LoadNumberAsInt32Double(MacroAssembler* masm, __ Branch(not_int32, ne, scratch2, Operand(zero_reg)); if (destination == kCoreRegisters) { - __ mfc1(dst1, double_dst); - __ mfc1(dst2, FPURegister::from_code(double_dst.code() + 1)); + __ Move(dst1, dst2, double_dst); } } else { @@ -891,10 +887,8 @@ void FloatingPointHelper::CallCCodeForDoubleOperation( // calling is compiled with hard-float flag and expecting hard float ABI // (parameters in f12/f14 registers). We need to copy parameters from // a0-a3 registers to f12/f14 register pairs. - __ mtc1(a0, f12); - __ mtc1(a1, f13); - __ mtc1(a2, f14); - __ mtc1(a3, f15); + __ Move(f12, a0, a1); + __ Move(f14, a2, a3); } // Call C routine that may not cause GC or other trouble. __ CallCFunction(ExternalReference::double_fp_operation(op, masm->isolate()), @@ -1171,10 +1165,8 @@ void EmitNanCheck(MacroAssembler* masm, Condition cc) { if (CpuFeatures::IsSupported(FPU)) { CpuFeatures::Scope scope(FPU); // Lhs and rhs are already loaded to f12 and f14 register pairs. - __ mfc1(t0, f14); // f14 has LS 32 bits of rhs. - __ mfc1(t1, f15); // f15 has MS 32 bits of rhs. - __ mfc1(t2, f12); // f12 has LS 32 bits of lhs. - __ mfc1(t3, f13); // f13 has MS 32 bits of lhs. + __ Move(t0, t1, f14); + __ Move(t2, t3, f12); } else { // Lhs and rhs are already loaded to GP registers. __ mov(t0, a0); // a0 has LS 32 bits of rhs. @@ -1237,12 +1229,10 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { // Exception: 0 and -0. bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); if (CpuFeatures::IsSupported(FPU)) { - CpuFeatures::Scope scope(FPU); + CpuFeatures::Scope scope(FPU); // Lhs and rhs are already loaded to f12 and f14 register pairs. - __ mfc1(t0, f14); // f14 has LS 32 bits of rhs. - __ mfc1(t1, f15); // f15 has MS 32 bits of rhs. - __ mfc1(t2, f12); // f12 has LS 32 bits of lhs. - __ mfc1(t3, f13); // f13 has MS 32 bits of lhs. + __ Move(t0, t1, f14); + __ Move(t2, t3, f12); } else { // Lhs and rhs are already loaded to GP registers. __ mov(t0, a0); // a0 has LS 32 bits of rhs. @@ -1284,10 +1274,8 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { // calling is compiled with hard-float flag and expecting hard float ABI // (parameters in f12/f14 registers). We need to copy parameters from // a0-a3 registers to f12/f14 register pairs. - __ mtc1(a0, f12); - __ mtc1(a1, f13); - __ mtc1(a2, f14); - __ mtc1(a3, f15); + __ Move(f12, a0, a1); + __ Move(f14, a2, a3); } __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()), 4); __ pop(ra); // Because this function returns int, result is in v0. @@ -3192,8 +3180,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { __ sra(t0, a0, kSmiTagSize); __ mtc1(t0, f4); __ cvt_d_w(f4, f4); - __ mfc1(a2, f4); - __ mfc1(a3, f5); + __ Move(a2, a3, f4); __ Branch(&loaded); __ bind(&input_not_smi); @@ -3209,8 +3196,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) { __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4)); } else { // Input is untagged double in f4. Output goes to f4. - __ mfc1(a2, f4); - __ mfc1(a3, f5); + __ Move(a2, a3, f4); } __ bind(&loaded); // a2 = low 32 bits of double value. @@ -3354,8 +3340,11 @@ void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, Register scratch) { __ push(ra); __ PrepareCallCFunction(2, scratch); - __ mfc1(v0, f4); - __ mfc1(v1, f5); + if (IsMipsSoftFloatABI) { + __ Move(v0, v1, f4); + } else { + __ mov_d(f12, f4); + } switch (type_) { case TranscendentalCache::SIN: __ CallCFunction( @@ -3451,16 +3440,9 @@ void MathPowStub::Generate(MacroAssembler* masm) { &call_runtime); __ push(ra); __ PrepareCallCFunction(3, scratch); - // ABI (o32) for func(double d, int x): d in f12, x in a2. - ASSERT(double_base.is(f12)); - ASSERT(exponent.is(a2)); - if (IsMipsSoftFloatABI) { - // Simulator case, supports FPU, but with soft-float passing. - __ mfc1(a0, double_base); - __ mfc1(a1, FPURegister::from_code(double_base.code() + 1)); - } + __ SetCallCDoubleArguments(double_base, double_exponent); __ CallCFunction( - ExternalReference::power_double_int_function(masm->isolate()), 3); + ExternalReference::power_double_int_function(masm->isolate()), 4); __ pop(ra); __ GetCFunctionDoubleResult(double_result); __ sdc1(double_result, @@ -3489,12 +3471,7 @@ void MathPowStub::Generate(MacroAssembler* masm) { // ABI (o32) for func(double a, double b): a in f12, b in f14. ASSERT(double_base.is(f12)); ASSERT(double_exponent.is(f14)); - if (IsMipsSoftFloatABI) { - __ mfc1(a0, double_base); - __ mfc1(a1, FPURegister::from_code(double_base.code() + 1)); - __ mfc1(a2, double_exponent); - __ mfc1(a3, FPURegister::from_code(double_exponent.code() + 1)); - } + __ SetCallCDoubleArguments(double_base, double_exponent); __ CallCFunction( ExternalReference::power_double_double_function(masm->isolate()), 4); __ pop(ra); @@ -3892,18 +3869,31 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { } -// Uses registers a0 to t0. Expected input is -// object in a0 (or at sp+1*kPointerSize) and function in -// a1 (or at sp), depending on whether or not -// args_in_registers() is true. +// Uses registers a0 to t0. +// Expected input (depending on whether args are in registers or on the stack): +// * object: a0 or at sp + 1 * kPointerSize. +// * function: a1 or at sp. +// +// Inlined call site patching is a crankshaft-specific feature that is not +// implemented on MIPS. void InstanceofStub::Generate(MacroAssembler* masm) { + // This is a crankshaft-specific feature that has not been implemented yet. + ASSERT(!HasCallSiteInlineCheck()); + // Call site inlining and patching implies arguments in registers. + ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); + // ReturnTrueFalse is only implemented for inlined call sites. + ASSERT(!ReturnTrueFalseObject() || HasCallSiteInlineCheck()); + // Fixed register usage throughout the stub: const Register object = a0; // Object (lhs). - const Register map = a3; // Map of the object. + Register map = a3; // Map of the object. const Register function = a1; // Function (rhs). const Register prototype = t0; // Prototype of the function. + const Register inline_site = t5; const Register scratch = a2; + Label slow, loop, is_instance, is_not_instance, not_js_object; + if (!HasArgsInRegisters()) { __ lw(object, MemOperand(sp, 1 * kPointerSize)); __ lw(function, MemOperand(sp, 0)); @@ -3913,47 +3903,70 @@ void InstanceofStub::Generate(MacroAssembler* masm) { __ JumpIfSmi(object, ¬_js_object); __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); - // Look up the function and the map in the instanceof cache. - Label miss; - __ LoadRoot(t1, Heap::kInstanceofCacheFunctionRootIndex); - __ Branch(&miss, ne, function, Operand(t1)); - __ LoadRoot(t1, Heap::kInstanceofCacheMapRootIndex); - __ Branch(&miss, ne, map, Operand(t1)); - __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); - __ DropAndRet(HasArgsInRegisters() ? 0 : 2); + // If there is a call site cache don't look in the global cache, but do the + // real lookup and update the call site cache. + if (!HasCallSiteInlineCheck()) { + Label miss; + __ LoadRoot(t1, Heap::kInstanceofCacheFunctionRootIndex); + __ Branch(&miss, ne, function, Operand(t1)); + __ LoadRoot(t1, Heap::kInstanceofCacheMapRootIndex); + __ Branch(&miss, ne, map, Operand(t1)); + __ LoadRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); + __ DropAndRet(HasArgsInRegisters() ? 0 : 2); + + __ bind(&miss); + } - __ bind(&miss); + // Get the prototype of the function. __ TryGetFunctionPrototype(function, prototype, scratch, &slow); // Check that the function prototype is a JS object. __ JumpIfSmi(prototype, &slow); __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); - __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); - __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); + // Update the global instanceof or call site inlined cache with the current + // map and function. The cached answer will be set when it is known below. + if (!HasCallSiteInlineCheck()) { + __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); + __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); + } else { + UNIMPLEMENTED_MIPS(); + } // Register mapping: a3 is object map and t0 is function prototype. // Get prototype of object into a2. __ lw(scratch, FieldMemOperand(map, Map::kPrototypeOffset)); + // We don't need map any more. Use it as a scratch register. + Register scratch2 = map; + map = no_reg; + // Loop through the prototype chain looking for the function prototype. + __ LoadRoot(scratch2, Heap::kNullValueRootIndex); __ bind(&loop); __ Branch(&is_instance, eq, scratch, Operand(prototype)); - __ LoadRoot(t1, Heap::kNullValueRootIndex); - __ Branch(&is_not_instance, eq, scratch, Operand(t1)); + __ Branch(&is_not_instance, eq, scratch, Operand(scratch2)); __ lw(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset)); __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); __ Branch(&loop); __ bind(&is_instance); ASSERT(Smi::FromInt(0) == 0); - __ mov(v0, zero_reg); - __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); + if (!HasCallSiteInlineCheck()) { + __ mov(v0, zero_reg); + __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); + } else { + UNIMPLEMENTED_MIPS(); + } __ DropAndRet(HasArgsInRegisters() ? 0 : 2); __ bind(&is_not_instance); - __ li(v0, Operand(Smi::FromInt(1))); - __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); + if (!HasCallSiteInlineCheck()) { + __ li(v0, Operand(Smi::FromInt(1))); + __ StoreRoot(v0, Heap::kInstanceofCacheAnswerRootIndex); + } else { + UNIMPLEMENTED_MIPS(); + } __ DropAndRet(HasArgsInRegisters() ? 0 : 2); Label object_not_null, object_not_null_or_smi; @@ -3961,7 +3974,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) { // Before null, smi and string value checks, check that the rhs is a function // as for a non-function rhs an exception needs to be thrown. __ JumpIfSmi(function, &slow); - __ GetObjectType(function, map, scratch); + __ GetObjectType(function, scratch2, scratch); __ Branch(&slow, ne, scratch, Operand(JS_FUNCTION_TYPE)); // Null is not instance of anything. @@ -3984,13 +3997,31 @@ void InstanceofStub::Generate(MacroAssembler* masm) { // Slow-case. Tail call builtin. __ bind(&slow); - if (HasArgsInRegisters()) { + if (!ReturnTrueFalseObject()) { + if (HasArgsInRegisters()) { + __ Push(a0, a1); + } + __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); + } else { + __ EnterInternalFrame(); __ Push(a0, a1); + __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); + __ LeaveInternalFrame(); + __ mov(a0, v0); + __ LoadRoot(v0, Heap::kTrueValueRootIndex); + __ DropAndRet(HasArgsInRegisters() ? 0 : 2, eq, a0, Operand(zero_reg)); + __ LoadRoot(v0, Heap::kFalseValueRootIndex); + __ DropAndRet(HasArgsInRegisters() ? 0 : 2); } - __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); } +Register InstanceofStub::left() { return a0; } + + +Register InstanceofStub::right() { return a1; } + + void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // The displacement is the offset of the last parameter (if any) // relative to the frame pointer. diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h index f847b51c6..fecd321fa 100644 --- a/src/mips/codegen-mips.h +++ b/src/mips/codegen-mips.h @@ -37,18 +37,6 @@ namespace v8 { namespace internal { -#if(defined(__mips_hard_float) && __mips_hard_float != 0) -// Use floating-point coprocessor instructions. This flag is raised when -// -mhard-float is passed to the compiler. -static const bool IsMipsSoftFloatABI = false; -#elif(defined(__mips_soft_float) && __mips_soft_float != 0) -// Not using floating-point coprocessor instructions. This flag is raised when -// -msoft-float is passed to the compiler. -static const bool IsMipsSoftFloatABI = true; -#else -static const bool IsMipsSoftFloatABI = true; -#endif - // Forward declarations class CompilationInfo; diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h index eb0d22c21..256733013 100644 --- a/src/mips/constants-mips.h +++ b/src/mips/constants-mips.h @@ -47,6 +47,19 @@ #endif +#if(defined(__mips_hard_float) && __mips_hard_float != 0) +// Use floating-point coprocessor instructions. This flag is raised when +// -mhard-float is passed to the compiler. +static const bool IsMipsSoftFloatABI = false; +#elif(defined(__mips_soft_float) && __mips_soft_float != 0) +// Not using floating-point coprocessor instructions. This flag is raised when +// -msoft-float is passed to the compiler. +static const bool IsMipsSoftFloatABI = true; +#else +static const bool IsMipsSoftFloatABI = true; +#endif + + // Defines constants and accessor classes to assemble, disassemble and // simulate MIPS32 instructions. // diff --git a/src/mips/debug-mips.cc b/src/mips/debug-mips.cc index ee7a93be1..e323c505e 100644 --- a/src/mips/debug-mips.cc +++ b/src/mips/debug-mips.cc @@ -105,7 +105,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() { // call t9 (jalr t9 / nop instruction pair) CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast( - Isolate::Current()->debug()->debug_break_return()->entry()))); + Isolate::Current()->debug()->debug_break_slot()->entry()))); patcher.masm()->Call(v8::internal::t9); } diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h index fd93e8b28..2e720fb17 100644 --- a/src/mips/frames-mips.h +++ b/src/mips/frames-mips.h @@ -79,6 +79,43 @@ static const int kNumSafepointSavedRegisters = typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved]; +static const int kUndefIndex = -1; +// Map with indexes on stack that corresponds to codes of saved registers. +static const int kSafepointRegisterStackIndexMap[kNumRegs] = { + kUndefIndex, + kUndefIndex, + 0, // v0 + kUndefIndex, + 1, // a0 + 2, // a1 + 3, // a2 + 4, // a3 + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + 5, // Saved temporaries. + 6, + 7, + 8, + 9, + 10, + 11, + 12, + kUndefIndex, + kUndefIndex, + kUndefIndex, + kUndefIndex, + 13, // gp + 14, // sp + 15, // fp + kUndefIndex +}; + // ---------------------------------------------------- diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 6f0cd2a6b..225feb46a 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -930,8 +930,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // check for an enum cache. Leave the map in a2 for the subsequent // prototype load. __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset)); - __ lw(a3, FieldMemOperand(a2, Map::kInstanceDescriptorsOffset)); - __ Branch(&call_runtime, eq, a3, Operand(empty_descriptor_array_value)); + __ lw(a3, FieldMemOperand(a2, Map::kInstanceDescriptorsOrBitField3Offset)); + __ JumpIfSmi(a3, &call_runtime); // Check that there is an enum cache in the non-empty instance // descriptors (a3). This is the case if the next enumeration @@ -972,7 +972,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // We got a map in register v0. Get the enumeration cache from it. __ bind(&use_cache); - __ lw(a1, FieldMemOperand(v0, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(v0, a1); __ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumerationIndexOffset)); __ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset)); @@ -2551,7 +2551,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( // Look for valueOf symbol in the descriptor array, and indicate false if // found. The type is not checked, so if it is a transition it is a false // negative. - __ lw(t0, FieldMemOperand(a1, Map::kInstanceDescriptorsOffset)); + __ LoadInstanceDescriptors(a1, t0); __ lw(a3, FieldMemOperand(t0, FixedArray::kLengthOffset)); // t0: descriptor array // a3: length of descriptor array @@ -2866,11 +2866,9 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList* args) { // 0x41300000 is the top half of 1.0 x 2^20 as a double. __ li(a1, Operand(0x41300000)); // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU. - __ mtc1(a1, f13); - __ mtc1(v0, f12); + __ Move(f12, v0, a1); // Move 0x4130000000000000 to FPU. - __ mtc1(a1, f15); - __ mtc1(zero_reg, f14); + __ Move(f14, zero_reg, a1); // Subtract and store the result in the heap number. __ sub_d(f0, f12, f14); __ sdc1(f0, MemOperand(s0, HeapNumber::kValueOffset - kHeapObjectTag)); diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 0d1eed56c..5d216834b 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -193,6 +193,77 @@ void MacroAssembler::RecordWriteHelper(Register object, sw(scratch, MemOperand(object, Page::kDirtyFlagOffset)); } +// Push and pop all registers that can hold pointers. +void MacroAssembler::PushSafepointRegisters() { + // Safepoints expect a block of kNumSafepointRegisters values on the + // stack, so adjust the stack for unsaved registers. + const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; + ASSERT(num_unsaved >= 0); + Subu(sp, sp, Operand(num_unsaved * kPointerSize)); + MultiPush(kSafepointSavedRegisters); +} + +void MacroAssembler::PopSafepointRegisters() { + const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; + MultiPop(kSafepointSavedRegisters); + Addu(sp, sp, Operand(num_unsaved * kPointerSize)); +} + +void MacroAssembler::PushSafepointRegistersAndDoubles() { + PushSafepointRegisters(); + Subu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize)); + for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) { + FPURegister reg = FPURegister::FromAllocationIndex(i); + sdc1(reg, MemOperand(sp, i * kDoubleSize)); + } +} + +void MacroAssembler::PopSafepointRegistersAndDoubles() { + for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) { + FPURegister reg = FPURegister::FromAllocationIndex(i); + ldc1(reg, MemOperand(sp, i * kDoubleSize)); + } + Addu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize)); + PopSafepointRegisters(); +} + +void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src, + Register dst) { + sw(src, SafepointRegistersAndDoublesSlot(dst)); +} + + +void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) { + sw(src, SafepointRegisterSlot(dst)); +} + + +void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) { + lw(dst, SafepointRegisterSlot(src)); +} + + +int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { + // The registers are pushed starting with the highest encoding, + // which means that lowest encodings are closest to the stack pointer. + return kSafepointRegisterStackIndexMap[reg_code]; +} + + +MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) { + return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); +} + + +MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) { + // General purpose registers are pushed last on the stack. + int doubles_size = FPURegister::kNumAllocatableRegisters * kDoubleSize; + int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize; + return MemOperand(sp, doubles_size + register_offset); +} + + + void MacroAssembler::InNewSpace(Register object, Register scratch, @@ -1903,13 +1974,6 @@ void MacroAssembler::Call(Label* target) { } -void MacroAssembler::Move(Register dst, Register src) { - if (!dst.is(src)) { - mov(dst, src); - } -} - - #ifdef ENABLE_DEBUGGER_SUPPORT void MacroAssembler::DebugBreak() { @@ -2585,17 +2649,56 @@ void MacroAssembler::CheckMap(Register obj, void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) { + CpuFeatures::Scope scope(FPU); if (IsMipsSoftFloatABI) { - mtc1(v0, dst); - mtc1(v1, FPURegister::from_code(dst.code() + 1)); + Move(v0, v1, dst); + } else { + Move(f0, dst); // Reg f0 is o32 ABI FP return value. + } +} + + +void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) { + CpuFeatures::Scope scope(FPU); + if (!IsMipsSoftFloatABI) { + Move(f12, dreg); } else { - if (!dst.is(f0)) { - mov_d(dst, f0); // Reg f0 is o32 ABI FP return value. + Move(a0, a1, dreg); + } +} + + +void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1, + DoubleRegister dreg2) { + CpuFeatures::Scope scope(FPU); + if (!IsMipsSoftFloatABI) { + if (dreg2.is(f12)) { + ASSERT(!dreg1.is(f14)); + Move(f14, dreg2); + Move(f12, dreg1); + } else { + Move(f12, dreg1); + Move(f14, dreg2); } + } else { + Move(a0, a1, dreg1); + Move(a2, a3, dreg2); } } +void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg, + Register reg) { + CpuFeatures::Scope scope(FPU); + if (!IsMipsSoftFloatABI) { + Move(f12, dreg); + Move(a2, reg); + } else { + Move(a2, reg); + Move(a0, a1, dreg); + } +} + // ----------------------------------------------------------------------------- // JavaScript invokes. @@ -3490,14 +3593,27 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate()))); sw(cp, MemOperand(t8)); - // Ensure we are not saving doubles, since it's not implemented yet. - ASSERT(save_doubles == 0); + const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); + if (save_doubles) { + // The stack must be allign to 0 modulo 8 for stores with sdc1. + ASSERT(kDoubleSize == frame_alignment); + if (frame_alignment > 0) { + ASSERT(IsPowerOf2(frame_alignment)); + And(sp, sp, Operand(-frame_alignment)); // Align stack. + } + int space = FPURegister::kNumRegisters * kDoubleSize; + Subu(sp, sp, Operand(space)); + // Remember: we only need to save every 2nd double FPU value. + for (int i = 0; i < FPURegister::kNumRegisters; i+=2) { + FPURegister reg = FPURegister::from_code(i); + sdc1(reg, MemOperand(sp, i * kDoubleSize)); + } + } // Reserve place for the return address, stack space and an optional slot // (used by the DirectCEntryStub to hold the return value if a struct is // returned) and align the frame preparing for calling the runtime function. ASSERT(stack_space >= 0); - const int frame_alignment = MacroAssembler::ActivationFrameAlignment(); Subu(sp, sp, Operand((stack_space + 2) * kPointerSize)); if (frame_alignment > 0) { ASSERT(IsPowerOf2(frame_alignment)); @@ -3513,8 +3629,15 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count) { - // Ensure we are not restoring doubles, since it's not implemented yet. - ASSERT(save_doubles == 0); + // Optionally restore all double registers. + if (save_doubles) { + // Remember: we only need to restore every 2nd double FPU value. + lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset)); + for (int i = 0; i < FPURegister::kNumRegisters; i+=2) { + FPURegister reg = FPURegister::from_code(i); + ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize)); + } + } // Clear top frame. li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate()))); @@ -3837,6 +3960,17 @@ void MacroAssembler::CallCFunctionHelper(Register function, #undef BRANCH_ARGS_CHECK +void MacroAssembler::LoadInstanceDescriptors(Register map, + Register descriptors) { + lw(descriptors, + FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset)); + Label not_smi; + JumpIfNotSmi(descriptors, ¬_smi); + li(descriptors, Operand(FACTORY->empty_descriptor_array())); + bind(¬_smi); +} + + CodePatcher::CodePatcher(byte* address, int instructions) : address_(address), instructions_(instructions), diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index d4da96fa7..73ee047e0 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -207,9 +207,28 @@ DECLARE_NOTARGET_PROTOTYPE(Ret) void Swap(Register reg1, Register reg2, Register scratch = no_reg); void Call(Label* target); - // May do nothing if the registers are identical. - void Move(Register dst, Register src); + inline void Move(Register dst, Register src) { + if (!dst.is(src)) { + mov(dst, src); + } + } + + inline void Move(FPURegister dst, FPURegister src) { + if (!dst.is(src)) { + mov_d(dst, src); + } + } + + inline void Move(Register dst_low, Register dst_high, FPURegister src) { + mfc1(dst_low, src); + mfc1(dst_high, FPURegister::from_code(src.code() + 1)); + } + + inline void Move(FPURegister dst, Register src_low, Register src_high) { + mtc1(src_low, dst); + mtc1(src_high, FPURegister::from_code(dst.code() + 1)); + } // Jump unconditionally to given label. // We NEED a nop in the branch delay slot, as it used by v8, for example in @@ -509,34 +528,19 @@ DECLARE_NOTARGET_PROTOTYPE(Ret) Addu(sp, sp, Operand(count * kPointerSize)); } - // --------------------------------------------------------------------------- - // These functions are only used by crankshaft, so they are currently - // unimplemented. - // Push and pop the registers that can hold pointers, as defined by the // RegList constant kSafepointSavedRegisters. - void PushSafepointRegisters() { - UNIMPLEMENTED_MIPS(); - } - - void PopSafepointRegisters() { - UNIMPLEMENTED_MIPS(); - } - - void PushSafepointRegistersAndDoubles() { - UNIMPLEMENTED_MIPS(); - } - - void PopSafepointRegistersAndDoubles() { - UNIMPLEMENTED_MIPS(); - } - - static int SafepointRegisterStackIndex(int reg_code) { - UNIMPLEMENTED_MIPS(); - return 0; - } - - // --------------------------------------------------------------------------- + void PushSafepointRegisters(); + void PopSafepointRegisters(); + void PushSafepointRegistersAndDoubles(); + void PopSafepointRegistersAndDoubles(); + // Store value in register src in the safepoint stack slot for + // register dst. + void StoreToSafepointRegisterSlot(Register src, Register dst); + void StoreToSafepointRegistersAndDoublesSlot(Register src, Register dst); + // Load the value of the src register from its safepoint stack slot + // into register dst. + void LoadFromSafepointRegisterSlot(Register dst, Register src); // MIPS32 R2 instruction macro. void Ins(Register rt, Register rs, uint16_t pos, uint16_t size); @@ -881,6 +885,14 @@ DECLARE_NOTARGET_PROTOTYPE(Ret) void CallCFunction(Register function, Register scratch, int num_arguments); void GetCFunctionDoubleResult(const DoubleRegister dst); + // There are two ways of passing double arguments on MIPS, depending on + // whether soft or hard floating point ABI is used. These functions + // abstract parameter passing for the three different ways we call + // C functions from generated code. + void SetCallCDoubleArguments(DoubleRegister dreg); + void SetCallCDoubleArguments(DoubleRegister dreg1, DoubleRegister dreg2); + void SetCallCDoubleArguments(DoubleRegister dreg, Register reg); + // Calls an API function. Allocates HandleScope, extracts returned value // from handle and propagates exceptions. Restores context. MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function, @@ -1060,6 +1072,8 @@ DECLARE_NOTARGET_PROTOTYPE(Ret) Register scratch2, Label* failure); + void LoadInstanceDescriptors(Register map, Register descriptors); + private: void CallCFunctionHelper(Register function, ExternalReference function_reference, @@ -1100,11 +1114,19 @@ DECLARE_NOTARGET_PROTOTYPE(Ret) Register scratch1, Register scratch2); + // Compute memory operands for safepoint stack slots. + static int SafepointRegisterStackIndex(int reg_code); + MemOperand SafepointRegisterSlot(Register reg); + MemOperand SafepointRegistersAndDoublesSlot(Register reg); bool generating_stub_; bool allow_stub_calls_; // This handle will be patched with the code object on installation. Handle code_object_; + + // Needs access to SafepointRegisterStackIndex for optimized frame + // traversal. + friend class OptimizedFrame; }; @@ -1181,4 +1203,3 @@ static inline MemOperand CFunctionArgumentOperand(int index) { } } // namespace v8::internal #endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_ - diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc index 8a335441b..68fb7ce87 100644 --- a/src/mips/simulator-mips.cc +++ b/src/mips/simulator-mips.cc @@ -496,12 +496,27 @@ void MipsDebugger::Debug() { end = cur + words; while (cur < end) { - PrintF(" 0x%08x: 0x%08x %10d\n", + PrintF(" 0x%08x: 0x%08x %10d", reinterpret_cast(cur), *cur, *cur); + HeapObject* obj = reinterpret_cast(*cur); + int value = *cur; + Heap* current_heap = v8::internal::Isolate::Current()->heap(); + if (current_heap->Contains(obj) || ((value & 1) == 0)) { + PrintF(" ("); + if ((value & 1) == 0) { + PrintF("smi %d", value / 2); + } else { + obj->ShortPrint(); + } + PrintF(")"); + } + PrintF("\n"); cur++; } - } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0)) { + } else if ((strcmp(cmd, "disasm") == 0) || + (strcmp(cmd, "dpc") == 0) || + (strcmp(cmd, "di") == 0)) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); // Use a reasonably large buffer. @@ -514,11 +529,23 @@ void MipsDebugger::Debug() { cur = reinterpret_cast(sim_->get_pc()); end = cur + (10 * Instruction::kInstrSize); } else if (argc == 2) { - int32_t value; - if (GetValue(arg1, &value)) { - cur = reinterpret_cast(value); - // No length parameter passed, assume 10 instructions. - end = cur + (10 * Instruction::kInstrSize); + int regnum = Registers::Number(arg1); + if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) { + // The argument is an address or a register name. + int32_t value; + if (GetValue(arg1, &value)) { + cur = reinterpret_cast(value); + // Disassemble 10 instructions at . + end = cur + (10 * Instruction::kInstrSize); + } + } else { + // The argument is the number of instructions. + int32_t value; + if (GetValue(arg1, &value)) { + cur = reinterpret_cast(sim_->get_pc()); + // Disassemble instructions. + end = cur + (value * Instruction::kInstrSize); + } } } else { int32_t value1; @@ -615,8 +642,10 @@ void MipsDebugger::Debug() { PrintF("flags\n"); PrintF(" print flags\n"); PrintF("disasm []\n"); - PrintF("disasm [[
] ]\n"); - PrintF(" disassemble code, default is 10 instructions from pc\n"); + PrintF("disasm [
]\n"); + PrintF("disasm [[
] ]\n"); + PrintF(" disassemble code, default is 10 instructions\n"); + PrintF(" from pc (alias 'di')\n"); PrintF("gdb\n"); PrintF(" enter gdb\n"); PrintF("break
\n"); @@ -934,6 +963,87 @@ double Simulator::get_fpu_register_double(int fpureg) const { } +// For use in calls that take two double values, constructed either +// from a0-a3 or f12 and f14. +void Simulator::GetFpArgs(double* x, double* y) { + if (!IsMipsSoftFloatABI) { + *x = get_fpu_register_double(12); + *y = get_fpu_register_double(14); + } else { + // We use a char buffer to get around the strict-aliasing rules which + // otherwise allow the compiler to optimize away the copy. + char buffer[sizeof(*x)]; + int32_t* reg_buffer = reinterpret_cast(buffer); + + // Registers a0 and a1 -> x. + reg_buffer[0] = get_register(a0); + reg_buffer[1] = get_register(a1); + memcpy(x, buffer, sizeof(buffer)); + + // Registers a2 and a3 -> y. + reg_buffer[0] = get_register(a2); + reg_buffer[1] = get_register(a3); + memcpy(y, buffer, sizeof(buffer)); + } +} + + +// For use in calls that take one double value, constructed either +// from a0 and a1 or f12. +void Simulator::GetFpArgs(double* x) { + if (!IsMipsSoftFloatABI) { + *x = get_fpu_register_double(12); + } else { + // We use a char buffer to get around the strict-aliasing rules which + // otherwise allow the compiler to optimize away the copy. + char buffer[sizeof(*x)]; + int32_t* reg_buffer = reinterpret_cast(buffer); + // Registers a0 and a1 -> x. + reg_buffer[0] = get_register(a0); + reg_buffer[1] = get_register(a1); + memcpy(x, buffer, sizeof(buffer)); + } +} + + +// For use in calls that take one double value constructed either +// from a0 and a1 or f12 and one integer value. +void Simulator::GetFpArgs(double* x, int32_t* y) { + if (!IsMipsSoftFloatABI) { + *x = get_fpu_register_double(12); + *y = get_register(a2); + } else { + // We use a char buffer to get around the strict-aliasing rules which + // otherwise allow the compiler to optimize away the copy. + char buffer[sizeof(*x)]; + int32_t* reg_buffer = reinterpret_cast(buffer); + // Registers 0 and 1 -> x. + reg_buffer[0] = get_register(a0); + reg_buffer[1] = get_register(a1); + memcpy(x, buffer, sizeof(buffer)); + + // Register 2 -> y. + reg_buffer[0] = get_register(a2); + memcpy(y, buffer, sizeof(*y)); + } +} + + +// The return value is either in v0/v1 or f0. +void Simulator::SetFpResult(const double& result) { + if (!IsMipsSoftFloatABI) { + set_fpu_register_double(0, result); + } else { + char buffer[2 * sizeof(registers_[0])]; + int32_t* reg_buffer = reinterpret_cast(buffer); + memcpy(buffer, &result, sizeof(buffer)); + // Copy result to v0 and v1. + set_register(v0, reg_buffer[0]); + set_register(v1, reg_buffer[1]); + } +} + + // Helper functions for setting and testing the FCSR register's bits. void Simulator::set_fcsr_bit(uint32_t cc, bool value) { if (value) { @@ -1208,6 +1318,33 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { (redirection->type() == ExternalReference::BUILTIN_FP_CALL) || (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL); + if (!IsMipsSoftFloatABI) { + // With the hard floating point calling convention, double + // arguments are passed in FPU registers. Fetch the arguments + // from there and call the builtin using soft floating point + // convention. + switch (redirection->type()) { + case ExternalReference::BUILTIN_FP_FP_CALL: + case ExternalReference::BUILTIN_COMPARE_CALL: + arg0 = get_fpu_register(f12); + arg1 = get_fpu_register(f13); + arg2 = get_fpu_register(f14); + arg3 = get_fpu_register(f15); + break; + case ExternalReference::BUILTIN_FP_CALL: + arg0 = get_fpu_register(f12); + arg1 = get_fpu_register(f13); + break; + case ExternalReference::BUILTIN_FP_INT_CALL: + arg0 = get_fpu_register(f12); + arg1 = get_fpu_register(f13); + arg2 = get_register(a2); + break; + default: + break; + } + } + // This is dodgy but it works because the C entry stubs are never moved. // See comment in codegen-arm.cc and bug 1242173. int32_t saved_ra = get_register(ra); @@ -1218,31 +1355,44 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware // FPU, or gcc soft-float routines. Hardware FPU is simulated in this // simulator. Soft-float has additional abstraction of ExternalReference, - // to support serialization. Finally, when simulated on x86 host, the - // x86 softfloat routines are used, and this Redirection infrastructure - // lets simulated-mips make calls into x86 C code. - // When doing that, the 'double' return type must be handled differently - // than the usual int64_t return. The data is returned in different - // registers and cannot be cast from one type to the other. However, the - // calling arguments are passed the same way in both cases. + // to support serialization. if (fp_call) { SimulatorRuntimeFPCall target = reinterpret_cast(external); if (::v8::internal::FLAG_trace_sim) { - PrintF( - "Call to host function at %p args %08x, %08x, %08x, %08x\n", - FUNCTION_ADDR(target), - arg0, - arg1, - arg2, - arg3); - } + double dval0, dval1; + int32_t ival; + switch (redirection->type()) { + case ExternalReference::BUILTIN_FP_FP_CALL: + case ExternalReference::BUILTIN_COMPARE_CALL: + GetFpArgs(&dval0, &dval1); + PrintF("Call to host function at %p with args %f, %f", + FUNCTION_ADDR(target), dval0, dval1); + break; + case ExternalReference::BUILTIN_FP_CALL: + GetFpArgs(&dval0); + PrintF("Call to host function at %p with arg %f", + FUNCTION_ADDR(target), dval1); + break; + case ExternalReference::BUILTIN_FP_INT_CALL: + GetFpArgs(&dval0, &ival); + PrintF("Call to host function at %p with args %f, %d", + FUNCTION_ADDR(target), dval0, ival); + break; + default: + UNREACHABLE(); + break; + } + } double result = target(arg0, arg1, arg2, arg3); - // fp result -> registers v0 and v1. - int32_t gpreg_pair[2]; - memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); - set_register(v0, gpreg_pair[0]); - set_register(v1, gpreg_pair[1]); + if (redirection->type() != ExternalReference::BUILTIN_COMPARE_CALL) { + SetFpResult(result); + } else { + int32_t gpreg_pair[2]; + memcpy(&gpreg_pair[0], &result, 2 * sizeof(int32_t)); + set_register(v0, gpreg_pair[0]); + set_register(v1, gpreg_pair[1]); + } } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { // See DirectCEntryStub::GenerateCall for explanation of register usage. SimulatorRuntimeDirectApiCall target = diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h index 38d097480..21476dccb 100644 --- a/src/mips/simulator-mips.h +++ b/src/mips/simulator-mips.h @@ -323,9 +323,12 @@ class Simulator { static void* RedirectExternalReference(void* external_function, ExternalReference::Type type); - // Used for real time calls that takes two double values as arguments and - // returns a double. - void SetFpResult(double result); + // For use in calls that take double value arguments. + void GetFpArgs(double* x, double* y); + void GetFpArgs(double* x); + void GetFpArgs(double* x, int32_t* y); + void SetFpResult(const double& result); + // Architecture state. // Registers. diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc index cb65d88dd..c1ae567ab 100644 --- a/src/mips/stub-cache-mips.cc +++ b/src/mips/stub-cache-mips.cc @@ -3410,7 +3410,7 @@ MaybeObject* ExternalArrayStoreStubCompiler::CompileStore( a3, Handle(receiver->map()), Handle(stub), - DONT_DO_SMI_CHECK); + DO_SMI_CHECK); Handle ic = isolate()->builtins()->KeyedStoreIC_Miss(); __ Jump(ic, RelocInfo::CODE_TARGET); @@ -3566,8 +3566,21 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray( __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag)); __ Ret(); } else { - WriteInt32ToHeapNumberStub stub(value, v0, t2, t3); - __ TailCallStub(&stub); + Register dst1 = t2; + Register dst2 = t3; + FloatingPointHelper::Destination dest = + FloatingPointHelper::kCoreRegisters; + FloatingPointHelper::ConvertIntToDouble(masm, + value, + dest, + f0, + dst1, + dst2, + t1, + f2); + __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset)); + __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset)); + __ Ret(); } } else if (array_type == kExternalUnsignedIntArray) { // The test is different for unsigned int values. Since we need -- 2.34.1