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
This commit is contained in:
parent
179702df03
commit
9891a057e1
37
SConstruct
37
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
|
||||
|
@ -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()) {
|
||||
__ Push(a0, a1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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<int32_t>(
|
||||
Isolate::Current()->debug()->debug_break_return()->entry())));
|
||||
Isolate::Current()->debug()->debug_break_slot()->entry())));
|
||||
patcher.masm()->Call(v8::internal::t9);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
|
||||
|
@ -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<Expression*>* 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));
|
||||
|
@ -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 {
|
||||
if (!dst.is(f0)) {
|
||||
mov_d(dst, f0); // Reg f0 is o32 ABI FP return value.
|
||||
}
|
||||
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 {
|
||||
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),
|
||||
|
@ -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<Object> 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_
|
||||
|
||||
|
@ -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<intptr_t>(cur), *cur, *cur);
|
||||
HeapObject* obj = reinterpret_cast<HeapObject*>(*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<byte*>(sim_->get_pc());
|
||||
end = cur + (10 * Instruction::kInstrSize);
|
||||
} else if (argc == 2) {
|
||||
int32_t value;
|
||||
if (GetValue(arg1, &value)) {
|
||||
cur = reinterpret_cast<byte*>(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<byte*>(value);
|
||||
// Disassemble 10 instructions at <arg1>.
|
||||
end = cur + (10 * Instruction::kInstrSize);
|
||||
}
|
||||
} else {
|
||||
// The argument is the number of instructions.
|
||||
int32_t value;
|
||||
if (GetValue(arg1, &value)) {
|
||||
cur = reinterpret_cast<byte*>(sim_->get_pc());
|
||||
// Disassemble <arg1> 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 [<instructions>]\n");
|
||||
PrintF("disasm [[<address>] <instructions>]\n");
|
||||
PrintF(" disassemble code, default is 10 instructions from pc\n");
|
||||
PrintF("disasm [<address/register>]\n");
|
||||
PrintF("disasm [[<address/register>] <instructions>]\n");
|
||||
PrintF(" disassemble code, default is 10 instructions\n");
|
||||
PrintF(" from pc (alias 'di')\n");
|
||||
PrintF("gdb\n");
|
||||
PrintF(" enter gdb\n");
|
||||
PrintF("break <address>\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<int32_t*>(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<int32_t*>(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<int32_t*>(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<int32_t*>(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<SimulatorRuntimeFPCall>(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 =
|
||||
|
@ -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.
|
||||
|
@ -3410,7 +3410,7 @@ MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
|
||||
a3,
|
||||
Handle<Map>(receiver->map()),
|
||||
Handle<Code>(stub),
|
||||
DONT_DO_SMI_CHECK);
|
||||
DO_SMI_CHECK);
|
||||
|
||||
Handle<Code> 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
|
||||
|
Loading…
Reference in New Issue
Block a user