Merge V8 at 3.8.9.11
Bug: 5688872
Change-Id: Ie3b1dd67a730ec5e82686b7b37dba26f6a9bb24f
diff --git a/src/mips/assembler-mips-inl.h b/src/mips/assembler-mips-inl.h
index 2ba9760..f9e75fa 100644
--- a/src/mips/assembler-mips-inl.h
+++ b/src/mips/assembler-mips-inl.h
@@ -30,13 +30,14 @@
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
#ifndef V8_MIPS_ASSEMBLER_MIPS_INL_H_
#define V8_MIPS_ASSEMBLER_MIPS_INL_H_
#include "mips/assembler-mips.h"
+
#include "cpu.h"
#include "debug.h"
@@ -78,6 +79,16 @@
}
+int FPURegister::ToAllocationIndex(FPURegister reg) {
+ ASSERT(reg.code() % 2 == 0);
+ ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
+ ASSERT(reg.is_valid());
+ ASSERT(!reg.is(kDoubleRegZero));
+ ASSERT(!reg.is(kLithiumScratchDouble));
+ return (reg.code() / 2);
+}
+
+
// -----------------------------------------------------------------------------
// RelocInfo.
@@ -133,7 +144,7 @@
}
-Handle<Object> RelocInfo::target_object_handle(Assembler *origin) {
+Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return Handle<Object>(reinterpret_cast<Object**>(
Assembler::target_address_at(pc_)));
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index e933181..85b6ed8 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -301,7 +301,7 @@
own_buffer_ = false;
}
- // Setup buffer pointers.
+ // Set up buffer pointers.
ASSERT(buffer_ != NULL);
pc_ = buffer_;
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
@@ -337,7 +337,7 @@
void Assembler::GetCode(CodeDesc* desc) {
ASSERT(pc_ <= reloc_info_writer.pos()); // No overlap.
- // Setup code descriptor.
+ // Set up code descriptor.
desc->buffer = buffer_;
desc->buffer_size = buffer_size_;
desc->instr_size = pc_offset();
@@ -1970,7 +1970,7 @@
}
CHECK_GT(desc.buffer_size, 0); // No overflow.
- // Setup new buffer.
+ // Set up new buffer.
desc.buffer = NewArray<byte>(desc.buffer_size);
desc.instr_size = pc_offset();
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index b66ea0d..b1ffc45 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -30,7 +30,7 @@
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
#ifndef V8_MIPS_ASSEMBLER_MIPS_H_
@@ -182,12 +182,7 @@
kNumReservedRegisters;
- static int ToAllocationIndex(FPURegister reg) {
- ASSERT(reg.code() % 2 == 0);
- ASSERT(reg.code() / 2 < kNumAllocatableRegisters);
- ASSERT(reg.is_valid());
- return (reg.code() / 2);
- }
+ inline static int ToAllocationIndex(FPURegister reg);
static FPURegister FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kNumAllocatableRegisters);
@@ -302,6 +297,14 @@
const FPURegister f30 = { 30 };
const FPURegister f31 = { 31 };
+// Register aliases.
+// cp is assumed to be a callee saved register.
+static const Register& kLithiumScratchReg = s3; // Scratch register.
+static const Register& kLithiumScratchReg2 = s4; // Scratch register.
+static const Register& kRootRegister = s6; // Roots array pointer.
+static const Register& cp = s7; // JavaScript context pointer.
+static const Register& fp = s8_fp; // Alias for fp.
+static const DoubleRegister& kLithiumScratchDouble = f30;
static const FPURegister& kDoubleRegZero = f28;
// FPU (coprocessor 1) control registers.
@@ -667,7 +670,7 @@
// Never use the int16_t b(l)cond version with a branch offset
// instead of using the Label* version.
- // Jump targets must be in the current 256 MB-aligned region. ie 28 bits.
+ // Jump targets must be in the current 256 MB-aligned region. i.e. 28 bits.
void j(int32_t target);
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index 98fd57d..3f4aab3 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -74,17 +74,33 @@
}
+// Load the built-in InternalArray function from the current context.
+static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
+ Register result) {
+ // Load the global context.
+
+ __ lw(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ lw(result,
+ FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
+ // Load the InternalArray function from the global context.
+ __ lw(result,
+ MemOperand(result,
+ Context::SlotOffset(
+ Context::INTERNAL_ARRAY_FUNCTION_INDEX)));
+}
+
+
// Load the built-in Array function from the current context.
static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
// Load the global context.
__ lw(result, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ lw(result,
- FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
+ FieldMemOperand(result, GlobalObject::kGlobalContextOffset));
// Load the Array function from the global context.
__ lw(result,
- MemOperand(result,
- Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+ MemOperand(result,
+ Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
}
@@ -308,7 +324,8 @@
static void ArrayNativeCode(MacroAssembler* masm,
Label* call_generic_code) {
Counters* counters = masm->isolate()->counters();
- Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array;
+ Label argc_one_or_more, argc_two_or_more, not_empty_array, empty_array,
+ has_non_smi_element;
// Check for array construction with zero arguments or one.
__ Branch(&argc_one_or_more, ne, a0, Operand(zero_reg));
@@ -322,7 +339,7 @@
t1,
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, a3, t0);
- // Setup return value, remove receiver from stack and return.
+ // Set up return value, remove receiver from stack and return.
__ mov(v0, a2);
__ Addu(sp, sp, Operand(kPointerSize));
__ Ret();
@@ -365,7 +382,7 @@
call_generic_code);
__ IncrementCounter(counters->array_function_native(), 1, a2, t0);
- // Setup return value, remove receiver and argument from stack and return.
+ // Set up return value, remove receiver and argument from stack and return.
__ mov(v0, a3);
__ Addu(sp, sp, Operand(2 * kPointerSize));
__ Ret();
@@ -400,13 +417,19 @@
// sp[0]: last argument
Label loop, entry;
- __ Branch(&entry);
+ __ Branch(USE_DELAY_SLOT, &entry);
+ __ mov(t3, sp);
__ bind(&loop);
- __ pop(a2);
+ __ lw(a2, MemOperand(t3));
+ __ Addu(t3, t3, kPointerSize);
+ if (FLAG_smi_only_arrays) {
+ __ JumpIfNotSmi(a2, &has_non_smi_element);
+ }
__ Addu(t1, t1, -kPointerSize);
__ sw(a2, MemOperand(t1));
__ bind(&entry);
__ Branch(&loop, lt, t0, Operand(t1));
+ __ mov(sp, t3);
// Remove caller arguments and receiver from the stack, setup return value and
// return.
@@ -416,6 +439,46 @@
__ Addu(sp, sp, Operand(kPointerSize));
__ mov(v0, a3);
__ Ret();
+
+ __ bind(&has_non_smi_element);
+ __ UndoAllocationInNewSpace(a3, t0);
+ __ b(call_generic_code);
+}
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a0 : number of arguments
+ // -- ra : return address
+ // -- sp[...]: constructor arguments
+ // -----------------------------------
+ Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+ // Get the InternalArray function.
+ GenerateLoadInternalArrayFunction(masm, a1);
+
+ if (FLAG_debug_code) {
+ // Initial map for the builtin InternalArray functions should be maps.
+ __ lw(a2, FieldMemOperand(a1, JSFunction::kPrototypeOrInitialMapOffset));
+ __ And(t0, a2, Operand(kSmiTagMask));
+ __ Assert(ne, "Unexpected initial map for InternalArray function",
+ t0, Operand(zero_reg));
+ __ GetObjectType(a2, a3, t0);
+ __ Assert(eq, "Unexpected initial map for InternalArray function",
+ t0, Operand(MAP_TYPE));
+ }
+
+ // Run the native code for the InternalArray function called as a normal
+ // function.
+ ArrayNativeCode(masm, &generic_array_code);
+
+ // Jump to the generic array code if the specialized code cannot handle the
+ // construction.
+ __ bind(&generic_array_code);
+
+ Handle<Code> array_code =
+ masm->isolate()->builtins()->InternalArrayCodeGeneric();
+ __ Jump(array_code, RelocInfo::CODE_TARGET);
}
@@ -832,7 +895,7 @@
// Initialize the FixedArray.
// a1: constructor
- // a3: number of elements in properties array (un-tagged)
+ // a3: number of elements in properties array (untagged)
// t4: JSObject
// t5: start of next object
__ LoadRoot(t6, Heap::kFixedArrayMapRootIndex);
@@ -918,10 +981,10 @@
// sp[4]: number of arguments (smi-tagged)
__ lw(a3, MemOperand(sp, 4 * kPointerSize));
- // Setup pointer to last argument.
+ // Set up pointer to last argument.
__ Addu(a2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
- // Setup number of arguments for function call below.
+ // Set up number of arguments for function call below.
__ srl(a0, a3, kSmiTagSize);
// Copy arguments and receiver to the expression stack.
@@ -1036,7 +1099,7 @@
// ----------- S t a t e -------------
// -- a0: code entry
// -- a1: function
- // -- a2: reveiver_pointer
+ // -- a2: receiver_pointer
// -- a3: argc
// -- s0: argv
// -----------------------------------
@@ -1051,17 +1114,14 @@
// Set up the context from the function argument.
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
- // Set up the roots register.
- ExternalReference roots_array_start =
- ExternalReference::roots_array_start(masm->isolate());
- __ li(s6, Operand(roots_array_start));
+ __ InitializeRootRegister();
// Push the function and the receiver onto the stack.
__ Push(a1, a2);
// Copy arguments to the stack in a loop.
// a3: argc
- // s0: argv, ie points to first arg
+ // s0: argv, i.e. points to first arg
Label loop, entry;
__ sll(t0, a3, kPointerSizeLog2);
__ addu(t2, s0, t0);
@@ -1740,6 +1800,7 @@
__ Call(a3);
+ masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
// Exit frame and return.
LeaveArgumentsAdaptorFrame(masm);
__ Ret();
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 92abf6d..289e6b8 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -157,13 +157,13 @@
// Load the function from the stack.
__ lw(a3, MemOperand(sp, 0));
- // Setup the object header.
+ // Set up the object header.
__ LoadRoot(a2, Heap::kFunctionContextMapRootIndex);
__ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ li(a2, Operand(Smi::FromInt(length)));
__ sw(a2, FieldMemOperand(v0, FixedArray::kLengthOffset));
- // Setup the fixed slots.
+ // Set up the fixed slots.
__ li(a1, Operand(Smi::FromInt(0)));
__ sw(a3, MemOperand(v0, Context::SlotOffset(Context::CLOSURE_INDEX)));
__ sw(cp, MemOperand(v0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
@@ -208,7 +208,7 @@
// Load the serialized scope info from the stack.
__ lw(a1, MemOperand(sp, 1 * kPointerSize));
- // Setup the object header.
+ // Set up the object header.
__ LoadRoot(a2, Heap::kBlockContextMapRootIndex);
__ sw(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
__ li(a2, Operand(Smi::FromInt(length)));
@@ -229,7 +229,7 @@
__ lw(a3, ContextOperand(a3, Context::CLOSURE_INDEX));
__ bind(&after_sentinel);
- // Setup the fixed slots.
+ // Set up the fixed slots.
__ sw(a3, ContextOperand(v0, Context::CLOSURE_INDEX));
__ sw(cp, ContextOperand(v0, Context::PREVIOUS_INDEX));
__ sw(a1, ContextOperand(v0, Context::EXTENSION_INDEX));
@@ -726,7 +726,7 @@
__ Subu(int_scratch, zero_reg, int_scratch);
__ bind(&skip_sub);
- // Get mantisssa[51:20].
+ // Get mantissa[51:20].
// Get the position of the first set bit.
__ clz(dst1, int_scratch);
@@ -971,7 +971,7 @@
// non zero bits left. So we need the (30 - exponent) last bits of the
// 31 higher bits of the mantissa to be null.
// Because bits [21:0] are null, we can check instead that the
- // (32 - exponent) last bits of the 32 higher bits of the mantisssa are null.
+ // (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
// Get the 32 higher bits of the mantissa in dst.
__ Ext(dst,
@@ -3592,113 +3592,218 @@
void MathPowStub::Generate(MacroAssembler* masm) {
- Label call_runtime;
+ CpuFeatures::Scope fpu_scope(FPU);
+ const Register base = a1;
+ const Register exponent = a2;
+ const Register heapnumbermap = t1;
+ const Register heapnumber = v0;
+ const DoubleRegister double_base = f2;
+ const DoubleRegister double_exponent = f4;
+ const DoubleRegister double_result = f0;
+ const DoubleRegister double_scratch = f6;
+ const FPURegister single_scratch = f8;
+ const Register scratch = t5;
+ const Register scratch2 = t3;
- if (CpuFeatures::IsSupported(FPU)) {
- CpuFeatures::Scope scope(FPU);
-
- Label base_not_smi;
- Label exponent_not_smi;
- Label convert_exponent;
-
- const Register base = a0;
- const Register exponent = a2;
- const Register heapnumbermap = t1;
- const Register heapnumber = s0; // Callee-saved register.
- const Register scratch = t2;
- const Register scratch2 = t3;
-
- // Alocate FP values in the ABI-parameter-passing regs.
- const DoubleRegister double_base = f12;
- const DoubleRegister double_exponent = f14;
- const DoubleRegister double_result = f0;
- const DoubleRegister double_scratch = f2;
-
- __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
+ Label call_runtime, done, exponent_not_smi, int_exponent;
+ if (exponent_type_ == ON_STACK) {
+ Label base_is_smi, unpack_exponent;
+ // The exponent and base are supplied as arguments on the stack.
+ // This can only happen if the stub is called from non-optimized code.
+ // Load input parameters from stack to double registers.
__ lw(base, MemOperand(sp, 1 * kPointerSize));
__ lw(exponent, MemOperand(sp, 0 * kPointerSize));
- // Convert base to double value and store it in f0.
- __ JumpIfNotSmi(base, &base_not_smi);
- // Base is a Smi. Untag and convert it.
- __ SmiUntag(base);
- __ mtc1(base, double_scratch);
- __ cvt_d_w(double_base, double_scratch);
- __ Branch(&convert_exponent);
+ __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
- __ bind(&base_not_smi);
+ __ JumpIfSmi(base, &base_is_smi);
__ lw(scratch, FieldMemOperand(base, JSObject::kMapOffset));
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
- // Base is a heapnumber. Load it into double register.
- __ ldc1(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
- __ bind(&convert_exponent);
+ __ ldc1(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
+ __ jmp(&unpack_exponent);
+
+ __ bind(&base_is_smi);
+ __ SmiUntag(base);
+ __ mtc1(base, single_scratch);
+ __ cvt_d_w(double_base, single_scratch);
+ __ bind(&unpack_exponent);
+
__ JumpIfNotSmi(exponent, &exponent_not_smi);
__ SmiUntag(exponent);
-
- // The base is in a double register and the exponent is
- // an untagged smi. Allocate a heap number and call a
- // C function for integer exponents. The register containing
- // the heap number is callee-saved.
- __ AllocateHeapNumber(heapnumber,
- scratch,
- scratch2,
- heapnumbermap,
- &call_runtime);
- __ push(ra);
- __ PrepareCallCFunction(1, 1, scratch);
- __ SetCallCDoubleArguments(double_base, exponent);
- {
- AllowExternalCallThatCantCauseGC scope(masm);
- __ CallCFunction(
- ExternalReference::power_double_int_function(masm->isolate()), 1, 1);
- __ pop(ra);
- __ GetCFunctionDoubleResult(double_result);
- }
- __ sdc1(double_result,
- FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
- __ mov(v0, heapnumber);
- __ DropAndRet(2 * kPointerSize);
+ __ jmp(&int_exponent);
__ bind(&exponent_not_smi);
__ lw(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
__ Branch(&call_runtime, ne, scratch, Operand(heapnumbermap));
- // Exponent is a heapnumber. Load it into double register.
__ ldc1(double_exponent,
FieldMemOperand(exponent, HeapNumber::kValueOffset));
+ } else if (exponent_type_ == TAGGED) {
+ // Base is already in double_base.
+ __ JumpIfNotSmi(exponent, &exponent_not_smi);
+ __ SmiUntag(exponent);
+ __ jmp(&int_exponent);
- // The base and the exponent are in double registers.
- // Allocate a heap number and call a C function for
- // double exponents. The register containing
- // the heap number is callee-saved.
- __ AllocateHeapNumber(heapnumber,
- scratch,
- scratch2,
- heapnumbermap,
- &call_runtime);
- __ push(ra);
- __ PrepareCallCFunction(0, 2, scratch);
- // ABI (o32) for func(double a, double b): a in f12, b in f14.
- ASSERT(double_base.is(f12));
- ASSERT(double_exponent.is(f14));
- __ SetCallCDoubleArguments(double_base, double_exponent);
- {
- AllowExternalCallThatCantCauseGC scope(masm);
- __ CallCFunction(
- ExternalReference::power_double_double_function(masm->isolate()),
- 0,
- 2);
- __ pop(ra);
- __ GetCFunctionDoubleResult(double_result);
- }
- __ sdc1(double_result,
- FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
- __ mov(v0, heapnumber);
- __ DropAndRet(2 * kPointerSize);
+ __ bind(&exponent_not_smi);
+ __ ldc1(double_exponent,
+ FieldMemOperand(exponent, HeapNumber::kValueOffset));
}
- __ bind(&call_runtime);
- __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+ if (exponent_type_ != INTEGER) {
+ Label int_exponent_convert;
+ // Detect integer exponents stored as double.
+ __ EmitFPUTruncate(kRoundToMinusInf,
+ single_scratch,
+ double_exponent,
+ scratch,
+ scratch2,
+ kCheckForInexactConversion);
+ // scratch2 == 0 means there was no conversion error.
+ __ Branch(&int_exponent_convert, eq, scratch2, Operand(zero_reg));
+
+ if (exponent_type_ == ON_STACK) {
+ // Detect square root case. Crankshaft detects constant +/-0.5 at
+ // compile time and uses DoMathPowHalf instead. We then skip this check
+ // for non-constant cases of +/-0.5 as these hardly occur.
+ Label not_plus_half;
+
+ // Test for 0.5.
+ __ Move(double_scratch, 0.5);
+ __ BranchF(USE_DELAY_SLOT,
+ ¬_plus_half,
+ NULL,
+ ne,
+ double_exponent,
+ double_scratch);
+
+ // Calculates square root of base. Check for the special case of
+ // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
+ __ Move(double_scratch, -V8_INFINITY);
+ __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
+ __ neg_d(double_result, double_scratch);
+
+ // Add +0 to convert -0 to +0.
+ __ add_d(double_scratch, double_base, kDoubleRegZero);
+ __ sqrt_d(double_result, double_scratch);
+ __ jmp(&done);
+
+ __ bind(¬_plus_half);
+ __ Move(double_scratch, -0.5);
+ __ BranchF(USE_DELAY_SLOT,
+ &call_runtime,
+ NULL,
+ ne,
+ double_exponent,
+ double_scratch);
+
+ // Calculates square root of base. Check for the special case of
+ // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
+ __ Move(double_scratch, -V8_INFINITY);
+ __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, double_base, double_scratch);
+ __ Move(double_result, kDoubleRegZero);
+
+ // Add +0 to convert -0 to +0.
+ __ add_d(double_scratch, double_base, kDoubleRegZero);
+ __ Move(double_result, 1);
+ __ sqrt_d(double_scratch, double_scratch);
+ __ div_d(double_result, double_result, double_scratch);
+ __ jmp(&done);
+ }
+
+ __ push(ra);
+ {
+ AllowExternalCallThatCantCauseGC scope(masm);
+ __ PrepareCallCFunction(0, 2, scratch);
+ __ SetCallCDoubleArguments(double_base, double_exponent);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(masm->isolate()),
+ 0, 2);
+ }
+ __ pop(ra);
+ __ GetCFunctionDoubleResult(double_result);
+ __ jmp(&done);
+
+ __ bind(&int_exponent_convert);
+ __ mfc1(exponent, single_scratch);
+ }
+
+ // Calculate power with integer exponent.
+ __ bind(&int_exponent);
+
+ __ mov(scratch, exponent); // Back up exponent.
+ __ mov_d(double_scratch, double_base); // Back up base.
+ __ Move(double_result, 1.0);
+
+ // Get absolute value of exponent.
+ Label positive_exponent;
+ __ Branch(&positive_exponent, ge, scratch, Operand(zero_reg));
+ __ Subu(scratch, zero_reg, scratch);
+ __ bind(&positive_exponent);
+
+ Label while_true, no_carry, loop_end;
+ __ bind(&while_true);
+
+ __ And(scratch2, scratch, 1);
+
+ __ Branch(&no_carry, eq, scratch2, Operand(zero_reg));
+ __ mul_d(double_result, double_result, double_scratch);
+ __ bind(&no_carry);
+
+ __ sra(scratch, scratch, 1);
+
+ __ Branch(&loop_end, eq, scratch, Operand(zero_reg));
+ __ mul_d(double_scratch, double_scratch, double_scratch);
+
+ __ Branch(&while_true);
+
+ __ bind(&loop_end);
+
+ __ Branch(&done, ge, exponent, Operand(zero_reg));
+ __ Move(double_scratch, 1.0);
+ __ div_d(double_result, double_scratch, double_result);
+ // Test whether result is zero. Bail out to check for subnormal result.
+ // Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
+ __ BranchF(&done, NULL, ne, double_result, kDoubleRegZero);
+
+ // double_exponent may not contain the exponent value if the input was a
+ // smi. We set it with exponent value before bailing out.
+ __ mtc1(exponent, single_scratch);
+ __ cvt_d_w(double_exponent, single_scratch);
+
+ // Returning or bailing out.
+ Counters* counters = masm->isolate()->counters();
+ if (exponent_type_ == ON_STACK) {
+ // The arguments are still on the stack.
+ __ bind(&call_runtime);
+ __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
+
+ // The stub is called from non-optimized code, which expects the result
+ // as heap number in exponent.
+ __ bind(&done);
+ __ AllocateHeapNumber(
+ heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
+ __ sdc1(double_result,
+ FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
+ ASSERT(heapnumber.is(v0));
+ __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
+ __ DropAndRet(2);
+ } else {
+ __ push(ra);
+ {
+ AllowExternalCallThatCantCauseGC scope(masm);
+ __ PrepareCallCFunction(0, 2, scratch);
+ __ SetCallCDoubleArguments(double_base, double_exponent);
+ __ CallCFunction(
+ ExternalReference::power_double_double_function(masm->isolate()),
+ 0, 2);
+ }
+ __ pop(ra);
+ __ GetCFunctionDoubleResult(double_result);
+
+ __ bind(&done);
+ __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
+ __ Ret();
+ }
}
@@ -3900,7 +4005,7 @@
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(save_doubles_);
- // Setup argc and the builtin function in callee-saved registers.
+ // Set up argc and the builtin function in callee-saved registers.
__ mov(s0, a0);
__ mov(s2, a1);
@@ -3956,7 +4061,7 @@
// Registers:
// a0: entry address
// a1: function
- // a2: reveiver
+ // a2: receiver
// a3: argc
//
// Stack:
@@ -3992,13 +4097,13 @@
isolate)));
__ lw(t0, MemOperand(t0));
__ Push(t3, t2, t1, t0);
- // Setup frame pointer for the frame to be pushed.
+ // Set up frame pointer for the frame to be pushed.
__ addiu(fp, sp, -EntryFrameConstants::kCallerFPOffset);
// Registers:
// a0: entry_address
// a1: function
- // a2: reveiver_pointer
+ // a2: receiver_pointer
// a3: argc
// s0: argv
//
@@ -4065,7 +4170,7 @@
// Registers:
// a0: entry_address
// a1: function
- // a2: reveiver_pointer
+ // a2: receiver_pointer
// a3: argc
// s0: argv
//
@@ -4480,7 +4585,7 @@
__ sw(a3, FieldMemOperand(v0, i));
}
- // Setup the callee in-object property.
+ // Set up the callee in-object property.
STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
__ lw(a3, MemOperand(sp, 2 * kPointerSize));
const int kCalleeOffset = JSObject::kHeaderSize +
@@ -4493,7 +4598,7 @@
Heap::kArgumentsLengthIndex * kPointerSize;
__ sw(a2, FieldMemOperand(v0, kLengthOffset));
- // Setup the elements pointer in the allocated arguments object.
+ // Set up the elements pointer in the allocated arguments object.
// If we allocated a parameter map, t0 will point there, otherwise
// it will point to the backing store.
__ Addu(t0, v0, Operand(Heap::kArgumentsObjectSize));
@@ -4595,7 +4700,7 @@
__ Ret();
// Do the runtime call to allocate the arguments object.
- // a2 = argument count (taggged)
+ // a2 = argument count (tagged)
__ bind(&runtime);
__ sw(a2, MemOperand(sp, 0 * kPointerSize)); // Patch argument count.
__ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
@@ -4670,7 +4775,7 @@
// Get the parameters pointer from the stack.
__ lw(a2, MemOperand(sp, 1 * kPointerSize));
- // Setup the elements pointer in the allocated arguments object and
+ // Set up the elements pointer in the allocated arguments object and
// initialize the header in the elements fixed array.
__ Addu(t0, v0, Operand(Heap::kArgumentsObjectSizeStrict));
__ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
@@ -4682,7 +4787,7 @@
// Copy the fixed array slots.
Label loop;
- // Setup t0 to point to the first array slot.
+ // Set up t0 to point to the first array slot.
__ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop);
// Pre-decrement a2 with kPointerSize on each iteration.
@@ -4902,9 +5007,9 @@
STATIC_ASSERT(kAsciiStringTag == 4);
STATIC_ASSERT(kTwoByteStringTag == 0);
// Find the code object based on the assumptions above.
- __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ascii.
+ __ And(a0, a0, Operand(kStringEncodingMask)); // Non-zero for ASCII.
__ lw(t9, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset));
- __ sra(a3, a0, 2); // a3 is 1 for ascii, 0 for UC16 (usyed below).
+ __ sra(a3, a0, 2); // a3 is 1 for ASCII, 0 for UC16 (used below).
__ lw(t1, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset));
__ movz(t9, t1, a0); // If UC16 (a0 is 0), replace t9 w/kDataUC16CodeOffset.
@@ -5321,7 +5426,7 @@
// of the original receiver from the call site).
__ bind(&non_function);
__ sw(a1, MemOperand(sp, argc_ * kPointerSize));
- __ li(a0, Operand(argc_)); // Setup the number of arguments.
+ __ li(a0, Operand(argc_)); // Set up the number of arguments.
__ mov(a2, zero_reg);
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION);
__ SetCallKind(t1, CALL_AS_METHOD);
@@ -5820,11 +5925,15 @@
void StringHelper::GenerateHashInit(MacroAssembler* masm,
- Register hash,
- Register character) {
- // hash = character + (character << 10);
- __ sll(hash, character, 10);
+ Register hash,
+ Register character) {
+ // hash = seed + character + ((seed + character) << 10);
+ __ LoadRoot(hash, Heap::kHashSeedRootIndex);
+ // Untag smi seed and add the character.
+ __ SmiUntag(hash);
__ addu(hash, hash, character);
+ __ sll(at, hash, 10);
+ __ addu(hash, hash, at);
// hash ^= hash >> 6;
__ srl(at, hash, 6);
__ xor_(hash, hash, at);
@@ -5832,8 +5941,8 @@
void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm,
- Register hash,
- Register character) {
+ Register hash,
+ Register character) {
// hash += character;
__ addu(hash, hash, character);
// hash += hash << 10;
@@ -5846,7 +5955,7 @@
void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
- Register hash) {
+ Register hash) {
// hash += hash << 3;
__ sll(at, hash, 3);
__ addu(hash, hash, at);
@@ -5857,18 +5966,17 @@
__ sll(at, hash, 15);
__ addu(hash, hash, at);
- uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1;
- __ li(at, Operand(kHashShiftCutOffMask));
+ __ li(at, Operand(String::kHashBitMask));
__ and_(hash, hash, at);
// if (hash == 0) hash = 27;
- __ ori(at, zero_reg, 27);
+ __ ori(at, zero_reg, StringHasher::kZeroHash);
__ movz(hash, at, hash);
}
void SubStringStub::Generate(MacroAssembler* masm) {
- Label sub_string_runtime;
+ Label runtime;
// Stack frame on entry.
// ra: return address
// sp[0]: to
@@ -5886,53 +5994,35 @@
static const int kFromOffset = 1 * kPointerSize;
static const int kStringOffset = 2 * kPointerSize;
- Register to = t2;
- Register from = t3;
-
- // Check bounds and smi-ness.
- __ lw(to, MemOperand(sp, kToOffset));
- __ lw(from, MemOperand(sp, kFromOffset));
+ __ lw(a2, MemOperand(sp, kToOffset));
+ __ lw(a3, MemOperand(sp, kFromOffset));
STATIC_ASSERT(kFromOffset == kToOffset + 4);
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
- __ JumpIfNotSmi(from, &sub_string_runtime);
- __ JumpIfNotSmi(to, &sub_string_runtime);
+ // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is
+ // safe in this case.
+ __ JumpIfSmi(a2, &runtime, at, USE_DELAY_SLOT);
+ __ SmiUntag(a2);
+ __ JumpIfSmi(a3, &runtime, at, USE_DELAY_SLOT);
+ __ SmiUntag(a3);
- __ sra(a3, from, kSmiTagSize); // Remove smi tag.
- __ sra(t5, to, kSmiTagSize); // Remove smi tag.
+ // Both a2 and a3 are untagged integers.
- // a3: from index (untagged smi)
- // t5: to index (untagged smi)
-
- __ Branch(&sub_string_runtime, lt, a3, Operand(zero_reg)); // From < 0.
+ __ Branch(&runtime, lt, a3, Operand(zero_reg)); // From < 0.
__ subu(a2, t5, a3);
- __ Branch(&sub_string_runtime, gt, a3, Operand(t5)); // Fail if from > to.
+ __ Branch(&runtime, gt, a3, Operand(t5)); // Fail if from > to.
- // Special handling of sub-strings of length 1 and 2. One character strings
- // are handled in the runtime system (looked up in the single character
- // cache). Two character strings are looked for in the symbol cache in
- // generated code.
- __ Branch(&sub_string_runtime, lt, a2, Operand(2));
-
- // Both to and from are smis.
-
- // a2: result string length
- // a3: from index (untagged smi)
- // t2: (a.k.a. to): to (smi)
- // t3: (a.k.a. from): from offset (smi)
- // t5: to index (untagged smi)
-
- // Make sure first argument is a sequential (or flat) string.
+ // Make sure first argument is a string.
__ lw(v0, MemOperand(sp, kStringOffset));
- __ Branch(&sub_string_runtime, eq, v0, Operand(kSmiTagMask));
+ __ Branch(&runtime, eq, v0, Operand(kSmiTagMask));
__ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
__ And(t4, v0, Operand(kIsNotStringMask));
- __ Branch(&sub_string_runtime, ne, t4, Operand(zero_reg));
+ __ Branch(&runtime, ne, t4, Operand(zero_reg));
// Short-cut for the case of trivial substring.
Label return_v0;
@@ -5942,74 +6032,16 @@
__ sra(t0, t0, 1);
__ Branch(&return_v0, eq, a2, Operand(t0));
- Label create_slice;
- if (FLAG_string_slices) {
- __ Branch(&create_slice, ge, a2, Operand(SlicedString::kMinLength));
- }
-
- // v0: original string
- // a1: instance type
- // a2: result string length
- // a3: from index (untagged smi)
- // t2: (a.k.a. to): to (smi)
- // t3: (a.k.a. from): from offset (smi)
- // t5: to index (untagged smi)
-
- Label seq_string;
- __ And(t0, a1, Operand(kStringRepresentationMask));
- STATIC_ASSERT(kSeqStringTag < kConsStringTag);
- STATIC_ASSERT(kConsStringTag < kExternalStringTag);
- STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
-
- // Slices and external strings go to runtime.
- __ Branch(&sub_string_runtime, gt, t0, Operand(kConsStringTag));
-
- // Sequential strings are handled directly.
- __ Branch(&seq_string, lt, t0, Operand(kConsStringTag));
-
- // Cons string. Try to recurse (once) on the first substring.
- // (This adds a little more generality than necessary to handle flattened
- // cons strings, but not much).
- __ lw(v0, FieldMemOperand(v0, ConsString::kFirstOffset));
- __ lw(t0, FieldMemOperand(v0, HeapObject::kMapOffset));
- __ lbu(a1, FieldMemOperand(t0, Map::kInstanceTypeOffset));
- STATIC_ASSERT(kSeqStringTag == 0);
- // Cons, slices and external strings go to runtime.
- __ Branch(&sub_string_runtime, ne, a1, Operand(kStringRepresentationMask));
-
- // Definitly a sequential string.
- __ bind(&seq_string);
-
- // v0: original string
- // a1: instance type
- // a2: result string length
- // a3: from index (untagged smi)
- // t2: (a.k.a. to): to (smi)
- // t3: (a.k.a. from): from offset (smi)
- // t5: to index (untagged smi)
-
- __ lw(t0, FieldMemOperand(v0, String::kLengthOffset));
- __ Branch(&sub_string_runtime, lt, t0, Operand(to)); // Fail if to > length.
- to = no_reg;
-
- // v0: original string or left hand side of the original cons string.
- // a1: instance type
- // a2: result string length
- // a3: from index (untagged smi)
- // t3: (a.k.a. from): from offset (smi)
- // t5: to index (untagged smi)
-
- // Check for flat ASCII string.
- Label non_ascii_flat;
- STATIC_ASSERT(kTwoByteStringTag == 0);
-
- __ And(t4, a1, Operand(kStringEncodingMask));
- __ Branch(&non_ascii_flat, eq, t4, Operand(zero_reg));
Label result_longer_than_two;
- __ Branch(&result_longer_than_two, gt, a2, Operand(2));
+ // Check for special case of two character ASCII string, in which case
+ // we do a lookup in the symbol table first.
+ __ li(t0, 2);
+ __ Branch(&result_longer_than_two, gt, a2, Operand(t0));
+ __ Branch(&runtime, lt, a2, Operand(t0));
- // Sub string of length 2 requested.
+ __ JumpIfInstanceTypeIsNotSequentialAscii(a1, a1, &runtime);
+
// Get the two characters forming the sub string.
__ Addu(v0, v0, Operand(a3));
__ lbu(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
@@ -6019,31 +6051,126 @@
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
masm, a3, t0, a1, t1, t2, t3, t4, &make_two_character_string);
- Counters* counters = masm->isolate()->counters();
__ jmp(&return_v0);
// a2: result string length.
// a3: two characters combined into halfword in little endian byte order.
__ bind(&make_two_character_string);
- __ AllocateAsciiString(v0, a2, t0, t1, t4, &sub_string_runtime);
+ __ AllocateAsciiString(v0, a2, t0, t1, t4, &runtime);
__ sh(a3, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
__ jmp(&return_v0);
__ bind(&result_longer_than_two);
- // Locate 'from' character of string.
- __ Addu(t1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- __ sra(t4, from, 1);
- __ Addu(t1, t1, t4);
+ // Deal with different string types: update the index if necessary
+ // and put the underlying string into t1.
+ // v0: original string
+ // a1: instance type
+ // a2: length
+ // a3: from index (untagged)
+ Label underlying_unpacked, sliced_string, seq_or_external_string;
+ // If the string is not indirect, it can only be sequential or external.
+ STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+ STATIC_ASSERT(kIsIndirectStringMask != 0);
+ __ And(t0, a1, Operand(kIsIndirectStringMask));
+ __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, t0, Operand(zero_reg));
- // Allocate the result.
- __ AllocateAsciiString(v0, a2, t4, t0, a1, &sub_string_runtime);
+ __ And(t0, a1, Operand(kSlicedNotConsMask));
+ __ Branch(&sliced_string, ne, t0, Operand(zero_reg));
+ // Cons string. Check whether it is flat, then fetch first part.
+ __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
+ __ LoadRoot(t0, Heap::kEmptyStringRootIndex);
+ __ Branch(&runtime, ne, t1, Operand(t0));
+ __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
+ // Update instance type.
+ __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
+ __ jmp(&underlying_unpacked);
- // v0: result string
- // a2: result string length
- // a3: from index (untagged smi)
- // t1: first character of substring to copy
- // t3: (a.k.a. from): from offset (smi)
+ __ bind(&sliced_string);
+ // Sliced string. Fetch parent and correct start index by offset.
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ sra(t1, t1, 1);
+ __ Addu(a3, a3, t1);
+ __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ // Update instance type.
+ __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset));
+ __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset));
+ __ jmp(&underlying_unpacked);
+
+ __ bind(&seq_or_external_string);
+ // Sequential or external string. Just move string to the expected register.
+ __ mov(t1, v0);
+
+ __ bind(&underlying_unpacked);
+
+ if (FLAG_string_slices) {
+ Label copy_routine;
+ // t1: underlying subject string
+ // a1: instance type of underlying subject string
+ // a2: length
+ // a3: adjusted start index (untagged)
+ // Short slice. Copy instead of slicing.
+ __ Branch(©_routine, lt, a2, Operand(SlicedString::kMinLength));
+ // Allocate new sliced string. At this point we do not reload the instance
+ // type including the string encoding because we simply rely on the info
+ // provided by the original string. It does not matter if the original
+ // string's encoding is wrong because we always have to recheck encoding of
+ // the newly created string's parent anyways due to externalized strings.
+ Label two_byte_slice, set_slice_header;
+ STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+ __ And(t0, a1, Operand(kStringEncodingMask));
+ __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg));
+ __ AllocateAsciiSlicedString(v0, a2, t2, t3, &runtime);
+ __ jmp(&set_slice_header);
+ __ bind(&two_byte_slice);
+ __ AllocateTwoByteSlicedString(v0, a2, t2, t3, &runtime);
+ __ bind(&set_slice_header);
+ __ sll(a3, a3, 1);
+ __ sw(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
+ __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
+ __ jmp(&return_v0);
+
+ __ bind(©_routine);
+ }
+
+ // t1: underlying subject string
+ // a1: instance type of underlying subject string
+ // a2: length
+ // a3: adjusted start index (untagged)
+ Label two_byte_sequential, sequential_string, allocate_result;
+ STATIC_ASSERT(kExternalStringTag != 0);
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ And(t0, a1, Operand(kExternalStringTag));
+ __ Branch(&sequential_string, eq, t0, Operand(zero_reg));
+
+ // Handle external string.
+ // Rule out short external strings.
+ STATIC_CHECK(kShortExternalStringTag != 0);
+ __ And(t0, a1, Operand(kShortExternalStringTag));
+ __ Branch(&runtime, ne, t0, Operand(zero_reg));
+ __ lw(t1, FieldMemOperand(t1, ExternalString::kResourceDataOffset));
+ // t1 already points to the first character of underlying string.
+ __ jmp(&allocate_result);
+
+ __ bind(&sequential_string);
+ // Locate first character of underlying subject string.
+ STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
+ __ Addu(t1, t1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+
+ __ bind(&allocate_result);
+ // Sequential acii string. Allocate the result.
+ STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
+ __ And(t0, a1, Operand(kStringEncodingMask));
+ __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg));
+
+ // Allocate and copy the resulting ASCII string.
+ __ AllocateAsciiString(v0, a2, t0, t2, t3, &runtime);
+
+ // Locate first character of substring to copy.
+ __ Addu(t1, t1, a3);
+
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
@@ -6056,30 +6183,17 @@
masm, a1, t1, a2, a3, t0, t2, t3, t4, COPY_ASCII | DEST_ALWAYS_ALIGNED);
__ jmp(&return_v0);
- __ bind(&non_ascii_flat);
- // a2: result string length
- // t1: string
- // t3: (a.k.a. from): from offset (smi)
- // Check for flat two byte string.
+ // Allocate and copy the resulting two-byte string.
+ __ bind(&two_byte_sequential);
+ __ AllocateTwoByteString(v0, a2, t0, t2, t3, &runtime);
- // Locate 'from' character of string.
- __ Addu(t1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // As "from" is a smi it is 2 times the value which matches the size of a two
- // byte character.
+ // Locate first character of substring to copy.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
- __ Addu(t1, t1, Operand(from));
-
- // Allocate the result.
- __ AllocateTwoByteString(v0, a2, a1, a3, t0, &sub_string_runtime);
-
- // v0: result string
- // a2: result string length
- // t1: first character of substring to copy
+ __ sll(t0, a3, 1);
+ __ Addu(t1, t1, t0);
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- from = no_reg;
-
// v0: result string.
// a1: first character of result.
// a2: result length.
@@ -6087,75 +6201,14 @@
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
StringHelper::GenerateCopyCharactersLong(
masm, a1, t1, a2, a3, t0, t2, t3, t4, DEST_ALWAYS_ALIGNED);
- __ jmp(&return_v0);
-
- if (FLAG_string_slices) {
- __ bind(&create_slice);
- // v0: original string
- // a1: instance type
- // a2: length
- // a3: from index (untagged smi)
- // t2 (a.k.a. to): to (smi)
- // t3 (a.k.a. from): from offset (smi)
- Label allocate_slice, sliced_string, seq_or_external_string;
- // If the string is not indirect, it can only be sequential or external.
- STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
- STATIC_ASSERT(kIsIndirectStringMask != 0);
- __ And(t4, a1, Operand(kIsIndirectStringMask));
- // External string. Jump to runtime.
- __ Branch(&seq_or_external_string, eq, t4, Operand(zero_reg));
-
- __ And(t4, a1, Operand(kSlicedNotConsMask));
- __ Branch(&sliced_string, ne, t4, Operand(zero_reg));
- // Cons string. Check whether it is flat, then fetch first part.
- __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset));
- __ LoadRoot(t5, Heap::kEmptyStringRootIndex);
- __ Branch(&sub_string_runtime, ne, t1, Operand(t5));
- __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset));
- __ jmp(&allocate_slice);
-
- __ bind(&sliced_string);
- // Sliced string. Fetch parent and correct start index by offset.
- __ lw(t1, FieldMemOperand(v0, SlicedString::kOffsetOffset));
- __ addu(t3, t3, t1);
- __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
- __ jmp(&allocate_slice);
-
- __ bind(&seq_or_external_string);
- // Sequential or external string. Just move string to the correct register.
- __ mov(t1, v0);
-
- __ bind(&allocate_slice);
- // a1: instance type of original string
- // a2: length
- // t1: underlying subject string
- // t3 (a.k.a. from): from offset (smi)
- // Allocate new sliced string. At this point we do not reload the instance
- // type including the string encoding because we simply rely on the info
- // provided by the original string. It does not matter if the original
- // string's encoding is wrong because we always have to recheck encoding of
- // the newly created string's parent anyways due to externalized strings.
- Label two_byte_slice, set_slice_header;
- STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
- STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
- __ And(t4, a1, Operand(kStringEncodingMask));
- __ Branch(&two_byte_slice, eq, t4, Operand(zero_reg));
- __ AllocateAsciiSlicedString(v0, a2, a3, t0, &sub_string_runtime);
- __ jmp(&set_slice_header);
- __ bind(&two_byte_slice);
- __ AllocateTwoByteSlicedString(v0, a2, a3, t0, &sub_string_runtime);
- __ bind(&set_slice_header);
- __ sw(t3, FieldMemOperand(v0, SlicedString::kOffsetOffset));
- __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset));
- }
__ bind(&return_v0);
+ Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->sub_string_native(), 1, a3, t0);
- __ Addu(sp, sp, Operand(3 * kPointerSize));
- __ Ret();
+ __ DropAndRet(3);
// Just jump to runtime to create the sub string.
- __ bind(&sub_string_runtime);
+ __ bind(&runtime);
__ TailCallRuntime(Runtime::kSubString, 3, 1);
}
@@ -6313,7 +6366,7 @@
void StringAddStub::Generate(MacroAssembler* masm) {
- Label string_add_runtime, call_builtin;
+ Label call_runtime, call_builtin;
Builtins::JavaScript builtin_id = Builtins::ADD;
Counters* counters = masm->isolate()->counters();
@@ -6328,7 +6381,7 @@
// Make sure that both arguments are strings if not known in advance.
if (flags_ == NO_STRING_ADD_FLAGS) {
- __ JumpIfEitherSmi(a0, a1, &string_add_runtime);
+ __ JumpIfEitherSmi(a0, a1, &call_runtime);
// Load instance types.
__ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
__ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset));
@@ -6338,7 +6391,7 @@
// If either is not a string, go to runtime.
__ Or(t4, t0, Operand(t1));
__ And(t4, t4, Operand(kIsNotStringMask));
- __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg));
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
} else {
// Here at least one of the arguments is definitely a string.
// We convert the one that is not known to be a string.
@@ -6377,8 +6430,7 @@
__ Branch(&strings_not_empty, ne, t4, Operand(zero_reg));
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
__ bind(&strings_not_empty);
}
@@ -6411,7 +6463,7 @@
__ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
}
__ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3,
- &string_add_runtime);
+ &call_runtime);
// Get the two characters forming the sub string.
__ lbu(a2, FieldMemOperand(a0, SeqAsciiString::kHeaderSize));
@@ -6421,10 +6473,9 @@
// just allocate a new one.
Label make_two_character_string;
StringHelper::GenerateTwoCharacterSymbolTableProbe(
- masm, a2, a3, t2, t3, t0, t1, t4, &make_two_character_string);
+ masm, a2, a3, t2, t3, t0, t1, t5, &make_two_character_string);
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
__ bind(&make_two_character_string);
// Resulting string has length 2 and first chars of two strings
@@ -6433,21 +6484,20 @@
// halfword store instruction (which assumes that processor is
// in a little endian mode).
__ li(t2, Operand(2));
- __ AllocateAsciiString(v0, t2, t0, t1, t4, &string_add_runtime);
+ __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
__ sh(a2, FieldMemOperand(v0, SeqAsciiString::kHeaderSize));
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
__ bind(&longer_than_two);
// Check if resulting string will be flat.
__ Branch(&string_add_flat_result, lt, t2,
- Operand(String::kMinNonFlatLength));
+ Operand(ConsString::kMinLength));
// Handle exceptionally long strings in the runtime system.
STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
ASSERT(IsPowerOf2(String::kMaxLength + 1));
// kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
- __ Branch(&string_add_runtime, hs, t2, Operand(String::kMaxLength + 1));
+ __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1));
// If result is not supposed to be flat, allocate a cons string object.
// If both strings are ASCII the result is an ASCII cons string.
@@ -6459,22 +6509,20 @@
}
Label non_ascii, allocated, ascii_data;
STATIC_ASSERT(kTwoByteStringTag == 0);
- // Branch to non_ascii if either string-encoding field is zero (non-ascii).
+ // Branch to non_ascii if either string-encoding field is zero (non-ASCII).
__ And(t4, t0, Operand(t1));
__ And(t4, t4, Operand(kStringEncodingMask));
__ Branch(&non_ascii, eq, t4, Operand(zero_reg));
// Allocate an ASCII cons string.
__ bind(&ascii_data);
- __ AllocateAsciiConsString(t3, t2, t0, t1, &string_add_runtime);
+ __ AllocateAsciiConsString(v0, t2, t0, t1, &call_runtime);
__ bind(&allocated);
// Fill the fields of the cons string.
- __ sw(a0, FieldMemOperand(t3, ConsString::kFirstOffset));
- __ sw(a1, FieldMemOperand(t3, ConsString::kSecondOffset));
- __ mov(v0, t3);
+ __ sw(a0, FieldMemOperand(v0, ConsString::kFirstOffset));
+ __ sw(a1, FieldMemOperand(v0, ConsString::kSecondOffset));
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
__ bind(&non_ascii);
// At least one of the strings is two-byte. Check whether it happens
@@ -6492,11 +6540,13 @@
__ Branch(&ascii_data, eq, t0, Operand(kAsciiStringTag | kAsciiDataHintTag));
// Allocate a two byte cons string.
- __ AllocateTwoByteConsString(t3, t2, t0, t1, &string_add_runtime);
+ __ AllocateTwoByteConsString(v0, t2, t0, t1, &call_runtime);
__ Branch(&allocated);
- // Handle creating a flat result. First check that both strings are
- // sequential and that they have the same encoding.
+ // We cannot encounter sliced strings or cons strings here since:
+ STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
+ // Handle creating a flat result from either external or sequential strings.
+ // Locate the first characters' locations.
// a0: first string
// a1: second string
// a2: length of first string
@@ -6504,6 +6554,7 @@
// t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
// t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
// t2: sum of lengths.
+ Label first_prepared, second_prepared;
__ bind(&string_add_flat_result);
if (flags_ != NO_STRING_ADD_FLAGS) {
__ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset));
@@ -6511,101 +6562,86 @@
__ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset));
__ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset));
}
- // Check that both strings are sequential, meaning that we
- // branch to runtime if either string tag is non-zero.
- STATIC_ASSERT(kSeqStringTag == 0);
- __ Or(t4, t0, Operand(t1));
- __ And(t4, t4, Operand(kStringRepresentationMask));
- __ Branch(&string_add_runtime, ne, t4, Operand(zero_reg));
+ // Check whether both strings have same encoding
+ __ Xor(t3, t0, Operand(t1));
+ __ And(t3, t3, Operand(kStringEncodingMask));
+ __ Branch(&call_runtime, ne, t3, Operand(zero_reg));
- // Now check if both strings have the same encoding (ASCII/Two-byte).
- // a0: first string
- // a1: second string
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ And(t4, t0, Operand(kStringRepresentationMask));
+
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
+ Label skip_first_add;
+ __ Branch(&skip_first_add, ne, t4, Operand(zero_reg));
+ __ Branch(USE_DELAY_SLOT, &first_prepared);
+ __ addiu(t3, a0, SeqAsciiString::kHeaderSize - kHeapObjectTag);
+ __ bind(&skip_first_add);
+ // External string: rule out short external string and load string resource.
+ STATIC_ASSERT(kShortExternalStringTag != 0);
+ __ And(t4, t0, Operand(kShortExternalStringMask));
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
+ __ lw(t3, FieldMemOperand(a0, ExternalString::kResourceDataOffset));
+ __ bind(&first_prepared);
+
+ STATIC_ASSERT(kSeqStringTag == 0);
+ __ And(t4, t1, Operand(kStringRepresentationMask));
+ STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
+ Label skip_second_add;
+ __ Branch(&skip_second_add, ne, t4, Operand(zero_reg));
+ __ Branch(USE_DELAY_SLOT, &second_prepared);
+ __ addiu(a1, a1, SeqAsciiString::kHeaderSize - kHeapObjectTag);
+ __ bind(&skip_second_add);
+ // External string: rule out short external string and load string resource.
+ STATIC_ASSERT(kShortExternalStringTag != 0);
+ __ And(t4, t1, Operand(kShortExternalStringMask));
+ __ Branch(&call_runtime, ne, t4, Operand(zero_reg));
+ __ lw(a1, FieldMemOperand(a1, ExternalString::kResourceDataOffset));
+ __ bind(&second_prepared);
+
+ Label non_ascii_string_add_flat_result;
+ // t3: first character of first string
+ // a1: first character of second string
// a2: length of first string
// a3: length of second string
- // t0: first string instance type
- // t1: second string instance type
// t2: sum of lengths.
- Label non_ascii_string_add_flat_result;
- ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test.
- __ xor_(t3, t1, t0);
- __ And(t3, t3, Operand(kStringEncodingMask));
- __ Branch(&string_add_runtime, ne, t3, Operand(zero_reg));
- // And see if it's ASCII (0) or two-byte (1).
- __ And(t3, t0, Operand(kStringEncodingMask));
- __ Branch(&non_ascii_string_add_flat_result, eq, t3, Operand(zero_reg));
+ // Both strings have the same encoding.
+ STATIC_ASSERT(kTwoByteStringTag == 0);
+ __ And(t4, t1, Operand(kStringEncodingMask));
+ __ Branch(&non_ascii_string_add_flat_result, eq, t4, Operand(zero_reg));
- // Both strings are sequential ASCII strings. We also know that they are
- // short (since the sum of the lengths is less than kMinNonFlatLength).
- // t2: length of resulting flat string
- __ AllocateAsciiString(t3, t2, t0, t1, t4, &string_add_runtime);
- // Locate first character of result.
- __ Addu(t2, t3, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // Locate first character of first argument.
- __ Addu(a0, a0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // a0: first character of first string.
- // a1: second string.
+ __ AllocateAsciiString(v0, t2, t0, t1, t5, &call_runtime);
+ __ Addu(t2, v0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
+ // v0: result string.
+ // t3: first character of first string.
+ // a1: first character of second string
// a2: length of first string.
// a3: length of second string.
// t2: first character of result.
- // t3: result string.
- StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, true);
- // Load second argument and locate first character.
- __ Addu(a1, a1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
- // a1: first character of second string.
- // a3: length of second string.
+ StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, true);
// t2: next character of result.
- // t3: result string.
StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, true);
- __ mov(v0, t3);
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
__ bind(&non_ascii_string_add_flat_result);
- // Both strings are sequential two byte strings.
- // a0: first string.
- // a1: second string.
- // a2: length of first string.
- // a3: length of second string.
- // t2: sum of length of strings.
- __ AllocateTwoByteString(t3, t2, t0, t1, t4, &string_add_runtime);
- // a0: first string.
- // a1: second string.
- // a2: length of first string.
- // a3: length of second string.
- // t3: result string.
-
- // Locate first character of result.
- __ Addu(t2, t3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
- // Locate first character of first argument.
- __ Addu(a0, a0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
-
- // a0: first character of first string.
- // a1: second string.
+ __ AllocateTwoByteString(v0, t2, t0, t1, t5, &call_runtime);
+ __ Addu(t2, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
+ // v0: result string.
+ // t3: first character of first string.
+ // a1: first character of second string.
// a2: length of first string.
// a3: length of second string.
// t2: first character of result.
- // t3: result string.
- StringHelper::GenerateCopyCharacters(masm, t2, a0, a2, t0, false);
-
- // Locate first character of second argument.
- __ Addu(a1, a1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
-
- // a1: first character of second string.
- // a3: length of second string.
- // t2: next character of result (after copy of first string).
- // t3: result string.
+ StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false);
+ // t2: next character of result.
StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false);
- __ mov(v0, t3);
__ IncrementCounter(counters->string_add_native(), 1, a2, a3);
- __ Addu(sp, sp, Operand(2 * kPointerSize));
- __ Ret();
+ __ DropAndRet(2);
// Just jump to runtime to add the two strings.
- __ bind(&string_add_runtime);
+ __ bind(&call_runtime);
__ TailCallRuntime(Runtime::kStringAdd, 2, 1);
if (call_builtin.is_linked()) {
@@ -6870,26 +6906,39 @@
}
-void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
- __ Push(a1, a0);
- __ push(ra);
+void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
+ Label miss;
+ __ And(a2, a1, a0);
+ __ JumpIfSmi(a2, &miss);
+ __ lw(a2, FieldMemOperand(a0, HeapObject::kMapOffset));
+ __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
+ __ Branch(&miss, ne, a2, Operand(known_map_));
+ __ Branch(&miss, ne, a3, Operand(known_map_));
- // Call the runtime system in a fresh internal frame.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss),
- masm->isolate());
+ __ Ret(USE_DELAY_SLOT);
+ __ subu(v0, a0, a1);
+
+ __ bind(&miss);
+ GenerateMiss(masm);
+}
+
+void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
{
+ // Call the runtime system in a fresh internal frame.
+ ExternalReference miss =
+ ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a1, a0);
+ __ push(ra);
+ __ Push(a1, a0);
__ li(t0, Operand(Smi::FromInt(op_)));
__ push(t0);
__ CallExternalReference(miss, 3);
+ // Compute the entry point of the rewritten stub.
+ __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
+ // Restore registers.
+ __ Pop(a1, a0, ra);
}
- // Compute the entry point of the rewritten stub.
- __ Addu(a2, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
- // Restore registers.
- __ pop(ra);
- __ pop(a0);
- __ pop(a1);
__ Jump(a2);
}
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index d0a7af5..7d654f6 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -302,7 +302,7 @@
return kRegisterType;
};
break;
- // 16 bits Immediate type instructions. eg: addi dest, src, imm16.
+ // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
case REGIMM:
case BEQ:
case BNE:
@@ -337,7 +337,7 @@
case SWC1:
case SDC1:
return kImmediateType;
- // 26 bits immediate type instructions. eg: j imm26.
+ // 26 bits immediate type instructions. e.g.: j imm26.
case J:
case JAL:
return kJumpType;
diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h
index 4f486c1..d62a890 100644
--- a/src/mips/constants-mips.h
+++ b/src/mips/constants-mips.h
@@ -125,7 +125,7 @@
struct RegisterAlias {
int reg;
- const char *name;
+ const char* name;
};
static const int32_t kMaxValue = 0x7fffffff;
@@ -147,7 +147,7 @@
struct RegisterAlias {
int creg;
- const char *name;
+ const char* name;
};
private:
@@ -747,7 +747,7 @@
// Say if the instruction should not be used in a branch delay slot.
bool IsForbiddenInBranchDelay() const;
- // Say if the instruction 'links'. eg: jal, bal.
+ // Say if the instruction 'links'. e.g. jal, bal.
bool IsLinkingInstruction() const;
// Say if the instruction is a break or a trap.
bool IsTrap() const;
diff --git a/src/mips/cpu-mips.cc b/src/mips/cpu-mips.cc
index 5c3912e..93ebeda 100644
--- a/src/mips/cpu-mips.cc
+++ b/src/mips/cpu-mips.cc
@@ -47,7 +47,7 @@
namespace internal {
-void CPU::Setup() {
+void CPU::SetUp() {
CpuFeatures::Probe();
}
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index a27c61c..26a4063 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -218,12 +218,13 @@
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::FRAME == opcode);
+ ASSERT(Translation::JS_FRAME == opcode);
unsigned node_id = iterator.Next();
USE(node_id);
ASSERT(node_id == ast_id);
@@ -259,9 +260,7 @@
output_ = new FrameDescription*[1];
output_[0] = new(output_frame_size) FrameDescription(
output_frame_size, function_);
-#ifdef DEBUG
- output_[0]->SetKind(Code::OPTIMIZED_FUNCTION);
-#endif
+ output_[0]->SetFrameType(StackFrame::JAVA_SCRIPT);
// Clear the incoming parameters in the optimized frame to avoid
// confusing the garbage collector.
@@ -326,7 +325,7 @@
output_[0] = input_;
output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
} else {
- // Setup the frame pointer and the context pointer.
+ // 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()));
@@ -349,15 +348,115 @@
}
+void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
+ int frame_index) {
+ JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
+ unsigned height = iterator->Next();
+ unsigned height_in_bytes = height * kPointerSize;
+ if (FLAG_trace_deopt) {
+ PrintF(" translating arguments adaptor => height=%d\n", height_in_bytes);
+ }
+
+ unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
+ unsigned input_frame_size = input_->GetFrameSize();
+ unsigned output_frame_size = height_in_bytes + fixed_frame_size;
+
+ // Allocate and store the output frame description.
+ FrameDescription* output_frame =
+ new(output_frame_size) FrameDescription(output_frame_size, function);
+ output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
+
+ // Arguments adaptor can not be topmost or bottommost.
+ ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
+ ASSERT(output_[frame_index] == NULL);
+ output_[frame_index] = output_frame;
+
+ // The top address of the frame is computed from the previous
+ // frame's top and this frame's size.
+ uint32_t top_address;
+ top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
+ output_frame->SetTop(top_address);
+
+ // Compute the incoming parameter translation.
+ int parameter_count = height;
+ unsigned output_offset = output_frame_size;
+ unsigned input_offset = input_frame_size;
+ for (int i = 0; i < parameter_count; ++i) {
+ output_offset -= kPointerSize;
+ DoTranslateCommand(iterator, frame_index, output_offset);
+ }
+ input_offset -= (parameter_count * kPointerSize);
+
+ // Read caller's PC from the previous frame.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ intptr_t callers_pc = output_[frame_index - 1]->GetPc();
+ output_frame->SetFrameSlot(output_offset, callers_pc);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
+ top_address + output_offset, output_offset, callers_pc);
+ }
+
+ // Read caller's FP from the previous frame, and set this frame's FP.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ intptr_t value = output_[frame_index - 1]->GetFp();
+ output_frame->SetFrameSlot(output_offset, value);
+ intptr_t fp_value = top_address + output_offset;
+ output_frame->SetFp(fp_value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
+ fp_value, output_offset, value);
+ }
+
+ // A marker value is used in place of the context.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ intptr_t context = reinterpret_cast<intptr_t>(
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ output_frame->SetFrameSlot(output_offset, context);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context (adaptor sentinel)\n",
+ top_address + output_offset, output_offset, context);
+ }
+
+ // The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ value = reinterpret_cast<intptr_t>(function);
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
+ top_address + output_offset, output_offset, value);
+ }
+
+ // Number of incoming arguments.
+ output_offset -= kPointerSize;
+ input_offset -= kPointerSize;
+ value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
+ output_frame->SetFrameSlot(output_offset, value);
+ if (FLAG_trace_deopt) {
+ PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
+ top_address + output_offset, output_offset, value, height - 1);
+ }
+
+ ASSERT(0 == output_offset);
+
+ Builtins* builtins = isolate_->builtins();
+ Code* adaptor_trampoline =
+ builtins->builtin(Builtins::kArgumentsAdaptorTrampoline);
+ uint32_t pc = reinterpret_cast<uint32_t>(
+ adaptor_trampoline->instruction_start() +
+ isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
+ output_frame->SetPc(pc);
+}
+
+
// This code is very similar to ia32/arm code, but relies on register names
// (fp, sp) and how the frame is laid out.
-void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
- int frame_index) {
+void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
+ int frame_index) {
// Read the ast node id, function, and frame height for this output frame.
- Translation::Opcode opcode =
- static_cast<Translation::Opcode>(iterator->Next());
- USE(opcode);
- ASSERT(Translation::FRAME == opcode);
int node_id = iterator->Next();
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
unsigned height = iterator->Next();
@@ -377,9 +476,7 @@
// Allocate and store the output frame description.
FrameDescription* output_frame =
new(output_frame_size) FrameDescription(output_frame_size, function);
-#ifdef DEBUG
- output_frame->SetKind(Code::FUNCTION);
-#endif
+ output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
bool is_bottommost = (0 == frame_index);
bool is_topmost = (output_count_ - 1 == frame_index);
@@ -733,10 +830,7 @@
}
}
- // Set up the roots register.
- ExternalReference roots_array_start =
- ExternalReference::roots_array_start(isolate);
- __ li(roots, Operand(roots_array_start));
+ __ InitializeRootRegister();
__ pop(at); // Get continuation, leave pc on stack.
__ pop(ra);
diff --git a/src/mips/frames-mips.h b/src/mips/frames-mips.h
index 9e626f3..2ed358a 100644
--- a/src/mips/frames-mips.h
+++ b/src/mips/frames-mips.h
@@ -195,6 +195,9 @@
class StandardFrameConstants : public AllStatic {
public:
+ // Fixed part of the frame consists of return address, caller fp,
+ // context and function.
+ static const int kFixedFrameSize = 4 * kPointerSize;
static const int kExpressionsOffset = -3 * kPointerSize;
static const int kMarkerOffset = -2 * kPointerSize;
static const int kContextOffset = -1 * kPointerSize;
@@ -230,6 +233,8 @@
class ArgumentsAdaptorFrameConstants : public AllStatic {
public:
static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
+ static const int kFrameSize =
+ StandardFrameConstants::kFixedFrameSize + kPointerSize;
};
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index f5b851d..da3be4c 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -125,7 +125,7 @@
// function.
//
// The live registers are:
-// o a1: the JS function object being called (ie, ourselves)
+// o a1: the JS function object being called (i.e. ourselves)
// o cp: our context
// o fp: our caller's frame pointer
// o sp: stack pointer
@@ -1017,7 +1017,7 @@
__ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumerationIndexOffset));
__ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset));
- // Setup the four remaining stack slots.
+ // Set up the four remaining stack slots.
__ push(v0); // Map.
__ lw(a1, FieldMemOperand(a2, FixedArray::kLengthOffset));
__ li(a0, Operand(Smi::FromInt(0)));
@@ -2958,8 +2958,12 @@
ASSERT(args->length() == 2);
VisitForStackValue(args->at(0));
VisitForStackValue(args->at(1));
- MathPowStub stub;
- __ CallStub(&stub);
+ if (CpuFeatures::IsSupported(FPU)) {
+ MathPowStub stub(MathPowStub::ON_STACK);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kMath_pow, 2);
+ }
context()->Plug(v0);
}
@@ -3651,7 +3655,7 @@
// One-character separator case.
__ bind(&one_char_separator);
- // Replace separator with its ascii character value.
+ // Replace separator with its ASCII character value.
__ lbu(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
// Jump into the loop after the code that copies the separator, so the first
// element is not preceded by a separator.
@@ -3662,7 +3666,7 @@
// result_pos: the position to which we are currently copying characters.
// element: Current array element.
// elements_end: Array end.
- // separator: Single separator ascii char (in lower byte).
+ // separator: Single separator ASCII char (in lower byte).
// Copy the separator character to the result.
__ sb(separator, MemOperand(result_pos));
diff --git a/src/mips/ic-mips.cc b/src/mips/ic-mips.cc
index b057695..3489936 100644
--- a/src/mips/ic-mips.cc
+++ b/src/mips/ic-mips.cc
@@ -868,22 +868,26 @@
// -- lr : return address
// -----------------------------------
Label slow, notin;
+ // Store address is returned in register (of MemOperand) mapped_location.
MemOperand mapped_location =
GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, ¬in, &slow);
__ sw(a0, mapped_location);
- __ Addu(t2, a3, t1);
__ mov(t5, a0);
- __ RecordWrite(a3, t2, t5, kRAHasNotBeenSaved, kDontSaveFPRegs);
+ ASSERT_EQ(mapped_location.offset(), 0);
+ __ RecordWrite(a3, mapped_location.rm(), t5,
+ kRAHasNotBeenSaved, kDontSaveFPRegs);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0); // (In delay slot) return the value stored in v0.
__ bind(¬in);
// The unmapped lookup expects that the parameter map is in a3.
+ // Store address is returned in register (of MemOperand) unmapped_location.
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
__ sw(a0, unmapped_location);
- __ Addu(t2, a3, t0);
__ mov(t5, a0);
- __ RecordWrite(a3, t2, t5, kRAHasNotBeenSaved, kDontSaveFPRegs);
+ ASSERT_EQ(unmapped_location.offset(), 0);
+ __ RecordWrite(a3, unmapped_location.rm(), t5,
+ kRAHasNotBeenSaved, kDontSaveFPRegs);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, a0); // (In delay slot) return the value stored in v0.
__ bind(&slow);
@@ -1029,19 +1033,32 @@
__ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset));
__ sra(at, t0, String::kHashShift);
__ xor_(a3, a3, at);
- __ And(a3, a3, Operand(KeyedLookupCache::kCapacityMask));
+ int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
+ __ And(a3, a3, Operand(mask));
// Load the key (consisting of map and symbol) from the cache and
// check for match.
+ Label load_in_object_property;
+ static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
+ Label hit_on_nth_entry[kEntriesPerBucket];
ExternalReference cache_keys =
ExternalReference::keyed_lookup_cache_keys(isolate);
__ li(t0, Operand(cache_keys));
__ sll(at, a3, kPointerSizeLog2 + 1);
__ addu(t0, t0, at);
- __ lw(t1, MemOperand(t0)); // Move t0 to symbol.
- __ Addu(t0, t0, Operand(kPointerSize));
+
+ for (int i = 0; i < kEntriesPerBucket - 1; i++) {
+ Label try_next_entry;
+ __ lw(t1, MemOperand(t0, kPointerSize * i * 2));
+ __ Branch(&try_next_entry, ne, a2, Operand(t1));
+ __ lw(t1, MemOperand(t0, kPointerSize * (i * 2 + 1)));
+ __ Branch(&hit_on_nth_entry[i], eq, a0, Operand(t1));
+ __ bind(&try_next_entry);
+ }
+
+ __ lw(t1, MemOperand(t0, kPointerSize * (kEntriesPerBucket - 1) * 2));
__ Branch(&slow, ne, a2, Operand(t1));
- __ lw(t1, MemOperand(t0));
+ __ lw(t1, MemOperand(t0, kPointerSize * ((kEntriesPerBucket - 1) * 2 + 1)));
__ Branch(&slow, ne, a0, Operand(t1));
// Get field offset.
@@ -1051,15 +1068,24 @@
// a3 : lookup cache index
ExternalReference cache_field_offsets =
ExternalReference::keyed_lookup_cache_field_offsets(isolate);
- __ li(t0, Operand(cache_field_offsets));
- __ sll(at, a3, kPointerSizeLog2);
- __ addu(at, t0, at);
- __ lw(t1, MemOperand(at));
- __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
- __ Subu(t1, t1, t2);
- __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
+
+ // Hit on nth entry.
+ for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
+ __ bind(&hit_on_nth_entry[i]);
+ __ li(t0, Operand(cache_field_offsets));
+ __ sll(at, a3, kPointerSizeLog2);
+ __ addu(at, t0, at);
+ __ lw(t1, MemOperand(at, kPointerSize * i));
+ __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
+ __ Subu(t1, t1, t2);
+ __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
+ if (i != 0) {
+ __ Branch(&load_in_object_property);
+ }
+ }
// Load in-object property.
+ __ bind(&load_in_object_property);
__ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
__ addu(t2, t2, t1); // Index from start of object.
__ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag.
@@ -1470,11 +1496,10 @@
// -- ra : return address
// -----------------------------------
//
- // This accepts as a receiver anything JSObject::SetElementsLength accepts
- // (currently anything except for external and pixel arrays which means
- // anything with elements of FixedArray type.), but currently is restricted
- // to JSArray.
- // Value must be a number, but only smis are accepted as the most common case.
+ // This accepts as a receiver anything JSArray::SetElementsLength accepts
+ // (currently anything except for external arrays which means anything with
+ // elements of FixedArray type). Value must be a number, but only smis are
+ // accepted as the most common case.
Label miss;
@@ -1496,6 +1521,10 @@
__ GetObjectType(scratch, scratch, scratch);
__ Branch(&miss, ne, scratch, Operand(FIXED_ARRAY_TYPE));
+ // Check that the array has fast properties, otherwise the length
+ // property might have been redefined.
+ // TODO(mstarzinger): Port this check to MIPS.
+
// Check that value is a smi.
__ JumpIfNotSmi(value, &miss);
@@ -1587,6 +1616,9 @@
rewritten = stub.GetCode();
} else {
ICCompareStub stub(op_, state);
+ if (state == KNOWN_OBJECTS) {
+ stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
+ }
rewritten = stub.GetCode();
}
set_target(*rewritten);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 848cf3e..e886c4a 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -291,7 +291,22 @@
if (op->IsRegister()) {
return ToRegister(op->index());
} else if (op->IsConstantOperand()) {
- __ li(scratch, ToOperand(op));
+ LConstantOperand* const_op = LConstantOperand::cast(op);
+ Handle<Object> literal = chunk_->LookupLiteral(const_op);
+ Representation r = chunk_->LookupLiteralRepresentation(const_op);
+ if (r.IsInteger32()) {
+ ASSERT(literal->IsNumber());
+ __ li(scratch, Operand(static_cast<int32_t>(literal->Number())));
+ } else if (r.IsDouble()) {
+ Abort("EmitLoadRegister: Unsupported double immediate.");
+ } else {
+ ASSERT(r.IsTagged());
+ if (literal->IsSmi()) {
+ __ li(scratch, Operand(literal));
+ } else {
+ __ LoadHeapObject(scratch, Handle<HeapObject>::cast(literal));
+ }
+ }
return scratch;
} else if (op->IsStackSlot() || op->IsArgument()) {
__ lw(scratch, ToMemOperand(op));
@@ -338,6 +353,18 @@
}
+Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
+ Handle<Object> literal = chunk_->LookupLiteral(op);
+ ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
+ return literal;
+}
+
+
+bool LCodeGen::IsInteger32(LConstantOperand* op) const {
+ return chunk_->LookupLiteralRepresentation(op).IsInteger32();
+}
+
+
int LCodeGen::ToInteger32(LConstantOperand* op) const {
Handle<Object> value = chunk_->LookupLiteral(op);
ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
@@ -420,7 +447,11 @@
WriteTranslation(environment->outer(), translation);
int closure_id = DefineDeoptimizationLiteral(environment->closure());
- translation->BeginFrame(environment->ast_id(), closure_id, height);
+ if (environment->is_arguments_adaptor()) {
+ translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
+ } else {
+ translation->BeginJSFrame(environment->ast_id(), closure_id, height);
+ }
for (int i = 0; i < translation_size; ++i) {
LOperand* value = environment->values()->at(i);
// spilled_registers_ and spilled_double_registers_ are either
@@ -546,10 +577,14 @@
// |>------------ translation_size ------------<|
int frame_count = 0;
+ int jsframe_count = 0;
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
++frame_count;
+ if (!e->is_arguments_adaptor()) {
+ ++jsframe_count;
+ }
}
- Translation translation(&translations_, frame_count);
+ Translation translation(&translations_, frame_count, jsframe_count);
WriteTranslation(environment, &translation);
int deoptimization_index = deoptimizations_.length();
int pc_offset = masm()->pc_offset();
@@ -1162,8 +1197,13 @@
void LCodeGen::DoConstantT(LConstantT* instr) {
- ASSERT(instr->result()->IsRegister());
- __ li(ToRegister(instr->result()), Operand(instr->value()));
+ Handle<Object> value = instr->value();
+ if (value->IsSmi()) {
+ __ li(ToRegister(instr->result()), Operand(value));
+ } else {
+ __ LoadHeapObject(ToRegister(instr->result()),
+ Handle<HeapObject>::cast(value));
+ }
}
@@ -1830,9 +1870,8 @@
}
-// Branches to a label or falls through with this instance class-name adr
-// returned in temp reg, available for comparison by the caller. Trashes the
-// temp registers, but not the input. Only input and temp2 may alias.
+// Branches to a label or falls through with the answer in flags. Trashes
+// the temp registers, but not the input.
void LCodeGen::EmitClassOfTest(Label* is_true,
Label* is_false,
Handle<String>class_name,
@@ -1840,7 +1879,9 @@
Register temp,
Register temp2) {
ASSERT(!input.is(temp));
- ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
+ ASSERT(!input.is(temp2));
+ ASSERT(!temp.is(temp2));
+
__ JumpIfSmi(input, is_false);
if (class_name->IsEqualTo(CStrVector("Function"))) {
@@ -2042,7 +2083,7 @@
// offset to the location of the map check.
Register temp = ToRegister(instr->TempAt(0));
ASSERT(temp.is(t0));
- __ li(InstanceofStub::right(), Operand(instr->function()));
+ __ LoadHeapObject(InstanceofStub::right(), instr->function());
static const int kAdditionalDelta = 7;
int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
Label before_push_delta;
@@ -2124,26 +2165,26 @@
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
- Register value = ToRegister(instr->InputAt(0));
- Register scratch = scratch0();
- Register scratch2 = ToRegister(instr->TempAt(0));
+ Register value = ToRegister(instr->value());
+ Register cell = scratch0();
// Load the cell.
- __ li(scratch, Operand(Handle<Object>(instr->hydrogen()->cell())));
+ __ li(cell, Operand(instr->hydrogen()->cell()));
// If the cell we are storing to contains the hole it could have
// been deleted from the property dictionary. In that case, we need
// to update the property details in the property dictionary to mark
// it as no longer deleted.
if (instr->hydrogen()->RequiresHoleCheck()) {
- __ lw(scratch2,
- FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ // We use a temp to check the payload.
+ Register payload = ToRegister(instr->TempAt(0));
+ __ lw(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(eq, instr->environment(), scratch2, Operand(at));
+ DeoptimizeIf(eq, instr->environment(), payload, Operand(at));
}
// Store the value.
- __ sw(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
+ __ sw(value, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
// Cells are always rescanned, so no write barrier here.
}
@@ -2163,14 +2204,42 @@
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
+
__ lw(result, ContextOperand(context, instr->slot_index()));
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment(), result, Operand(at));
+ } else {
+ Label is_not_hole;
+ __ Branch(&is_not_hole, ne, result, Operand(at));
+ __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+ __ bind(&is_not_hole);
+ }
+ }
}
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
+ Register scratch = scratch0();
MemOperand target = ContextOperand(context, instr->slot_index());
+
+ Label skip_assignment;
+
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ __ lw(scratch, target);
+ __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
+ } else {
+ __ Branch(&skip_assignment, ne, scratch, Operand(at));
+ }
+ }
+
__ sw(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
@@ -2185,6 +2254,8 @@
EMIT_REMEMBERED_SET,
check_needed);
}
+
+ __ bind(&skip_assignment);
}
@@ -2206,7 +2277,7 @@
Handle<String> name) {
LookupResult lookup(isolate());
type->LookupInDescriptors(NULL, *name, &lookup);
- ASSERT(lookup.IsProperty() &&
+ ASSERT(lookup.IsFound() &&
(lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
if (lookup.type() == FIELD) {
int index = lookup.GetLocalFieldIndexFromMap(*type);
@@ -2222,7 +2293,7 @@
}
} else {
Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
- LoadHeapObject(result, Handle<HeapObject>::cast(function));
+ __ LoadHeapObject(result, function);
}
}
@@ -2656,7 +2727,7 @@
this, pointers, Safepoint::kLazyDeopt);
// The number of arguments is stored in receiver which is a0, as expected
// by InvokeFunction.
- v8::internal::ParameterCount actual(receiver);
+ ParameterCount actual(receiver);
__ InvokeFunction(function, actual, CALL_FUNCTION,
safepoint_generator, CALL_AS_METHOD);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -2676,7 +2747,7 @@
void LCodeGen::DoThisFunction(LThisFunction* instr) {
Register result = ToRegister(instr->result());
- LoadHeapObject(result, instr->hydrogen()->closure());
+ __ LoadHeapObject(result, instr->hydrogen()->closure());
}
@@ -2712,31 +2783,41 @@
int arity,
LInstruction* instr,
CallKind call_kind) {
- // Change context if needed.
- bool change_context =
- (info()->closure()->context() != function->context()) ||
- scope()->contains_with() ||
- (scope()->num_heap_slots() > 0);
- if (change_context) {
- __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
- }
-
- // Set a0 to arguments count if adaption is not needed. Assumes that a0
- // is available to write to at this point.
- if (!function->NeedsArgumentsAdaption()) {
- __ li(a0, Operand(arity));
- }
+ bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
+ function->shared()->formal_parameter_count() == arity;
LPointerMap* pointers = instr->pointer_map();
RecordPosition(pointers->position());
- // Invoke function.
- __ SetCallKind(t1, call_kind);
- __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- __ Call(at);
+ if (can_invoke_directly) {
+ __ LoadHeapObject(a1, function);
+ // Change context if needed.
+ bool change_context =
+ (info()->closure()->context() != function->context()) ||
+ scope()->contains_with() ||
+ (scope()->num_heap_slots() > 0);
+ if (change_context) {
+ __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+ }
- // Setup deoptimization.
- RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+ // Set r0 to arguments count if adaption is not needed. Assumes that r0
+ // is available to write to at this point.
+ if (!function->NeedsArgumentsAdaption()) {
+ __ li(a0, Operand(arity));
+ }
+
+ // Invoke function.
+ __ SetCallKind(t1, call_kind);
+ __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
+ __ Call(at);
+
+ // Set up deoptimization.
+ RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+ } else {
+ SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+ ParameterCount count(arity);
+ __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
+ }
// Restore context.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
@@ -2746,7 +2827,6 @@
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
__ mov(a0, v0);
- __ li(a1, Operand(instr->function()));
CallKnownFunction(instr->function(), instr->arity(), instr, CALL_AS_METHOD);
}
@@ -2825,7 +2905,7 @@
__ mov(result, input);
ASSERT_EQ(2, masm()->InstructionsGeneratedSince(&done));
__ subu(result, zero_reg, input);
- // Overflow if result is still negative, ie 0x80000000.
+ // Overflow if result is still negative, i.e. 0x80000000.
DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
__ bind(&done);
}
@@ -2985,69 +3065,75 @@
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
DoubleRegister result = ToDoubleRegister(instr->result());
- DoubleRegister double_scratch = double_scratch0();
+ DoubleRegister temp = ToDoubleRegister(instr->TempAt(0));
+
+ ASSERT(!input.is(result));
+
+ // Note that according to ECMA-262 15.8.2.13:
+ // Math.pow(-Infinity, 0.5) == Infinity
+ // Math.sqrt(-Infinity) == NaN
+ Label done;
+ __ Move(temp, -V8_INFINITY);
+ __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
+ // Set up Infinity in the delay slot.
+ // result is overwritten if the branch is not taken.
+ __ neg_d(result, temp);
// Add +0 to convert -0 to +0.
- __ mtc1(zero_reg, double_scratch.low());
- __ mtc1(zero_reg, double_scratch.high());
- __ add_d(result, input, double_scratch);
+ __ add_d(result, input, kDoubleRegZero);
__ sqrt_d(result, result);
+ __ bind(&done);
}
void LCodeGen::DoPower(LPower* instr) {
- LOperand* left = instr->InputAt(0);
- LOperand* right = instr->InputAt(1);
- Register scratch = scratch0();
- DoubleRegister result_reg = ToDoubleRegister(instr->result());
Representation exponent_type = instr->hydrogen()->right()->representation();
- if (exponent_type.IsDouble()) {
- // Prepare arguments and call C function.
- __ PrepareCallCFunction(0, 2, scratch);
- __ SetCallCDoubleArguments(ToDoubleRegister(left),
- ToDoubleRegister(right));
- __ CallCFunction(
- ExternalReference::power_double_double_function(isolate()), 0, 2);
+ // Having marked this as a call, we can use any registers.
+ // Just make sure that the input/output registers are the expected ones.
+ ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
+ ToDoubleRegister(instr->InputAt(1)).is(f4));
+ ASSERT(!instr->InputAt(1)->IsRegister() ||
+ ToRegister(instr->InputAt(1)).is(a2));
+ ASSERT(ToDoubleRegister(instr->InputAt(0)).is(f2));
+ ASSERT(ToDoubleRegister(instr->result()).is(f0));
+
+ if (exponent_type.IsTagged()) {
+ Label no_deopt;
+ __ JumpIfSmi(a2, &no_deopt);
+ __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset));
+ DeoptimizeIf(ne, instr->environment(), t3, Operand(at));
+ __ bind(&no_deopt);
+ MathPowStub stub(MathPowStub::TAGGED);
+ __ CallStub(&stub);
} else if (exponent_type.IsInteger32()) {
- ASSERT(ToRegister(right).is(a0));
- // Prepare arguments and call C function.
- __ PrepareCallCFunction(1, 1, scratch);
- __ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right));
- __ CallCFunction(
- ExternalReference::power_double_int_function(isolate()), 1, 1);
+ MathPowStub stub(MathPowStub::INTEGER);
+ __ CallStub(&stub);
} else {
- ASSERT(exponent_type.IsTagged());
- ASSERT(instr->hydrogen()->left()->representation().IsDouble());
-
- Register right_reg = ToRegister(right);
-
- // Check for smi on the right hand side.
- Label non_smi, call;
- __ JumpIfNotSmi(right_reg, &non_smi);
-
- // Untag smi and convert it to a double.
- __ SmiUntag(right_reg);
- FPURegister single_scratch = double_scratch0();
- __ mtc1(right_reg, single_scratch);
- __ cvt_d_w(result_reg, single_scratch);
- __ Branch(&call);
-
- // Heap number map check.
- __ bind(&non_smi);
- __ lw(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset));
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
- DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
- __ ldc1(result_reg, FieldMemOperand(right_reg, HeapNumber::kValueOffset));
-
- // Prepare arguments and call C function.
- __ bind(&call);
- __ PrepareCallCFunction(0, 2, scratch);
- __ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg);
- __ CallCFunction(
- ExternalReference::power_double_double_function(isolate()), 0, 2);
+ ASSERT(exponent_type.IsDouble());
+ MathPowStub stub(MathPowStub::DOUBLE);
+ __ CallStub(&stub);
}
- // Store the result in the result register.
- __ GetCFunctionDoubleResult(result_reg);
+}
+
+
+void LCodeGen::DoRandom(LRandom* instr) {
+ // Having marked this instruction as a call we can use any
+ // registers.
+ ASSERT(ToDoubleRegister(instr->result()).is(f0));
+ ASSERT(ToRegister(instr->InputAt(0)).is(a0));
+
+ __ PrepareCallCFunction(1, a1);
+ __ lw(a0, FieldMemOperand(a0, GlobalObject::kGlobalContextOffset));
+ __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
+
+ // 0x41300000 is the top half of 1.0 x 2^20 as a double.
+ __ li(a2, Operand(0x41300000));
+ // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
+ __ Move(f12, v0, a2);
+ // Move 0x4130000000000000 to FPU.
+ __ Move(f14, zero_reg, a2);
+ // Subtract to get the result.
+ __ sub_d(f0, f12, f14);
}
@@ -3183,7 +3269,6 @@
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
- __ li(a1, Operand(instr->target()));
CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
}
@@ -3279,13 +3364,6 @@
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
Register scratch = scratch0();
- // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
- // conversion, so it deopts in that case.
- if (instr->hydrogen()->ValueNeedsSmiCheck()) {
- __ And(at, value, Operand(kSmiTagMask));
- DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
- }
-
// Do the store.
if (instr->key()->IsConstantOperand()) {
ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
@@ -3758,6 +3836,7 @@
void LCodeGen::EmitNumberUntagD(Register input_reg,
DoubleRegister result_reg,
bool deoptimize_on_undefined,
+ bool deoptimize_on_minus_zero,
LEnvironment* env) {
Register scratch = scratch0();
@@ -3787,6 +3866,12 @@
}
// Heap number to double register conversion.
__ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
+ if (deoptimize_on_minus_zero) {
+ __ mfc1(at, result_reg.low());
+ __ Branch(&done, ne, at, Operand(zero_reg));
+ __ mfc1(scratch, result_reg.high());
+ DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask));
+ }
__ Branch(&done);
// Smi to double register conversion
@@ -3918,6 +4003,7 @@
EmitNumberUntagD(input_reg, result_reg,
instr->hydrogen()->deoptimize_on_undefined(),
+ instr->hydrogen()->deoptimize_on_minus_zero(),
instr->environment());
}
@@ -4011,10 +4097,32 @@
void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
- ASSERT(instr->InputAt(0)->IsRegister());
- Register reg = ToRegister(instr->InputAt(0));
- DeoptimizeIf(ne, instr->environment(), reg,
- Operand(instr->hydrogen()->target()));
+ Register reg = ToRegister(instr->value());
+ Handle<JSFunction> target = instr->hydrogen()->target();
+ if (isolate()->heap()->InNewSpace(*target)) {
+ Register reg = ToRegister(instr->value());
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(target);
+ __ li(at, Operand(Handle<Object>(cell)));
+ __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset));
+ DeoptimizeIf(ne, instr->environment(), reg,
+ Operand(at));
+ } else {
+ DeoptimizeIf(ne, instr->environment(), reg,
+ Operand(target));
+ }
+}
+
+
+void LCodeGen::DoCheckMapCommon(Register reg,
+ Register scratch,
+ Handle<Map> map,
+ CompareMapMode mode,
+ LEnvironment* env) {
+ Label success;
+ __ CompareMapAndBranch(reg, scratch, map, &success, eq, &success, mode);
+ DeoptimizeIf(al, env);
+ __ bind(&success);
}
@@ -4023,11 +4131,9 @@
LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister());
Register reg = ToRegister(input);
- __ lw(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
- DeoptimizeIf(ne,
- instr->environment(),
- scratch,
- Operand(instr->hydrogen()->map()));
+ Handle<Map> map = instr->hydrogen()->map();
+ DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(),
+ instr->environment());
}
@@ -4083,19 +4189,6 @@
}
-void LCodeGen::LoadHeapObject(Register result,
- Handle<HeapObject> object) {
- if (heap()->InNewSpace(*object)) {
- Handle<JSGlobalPropertyCell> cell =
- factory()->NewJSGlobalPropertyCell(object);
- __ li(result, Operand(cell));
- __ lw(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
- } else {
- __ li(result, Operand(object));
- }
-}
-
-
void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
Register temp1 = ToRegister(instr->TempAt(0));
Register temp2 = ToRegister(instr->TempAt(1));
@@ -4104,40 +4197,53 @@
Handle<JSObject> current_prototype = instr->prototype();
// Load prototype object.
- LoadHeapObject(temp1, current_prototype);
+ __ LoadHeapObject(temp1, current_prototype);
// Check prototype maps up to the holder.
while (!current_prototype.is_identical_to(holder)) {
- __ lw(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
- DeoptimizeIf(ne,
- instr->environment(),
- temp2,
- Operand(Handle<Map>(current_prototype->map())));
+ DoCheckMapCommon(temp1, temp2,
+ Handle<Map>(current_prototype->map()),
+ ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
current_prototype =
Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
// Load next prototype object.
- LoadHeapObject(temp1, current_prototype);
+ __ LoadHeapObject(temp1, current_prototype);
}
// Check the holder map.
- __ lw(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
- DeoptimizeIf(ne,
- instr->environment(),
- temp2,
- Operand(Handle<Map>(current_prototype->map())));
+ DoCheckMapCommon(temp1, temp2,
+ Handle<Map>(current_prototype->map()),
+ ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
}
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
- Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
- ASSERT_EQ(2, constant_elements->length());
- ElementsKind constant_elements_kind =
- static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+ Heap* heap = isolate()->heap();
+ ElementsKind boilerplate_elements_kind =
+ instr->hydrogen()->boilerplate_elements_kind();
+ // Deopt if the array literal boilerplate ElementsKind is of a type different
+ // than the expected one. The check isn't necessary if the boilerplate has
+ // already been converted to FAST_ELEMENTS.
+ if (boilerplate_elements_kind != FAST_ELEMENTS) {
+ __ LoadHeapObject(a1, instr->hydrogen()->boilerplate_object());
+ // Load map into a2.
+ __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
+ // Load the map's "bit field 2".
+ __ lbu(a2, FieldMemOperand(a2, Map::kBitField2Offset));
+ // Retrieve elements_kind from bit field 2.
+ __ Ext(a2, a2, Map::kElementsKindShift, Map::kElementsKindBitCount);
+ DeoptimizeIf(ne,
+ instr->environment(),
+ a2,
+ Operand(boilerplate_elements_kind));
+ }
__ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ lw(a3, FieldMemOperand(a3, JSFunction::kLiteralsOffset));
__ li(a2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
- __ li(a1, Operand(constant_elements));
+ // Boilerplate already exists, constant elements are never accessed.
+ // Pass an empty fixed array.
+ __ li(a1, Operand(Handle<FixedArray>(heap->empty_fixed_array())));
__ Push(a3, a2, a1);
// Pick the right runtime function or stub to call.
@@ -4154,9 +4260,9 @@
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
} else {
FastCloneShallowArrayStub::Mode mode =
- constant_elements_kind == FAST_DOUBLE_ELEMENTS
- ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
- : FastCloneShallowArrayStub::CLONE_ELEMENTS;
+ boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
+ ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
+ : FastCloneShallowArrayStub::CLONE_ELEMENTS;
FastCloneShallowArrayStub stub(mode, length);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
@@ -4195,10 +4301,10 @@
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
__ Addu(a2, result, Operand(*offset));
__ sw(a2, FieldMemOperand(result, total_offset));
- LoadHeapObject(source, value_object);
+ __ LoadHeapObject(source, value_object);
EmitDeepCopy(value_object, result, source, offset);
} else if (value->IsHeapObject()) {
- LoadHeapObject(a2, Handle<HeapObject>::cast(value));
+ __ LoadHeapObject(a2, Handle<HeapObject>::cast(value));
__ sw(a2, FieldMemOperand(result, total_offset));
} else {
__ li(a2, Operand(value));
@@ -4224,7 +4330,7 @@
__ bind(&allocated);
int offset = 0;
- LoadHeapObject(a1, instr->hydrogen()->boilerplate());
+ __ LoadHeapObject(a1, instr->hydrogen()->boilerplate());
EmitDeepCopy(instr->hydrogen()->boilerplate(), v0, a1, &offset);
ASSERT_EQ(size, offset);
}
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 32d4fb3..513992c 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -93,6 +93,9 @@
// Returns a MemOperand pointing to the high word of a DoubleStackSlot.
MemOperand ToHighMemOperand(LOperand* op) const;
+ bool IsInteger32(LConstantOperand* op) const;
+ Handle<Object> ToHandle(LConstantOperand* op) const;
+
// Try to generate code for the entire chunk, but it may fail if the
// chunk contains constructs we cannot handle. Returns true if the
// code generation attempt succeeded.
@@ -112,6 +115,9 @@
void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
Label* map_check);
+ void DoCheckMapCommon(Register reg, Register scratch, Handle<Map> map,
+ CompareMapMode mode, LEnvironment* env);
+
// Parallel move support.
void DoParallelMove(LParallelMove* move);
void DoGap(LGap* instr);
@@ -145,9 +151,9 @@
Scope* scope() const { return scope_; }
HGraph* graph() const { return chunk_->graph(); }
- Register scratch0() { return lithiumScratchReg; }
- Register scratch1() { return lithiumScratchReg2; }
- DoubleRegister double_scratch0() { return lithiumScratchDouble; }
+ Register scratch0() { return kLithiumScratchReg; }
+ Register scratch1() { return kLithiumScratchReg2; }
+ DoubleRegister double_scratch0() { return kLithiumScratchDouble; }
int GetNextEmittedBlock(int block);
LInstruction* GetNextInstruction();
@@ -220,8 +226,8 @@
Safepoint::DeoptMode mode);
void DeoptimizeIf(Condition cc,
LEnvironment* environment,
- Register src1,
- const Operand& src2);
+ Register src1 = zero_reg,
+ const Operand& src2 = Operand(zero_reg));
void AddToTranslation(Translation* translation,
LOperand* op,
@@ -277,6 +283,7 @@
void EmitNumberUntagD(Register input,
DoubleRegister result,
bool deoptimize_on_undefined,
+ bool deoptimize_on_minus_zero,
LEnvironment* env);
// Emits optimized code for typeof x == "y". Modifies input register.
@@ -420,7 +427,7 @@
virtual void Generate() = 0;
virtual LInstruction* instr() = 0;
- void SetExit(Label *exit) { external_exit_ = exit; }
+ void SetExit(Label* exit) { external_exit_ = exit; }
Label* entry() { return &entry_; }
Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
int instruction_index() const { return instruction_index_; }
diff --git a/src/mips/lithium-gap-resolver-mips.cc b/src/mips/lithium-gap-resolver-mips.cc
index 8f7f89c..41b060d 100644
--- a/src/mips/lithium-gap-resolver-mips.cc
+++ b/src/mips/lithium-gap-resolver-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -33,8 +33,7 @@
namespace v8 {
namespace internal {
-static const Register kSavedValueRegister = lithiumScratchReg;
-static const DoubleRegister kSavedDoubleValueRegister = lithiumScratchDouble;
+static const Register kSavedValueRegister = kLithiumScratchReg;
LGapResolver::LGapResolver(LCodeGen* owner)
: cgen_(owner),
@@ -175,9 +174,9 @@
} else if (source->IsStackSlot()) {
__ lw(kSavedValueRegister, cgen_->ToMemOperand(source));
} else if (source->IsDoubleRegister()) {
- __ mov_d(kSavedDoubleValueRegister, cgen_->ToDoubleRegister(source));
+ __ mov_d(kLithiumScratchDouble, cgen_->ToDoubleRegister(source));
} else if (source->IsDoubleStackSlot()) {
- __ ldc1(kSavedDoubleValueRegister, cgen_->ToMemOperand(source));
+ __ ldc1(kLithiumScratchDouble, cgen_->ToMemOperand(source));
} else {
UNREACHABLE();
}
@@ -190,16 +189,16 @@
ASSERT(in_cycle_);
ASSERT(saved_destination_ != NULL);
- // Spilled value is in kSavedValueRegister or kSavedDoubleValueRegister.
+ // Spilled value is in kSavedValueRegister or kLithiumScratchDouble.
if (saved_destination_->IsRegister()) {
__ mov(cgen_->ToRegister(saved_destination_), kSavedValueRegister);
} else if (saved_destination_->IsStackSlot()) {
__ sw(kSavedValueRegister, cgen_->ToMemOperand(saved_destination_));
} else if (saved_destination_->IsDoubleRegister()) {
__ mov_d(cgen_->ToDoubleRegister(saved_destination_),
- kSavedDoubleValueRegister);
+ kLithiumScratchDouble);
} else if (saved_destination_->IsDoubleStackSlot()) {
- __ sdc1(kSavedDoubleValueRegister,
+ __ sdc1(kLithiumScratchDouble,
cgen_->ToMemOperand(saved_destination_));
} else {
UNREACHABLE();
@@ -239,8 +238,8 @@
// Therefore we can't use 'at'. It is OK if the read from the source
// destroys 'at', since that happens before the value is read.
// This uses only a single reg of the double reg-pair.
- __ lwc1(kSavedDoubleValueRegister, source_operand);
- __ swc1(kSavedDoubleValueRegister, destination_operand);
+ __ lwc1(kLithiumScratchDouble, source_operand);
+ __ swc1(kLithiumScratchDouble, destination_operand);
} else {
__ lw(at, source_operand);
__ sw(at, destination_operand);
@@ -252,14 +251,24 @@
}
} else if (source->IsConstantOperand()) {
- Operand source_operand = cgen_->ToOperand(source);
+ LConstantOperand* constant_source = LConstantOperand::cast(source);
if (destination->IsRegister()) {
- __ li(cgen_->ToRegister(destination), source_operand);
+ Register dst = cgen_->ToRegister(destination);
+ if (cgen_->IsInteger32(constant_source)) {
+ __ li(dst, Operand(cgen_->ToInteger32(constant_source)));
+ } else {
+ __ LoadObject(dst, cgen_->ToHandle(constant_source));
+ }
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone.
- MemOperand destination_operand = cgen_->ToMemOperand(destination);
- __ li(kSavedValueRegister, source_operand);
+ if (cgen_->IsInteger32(constant_source)) {
+ __ li(kSavedValueRegister,
+ Operand(cgen_->ToInteger32(constant_source)));
+ } else {
+ __ LoadObject(kSavedValueRegister,
+ cgen_->ToHandle(constant_source));
+ }
__ sw(kSavedValueRegister, cgen_->ToMemOperand(destination));
}
@@ -281,7 +290,7 @@
ASSERT(destination->IsDoubleStackSlot());
MemOperand destination_operand = cgen_->ToMemOperand(destination);
if (in_cycle_) {
- // kSavedDoubleValueRegister was used to break the cycle,
+ // kLithiumScratchDouble was used to break the cycle,
// but kSavedValueRegister is free.
MemOperand source_high_operand =
cgen_->ToHighMemOperand(source);
@@ -292,8 +301,8 @@
__ lw(kSavedValueRegister, source_high_operand);
__ sw(kSavedValueRegister, destination_high_operand);
} else {
- __ ldc1(kSavedDoubleValueRegister, source_operand);
- __ sdc1(kSavedDoubleValueRegister, destination_operand);
+ __ ldc1(kLithiumScratchDouble, source_operand);
+ __ sdc1(kLithiumScratchDouble, destination_operand);
}
}
} else {
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 19892fc..99e718c 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -1005,14 +1005,16 @@
LEnvironment* outer =
CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
int ast_id = hydrogen_env->ast_id();
- ASSERT(ast_id != AstNode::kNoNumber);
+ ASSERT(ast_id != AstNode::kNoNumber || hydrogen_env->is_arguments_adaptor());
int value_count = hydrogen_env->length();
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
+ hydrogen_env->is_arguments_adaptor(),
ast_id,
hydrogen_env->parameter_count(),
argument_count_,
value_count,
outer);
+ int argument_index = *argument_index_accumulator;
for (int i = 0; i < value_count; ++i) {
if (hydrogen_env->is_special_index(i)) continue;
@@ -1021,13 +1023,17 @@
if (value->IsArgumentsObject()) {
op = NULL;
} else if (value->IsPushArgument()) {
- op = new LArgument((*argument_index_accumulator)++);
+ op = new LArgument(argument_index++);
} else {
op = UseAny(value);
}
result->AddValue(op, value->representation());
}
+ if (!hydrogen_env->is_arguments_adaptor()) {
+ *argument_index_accumulator = argument_index;
+ }
+
return result;
}
@@ -1038,14 +1044,23 @@
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
- HValue* v = instr->value();
- if (v->EmitAtUses()) {
- HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
+ HValue* value = instr->value();
+ if (value->EmitAtUses()) {
+ HBasicBlock* successor = HConstant::cast(value)->ToBoolean()
? instr->FirstSuccessor()
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- return AssignEnvironment(new LBranch(UseRegister(v)));
+
+ LBranch* result = new LBranch(UseRegister(value));
+ // Tagged values that are not known smis or booleans require a
+ // deoptimization environment.
+ Representation rep = value->representation();
+ HType type = value->type();
+ if (rep.IsTagged() && !type.IsSmi() && !type.IsBoolean()) {
+ return AssignEnvironment(result);
+ }
+ return result;
}
@@ -1152,6 +1167,13 @@
LOperand* input = UseFixedDouble(instr->value(), f4);
LUnaryMathOperation* result = new LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, f4), instr);
+ } else if (op == kMathPowHalf) {
+ // Input cannot be the same as the result.
+ // See lithium-codegen-mips.cc::DoMathPowHalf.
+ LOperand* input = UseFixedDouble(instr->value(), f8);
+ LOperand* temp = FixedTemp(f6);
+ LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
+ return DefineFixedDouble(result, f4);
} else {
LOperand* input = UseRegisterAtStart(instr->value());
LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
@@ -1165,8 +1187,6 @@
return DefineAsRegister(result);
case kMathRound:
return AssignEnvironment(DefineAsRegister(result));
- case kMathPowHalf:
- return DefineAsRegister(result);
default:
UNREACHABLE();
return NULL;
@@ -1340,7 +1360,12 @@
} else {
left = UseRegisterAtStart(instr->LeastConstantOperand());
}
- return AssignEnvironment(DefineAsRegister(new LMulI(left, right, temp)));
+ LMulI* mul = new LMulI(left, right, temp);
+ if (instr->CheckFlag(HValue::kCanOverflow) ||
+ instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ AssignEnvironment(mul);
+ }
+ return DefineAsRegister(mul);
} else if (instr->representation().IsDouble()) {
return DoArithmeticD(Token::MUL, instr);
@@ -1401,14 +1426,23 @@
LOperand* left = UseFixedDouble(instr->left(), f2);
LOperand* right = exponent_type.IsDouble() ?
UseFixedDouble(instr->right(), f4) :
- UseFixed(instr->right(), a0);
+ UseFixed(instr->right(), a2);
LPower* result = new LPower(left, right);
- return MarkAsCall(DefineFixedDouble(result, f6),
+ return MarkAsCall(DefineFixedDouble(result, f0),
instr,
CAN_DEOPTIMIZE_EAGERLY);
}
+LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseFixed(instr->global_object(), a0);
+ LRandom* result = new LRandom(global_object);
+ return MarkAsCall(DefineFixedDouble(result, f0), instr);
+}
+
+
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
Representation r = instr->GetInputRepresentation();
ASSERT(instr->left()->representation().IsTagged());
@@ -1526,7 +1560,7 @@
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
HClassOfTestAndBranch* instr) {
ASSERT(instr->value()->representation().IsTagged());
- return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
+ return new LClassOfTestAndBranch(UseRegister(instr->value()),
TempRegister());
}
@@ -1553,7 +1587,7 @@
LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
LOperand* object = UseRegister(instr->value());
LValueOf* result = new LValueOf(object, TempRegister());
- return AssignEnvironment(DefineAsRegister(result));
+ return DefineAsRegister(result);
}
@@ -1777,11 +1811,12 @@
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
- LOperand* temp = TempRegister();
- LOperand* value = UseTempRegister(instr->value());
- LInstruction* result = new LStoreGlobalCell(value, temp);
- if (instr->RequiresHoleCheck()) result = AssignEnvironment(result);
- return result;
+ LOperand* value = UseRegister(instr->value());
+ // Use a temp to check the value in the cell in the case where we perform
+ // a hole check.
+ return instr->RequiresHoleCheck()
+ ? AssignEnvironment(new LStoreGlobalCell(value, TempRegister()))
+ : new LStoreGlobalCell(value, NULL);
}
@@ -1796,7 +1831,8 @@
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
LOperand* context = UseRegisterAtStart(instr->value());
- return DefineAsRegister(new LLoadContextSlot(context));
+ LInstruction* result = DefineAsRegister(new LLoadContextSlot(context));
+ return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
}
@@ -1810,7 +1846,8 @@
context = UseRegister(instr->context());
value = UseRegister(instr->value());
}
- return new LStoreContextSlot(context, value);
+ LInstruction* result = new LStoreContextSlot(context, value);
+ return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
}
@@ -1869,7 +1906,8 @@
LOperand* obj = UseRegisterAtStart(instr->object());
LOperand* key = UseRegisterAtStart(instr->key());
LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
- return AssignEnvironment(DefineAsRegister(result));
+ if (instr->RequiresHoleCheck()) AssignEnvironment(result);
+ return DefineAsRegister(result);
}
@@ -1933,8 +1971,7 @@
LOperand* key = needs_write_barrier
? UseTempRegister(instr->key())
: UseRegisterOrConstantAtStart(instr->key());
-
- return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
+ return new LStoreKeyedFastElement(obj, key, val);
}
@@ -2216,6 +2253,7 @@
HEnvironment* outer = current_block_->last_environment();
HConstant* undefined = graph()->GetConstantUndefined();
HEnvironment* inner = outer->CopyForInlining(instr->closure(),
+ instr->arguments_count(),
instr->function(),
undefined,
instr->call_kind());
@@ -2226,7 +2264,8 @@
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
- HEnvironment* outer = current_block_->last_environment()->outer();
+ HEnvironment* outer = current_block_->last_environment()->
+ DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
return NULL;
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index eb85f10..069a025 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -141,6 +141,7 @@
V(Parameter) \
V(Power) \
V(PushArgument) \
+ V(Random) \
V(RegExpLiteral) \
V(Return) \
V(ShiftI) \
@@ -1026,6 +1027,17 @@
};
+class LRandom: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LRandom(LOperand* global_object) {
+ inputs_[0] = global_object;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Random, "random")
+ DECLARE_HYDROGEN_ACCESSOR(Random)
+};
+
+
class LArithmeticD: public LTemplateInstruction<1, 2, 0> {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
@@ -1242,6 +1254,8 @@
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell")
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell)
+
+ LOperand* value() { return inputs_[0]; }
};
@@ -1793,6 +1807,8 @@
inputs_[0] = value;
}
+ LOperand* value() { return InputAt(0); }
+
DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
};
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index a6dcddc..941c7fe 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -81,6 +81,19 @@
}
+void MacroAssembler::LoadHeapObject(Register result,
+ Handle<HeapObject> object) {
+ if (isolate()->heap()->InNewSpace(*object)) {
+ Handle<JSGlobalPropertyCell> cell =
+ isolate()->factory()->NewJSGlobalPropertyCell(object);
+ li(result, Operand(cell));
+ lw(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
+ } else {
+ li(result, Operand(object));
+ }
+}
+
+
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
// Safepoints expect a block of kNumSafepointRegisters values on the
@@ -239,6 +252,12 @@
// registers are cp.
ASSERT(!address.is(cp) && !value.is(cp));
+ if (emit_debug_code()) {
+ lw(at, MemOperand(address));
+ Assert(
+ eq, "Wrong address or value passed to RecordWrite", at, Operand(value));
+ }
+
Label done;
if (smi_check == INLINE_SMI_CHECK) {
@@ -284,7 +303,7 @@
SaveFPRegsMode fp_mode,
RememberedSetFinalAction and_then) {
Label done;
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
Label ok;
JumpIfNotInNewSpace(object, scratch, &ok);
stop("Remembered set pointer is in new space");
@@ -396,6 +415,46 @@
}
+void MacroAssembler::GetNumberHash(Register reg0, Register scratch) {
+ // First of all we assign the hash seed to scratch.
+ LoadRoot(scratch, Heap::kHashSeedRootIndex);
+ SmiUntag(scratch);
+
+ // Xor original key with a seed.
+ xor_(reg0, reg0, scratch);
+
+ // Compute the hash code from the untagged key. This must be kept in sync
+ // with ComputeIntegerHash in utils.h.
+ //
+ // hash = ~hash + (hash << 15);
+ nor(scratch, reg0, zero_reg);
+ sll(at, reg0, 15);
+ addu(reg0, scratch, at);
+
+ // hash = hash ^ (hash >> 12);
+ srl(at, reg0, 12);
+ xor_(reg0, reg0, at);
+
+ // hash = hash + (hash << 2);
+ sll(at, reg0, 2);
+ addu(reg0, reg0, at);
+
+ // hash = hash ^ (hash >> 4);
+ srl(at, reg0, 4);
+ xor_(reg0, reg0, at);
+
+ // hash = hash * 2057;
+ sll(scratch, reg0, 11);
+ sll(at, reg0, 3);
+ addu(reg0, reg0, at);
+ addu(reg0, reg0, scratch);
+
+ // hash = hash ^ (hash >> 16);
+ srl(at, reg0, 16);
+ xor_(reg0, reg0, at);
+}
+
+
void MacroAssembler::LoadFromNumberDictionary(Label* miss,
Register elements,
Register key,
@@ -427,36 +486,10 @@
// at - Temporary (avoid MacroAssembler instructions also using 'at').
Label done;
- // Compute the hash code from the untagged key. This must be kept in sync
- // with ComputeIntegerHash in utils.h.
- //
- // hash = ~hash + (hash << 15);
- nor(reg1, reg0, zero_reg);
- sll(at, reg0, 15);
- addu(reg0, reg1, at);
-
- // hash = hash ^ (hash >> 12);
- srl(at, reg0, 12);
- xor_(reg0, reg0, at);
-
- // hash = hash + (hash << 2);
- sll(at, reg0, 2);
- addu(reg0, reg0, at);
-
- // hash = hash ^ (hash >> 4);
- srl(at, reg0, 4);
- xor_(reg0, reg0, at);
-
- // hash = hash * 2057;
- li(reg1, Operand(2057));
- mul(reg0, reg0, reg1);
-
- // hash = hash ^ (hash >> 16);
- srl(at, reg0, 16);
- xor_(reg0, reg0, at);
+ GetNumberHash(reg0, reg1);
// Compute the capacity mask.
- lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
+ lw(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
sra(reg1, reg1, kSmiTagSize);
Subu(reg1, reg1, Operand(1));
@@ -467,12 +500,12 @@
mov(reg2, reg0);
// Compute the masked index: (hash + i + i * i) & mask.
if (i > 0) {
- Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i)));
+ Addu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
}
and_(reg2, reg2, reg1);
// Scale the index by multiplying by the element size.
- ASSERT(NumberDictionary::kEntrySize == 3);
+ ASSERT(SeededNumberDictionary::kEntrySize == 3);
sll(at, reg2, 1); // 2x.
addu(reg2, reg2, at); // reg2 = reg2 * 3.
@@ -480,7 +513,7 @@
sll(at, reg2, kPointerSizeLog2);
addu(reg2, elements, at);
- lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset));
+ lw(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset));
if (i != kProbes - 1) {
Branch(&done, eq, key, Operand(at));
} else {
@@ -492,14 +525,14 @@
// Check that the value is a normal property.
// reg2: elements + (index * kPointerSize).
const int kDetailsOffset =
- NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
+ SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
Branch(miss, ne, at, Operand(zero_reg));
// Get the value at the masked, scaled index and return.
const int kValueOffset =
- NumberDictionary::kElementsStartOffset + kPointerSize;
+ SeededNumberDictionary::kElementsStartOffset + kPointerSize;
lw(result, FieldMemOperand(reg2, kValueOffset));
}
@@ -1145,7 +1178,7 @@
Branch(not_int32, gt, scratch2, Operand(non_smi_exponent));
// We know the exponent is smaller than 30 (biased). If it is less than
- // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
+ // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e.
// it rounds to zero.
const uint32_t zero_exponent =
(HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
@@ -3282,17 +3315,51 @@
}
+void MacroAssembler::CompareMapAndBranch(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Label* early_success,
+ Condition cond,
+ Label* branch_to,
+ CompareMapMode mode) {
+ lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+ Operand right = Operand(map);
+ if (mode == ALLOW_ELEMENT_TRANSITION_MAPS) {
+ Map* transitioned_fast_element_map(
+ map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL));
+ ASSERT(transitioned_fast_element_map == NULL ||
+ map->elements_kind() != FAST_ELEMENTS);
+ if (transitioned_fast_element_map != NULL) {
+ Branch(early_success, eq, scratch, right);
+ right = Operand(Handle<Map>(transitioned_fast_element_map));
+ }
+
+ Map* transitioned_double_map(
+ map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL));
+ ASSERT(transitioned_double_map == NULL ||
+ map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
+ if (transitioned_double_map != NULL) {
+ Branch(early_success, eq, scratch, right);
+ right = Operand(Handle<Map>(transitioned_double_map));
+ }
+ }
+
+ Branch(branch_to, cond, scratch, right);
+}
+
+
void MacroAssembler::CheckMap(Register obj,
Register scratch,
Handle<Map> map,
Label* fail,
- SmiCheckType smi_check_type) {
+ SmiCheckType smi_check_type,
+ CompareMapMode mode) {
if (smi_check_type == DO_SMI_CHECK) {
JumpIfSmi(obj, fail);
}
- lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
- li(at, Operand(map));
- Branch(fail, ne, scratch, Operand(at));
+ Label success;
+ CompareMapAndBranch(obj, scratch, map, &success, ne, fail, mode);
+ bind(&success);
}
@@ -3399,10 +3466,12 @@
Handle<Code> code_constant,
Register code_reg,
Label* done,
+ bool* definitely_mismatches,
InvokeFlag flag,
const CallWrapper& call_wrapper,
CallKind call_kind) {
bool definitely_matches = false;
+ *definitely_mismatches = false;
Label regular_invoke;
// Check whether the expected and actual arguments count match. If not,
@@ -3433,6 +3502,7 @@
// arguments.
definitely_matches = true;
} else {
+ *definitely_mismatches = true;
li(a2, Operand(expected.immediate()));
}
}
@@ -3456,7 +3526,9 @@
SetCallKind(t1, call_kind);
Call(adaptor);
call_wrapper.AfterCall();
- jmp(done);
+ if (!*definitely_mismatches) {
+ Branch(done);
+ }
} else {
SetCallKind(t1, call_kind);
Jump(adaptor, RelocInfo::CODE_TARGET);
@@ -3477,21 +3549,25 @@
Label done;
- InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
+ bool definitely_mismatches = false;
+ InvokePrologue(expected, actual, Handle<Code>::null(), code,
+ &done, &definitely_mismatches, flag,
call_wrapper, call_kind);
- if (flag == CALL_FUNCTION) {
- call_wrapper.BeforeCall(CallSize(code));
- SetCallKind(t1, call_kind);
- Call(code);
- call_wrapper.AfterCall();
- } else {
- ASSERT(flag == JUMP_FUNCTION);
- SetCallKind(t1, call_kind);
- Jump(code);
+ if (!definitely_mismatches) {
+ if (flag == CALL_FUNCTION) {
+ call_wrapper.BeforeCall(CallSize(code));
+ SetCallKind(t1, call_kind);
+ Call(code);
+ call_wrapper.AfterCall();
+ } else {
+ ASSERT(flag == JUMP_FUNCTION);
+ SetCallKind(t1, call_kind);
+ Jump(code);
+ }
+ // Continue here if InvokePrologue does handle the invocation due to
+ // mismatched parameter counts.
+ bind(&done);
}
- // Continue here if InvokePrologue does handle the invocation due to
- // mismatched parameter counts.
- bind(&done);
}
@@ -3506,18 +3582,22 @@
Label done;
- InvokePrologue(expected, actual, code, no_reg, &done, flag,
+ bool definitely_mismatches = false;
+ InvokePrologue(expected, actual, code, no_reg,
+ &done, &definitely_mismatches, flag,
NullCallWrapper(), call_kind);
- if (flag == CALL_FUNCTION) {
- SetCallKind(t1, call_kind);
- Call(code, rmode);
- } else {
- SetCallKind(t1, call_kind);
- Jump(code, rmode);
+ if (!definitely_mismatches) {
+ if (flag == CALL_FUNCTION) {
+ SetCallKind(t1, call_kind);
+ Call(code, rmode);
+ } else {
+ SetCallKind(t1, call_kind);
+ Jump(code, rmode);
+ }
+ // Continue here if InvokePrologue does handle the invocation due to
+ // mismatched parameter counts.
+ bind(&done);
}
- // Continue here if InvokePrologue does handle the invocation due to
- // mismatched parameter counts.
- bind(&done);
}
@@ -3550,12 +3630,13 @@
void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
const ParameterCount& actual,
InvokeFlag flag,
+ const CallWrapper& call_wrapper,
CallKind call_kind) {
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
// Get the function and setup the context.
- li(a1, Operand(function));
+ LoadHeapObject(a1, function);
lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
ParameterCount expected(function->shared()->formal_parameter_count());
@@ -3563,7 +3644,7 @@
// allow recompilation to take effect without changing any of the
// call sites.
lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- InvokeCode(a3, expected, actual, flag, NullCallWrapper(), call_kind);
+ InvokeCode(a3, expected, actual, flag, call_wrapper, call_kind);
}
@@ -4248,7 +4329,7 @@
void MacroAssembler::EnterExitFrame(bool save_doubles,
int stack_space) {
- // Setup the frame structure on the stack.
+ // Set up the frame structure on the stack.
STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset);
@@ -4266,7 +4347,7 @@
addiu(sp, sp, -4 * kPointerSize);
sw(ra, MemOperand(sp, 3 * kPointerSize));
sw(fp, MemOperand(sp, 2 * kPointerSize));
- addiu(fp, sp, 2 * kPointerSize); // Setup new frame pointer.
+ addiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer.
if (emit_debug_code()) {
sw(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
@@ -4841,7 +4922,7 @@
And(t8, mask_scratch, load_scratch);
Branch(&done, ne, t8, Operand(zero_reg));
- if (FLAG_debug_code) {
+ if (emit_debug_code()) {
// Check for impossible bit pattern.
Label ok;
// sll may overflow, making the check conservative.
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index 454fe9e..b976f6e 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -51,16 +51,6 @@
// MIPS generated code calls C code, it must be via t9 register.
-// Register aliases.
-// cp is assumed to be a callee saved register.
-const Register lithiumScratchReg = s3; // Scratch register.
-const Register lithiumScratchReg2 = s4; // Scratch register.
-const Register condReg = s5; // Simulated (partial) condition code for mips.
-const Register roots = s6; // Roots array pointer.
-const Register cp = s7; // JavaScript context pointer.
-const Register fp = s8_fp; // Alias for fp.
-const DoubleRegister lithiumScratchDouble = f30; // Double scratch register.
-
// Flags used for the AllocateInNewSpace functions.
enum AllocationFlags {
// No special flags.
@@ -262,6 +252,15 @@
Heap::RootListIndex index,
Condition cond, Register src1, const Operand& src2);
+ void LoadHeapObject(Register dst, Handle<HeapObject> object);
+
+ void LoadObject(Register result, Handle<Object> object) {
+ if (object->IsHeapObject()) {
+ LoadHeapObject(result, Handle<HeapObject>::cast(object));
+ } else {
+ li(result, object);
+ }
+ }
// ---------------------------------------------------------------------------
// GC Support
@@ -331,7 +330,7 @@
Register scratch3,
Label* object_is_white_and_not_data);
- // Detects conservatively whether an object is data-only, ie it does need to
+ // Detects conservatively whether an object is data-only, i.e. it does need to
// be scanned by the garbage collector.
void JumpIfDataObject(Register value,
Register scratch,
@@ -396,6 +395,7 @@
Register scratch,
Label* miss);
+ void GetNumberHash(Register reg0, Register scratch);
void LoadFromNumberDictionary(Label* miss,
Register elements,
@@ -411,7 +411,7 @@
}
// Check if the given instruction is a 'type' marker.
- // ie. check if it is a sll zero_reg, zero_reg, <type> (referenced as
+ // i.e. check if it is a sll zero_reg, zero_reg, <type> (referenced as
// nop(type)). These instructions are generated to mark special location in
// the code, like some special IC code.
static inline bool IsMarkedCode(Instr instr, int type) {
@@ -780,11 +780,16 @@
Register map,
Register scratch);
+ void InitializeRootRegister() {
+ ExternalReference roots_array_start =
+ ExternalReference::roots_array_start(isolate());
+ li(kRootRegister, Operand(roots_array_start));
+ }
// -------------------------------------------------------------------------
// JavaScript invokes.
- // Setup call kind marking in t1. The method takes t1 as an
+ // Set up call kind marking in t1. The method takes t1 as an
// explicit first parameter to make the code more readable at the
// call sites.
void SetCallKind(Register dst, CallKind kind);
@@ -815,6 +820,7 @@
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& actual,
InvokeFlag flag,
+ const CallWrapper& call_wrapper,
CallKind call_kind);
@@ -925,15 +931,29 @@
Register scratch4,
Label* fail);
- // Check if the map of an object is equal to a specified map (either
- // given directly or as an index into the root list) and branch to
- // label if not. Skip the smi check if not required (object is known
- // to be a heap object).
+ // Compare an object's map with the specified map and its transitioned
+ // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to
+ // "branch_to" if the result of the comparison is "cond". If multiple map
+ // compares are required, the compare sequences branches to early_success.
+ void CompareMapAndBranch(Register obj,
+ Register scratch,
+ Handle<Map> map,
+ Label* early_success,
+ Condition cond,
+ Label* branch_to,
+ CompareMapMode mode = REQUIRE_EXACT_MAP);
+
+ // Check if the map of an object is equal to a specified map and branch to
+ // label if not. Skip the smi check if not required (object is known to be a
+ // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
+ // against maps that are ElementsKind transition maps of the specificed map.
void CheckMap(Register obj,
Register scratch,
Handle<Map> map,
Label* fail,
- SmiCheckType smi_check_type);
+ SmiCheckType smi_check_type,
+ CompareMapMode mode = REQUIRE_EXACT_MAP);
+
void CheckMap(Register obj,
Register scratch,
@@ -1117,7 +1137,7 @@
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Restores context. stack_space
- // - space to be unwound on exit (includes the call js arguments space and
+ // - space to be unwound on exit (includes the call JS arguments space and
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(ExternalReference function, int stack_space);
@@ -1358,6 +1378,7 @@
Handle<Code> code_constant,
Register code_reg,
Label* done,
+ bool* definitely_mismatches,
InvokeFlag flag,
const CallWrapper& call_wrapper,
CallKind call_kind);
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index f70775d..a158f04 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -888,7 +888,7 @@
isolate_->set_simulator_i_cache(i_cache_);
}
Initialize(isolate);
- // Setup simulator support first. Some of this information is needed to
+ // Set up simulator support first. Some of this information is needed to
// setup the architecture state.
stack_ = reinterpret_cast<char*>(malloc(stack_size_));
pc_modified_ = false;
@@ -897,7 +897,7 @@
break_pc_ = NULL;
break_instr_ = 0;
- // Setup architecture state.
+ // Set up architecture state.
// All registers are initialized to zero to start with.
for (int i = 0; i < kNumSimuRegisters; i++) {
registers_[i] = 0;
@@ -1944,7 +1944,7 @@
// Next pc
int32_t next_pc = 0;
- // Setup the variables if needed before executing the instruction.
+ // Set up the variables if needed before executing the instruction.
ConfigureTypeRegister(instr,
alu_out,
i64hilo,
@@ -2291,7 +2291,7 @@
}
-// Type 2: instructions using a 16 bytes immediate. (eg: addi, beq).
+// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq).
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
@@ -2614,7 +2614,7 @@
}
-// Type 3: instructions using a 26 bytes immediate. (eg: j, jal).
+// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
void Simulator::DecodeTypeJump(Instruction* instr) {
// Get current pc.
int32_t current_pc = get_pc();
@@ -2711,7 +2711,7 @@
int32_t Simulator::Call(byte* entry, int argument_count, ...) {
va_list parameters;
va_start(parameters, argument_count);
- // Setup arguments.
+ // Set up arguments.
// First four arguments passed in registers.
ASSERT(argument_count >= 4);
@@ -2758,7 +2758,7 @@
int32_t sp_val = get_register(sp);
int32_t fp_val = get_register(fp);
- // Setup the callee-saved registers with a known value. To be able to check
+ // Set up the callee-saved registers with a known value. To be able to check
// that they are preserved properly across JS execution.
int32_t callee_saved_value = icount_;
set_register(s0, callee_saved_value);
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 9f214a3..0051edf 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -377,13 +377,9 @@
Label* miss_label) {
// a0 : value.
Label exit;
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(receiver_reg, miss_label, scratch);
-
- // Check that the map of the receiver hasn't changed.
- __ lw(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- __ Branch(miss_label, ne, scratch, Operand(Handle<Map>(object->map())));
+ // Check that the map of the object hasn't changed.
+ __ CheckMap(receiver_reg, scratch, Handle<Map>(object->map()), miss_label,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -565,16 +561,16 @@
int argc) {
// ----------- S t a t e -------------
// -- sp[0] : holder (set by CheckPrototypes)
- // -- sp[4] : callee js function
+ // -- sp[4] : callee JS function
// -- sp[8] : call data
- // -- sp[12] : last js argument
+ // -- sp[12] : last JS argument
// -- ...
- // -- sp[(argc + 3) * 4] : first js argument
+ // -- sp[(argc + 3) * 4] : first JS argument
// -- sp[(argc + 4) * 4] : receiver
// -----------------------------------
// Get the function and setup the context.
Handle<JSFunction> function = optimization.constant_function();
- __ li(t1, Operand(function));
+ __ LoadHeapObject(t1, function);
__ lw(cp, FieldMemOperand(t1, JSFunction::kContextOffset));
// Pass the additional arguments FastHandleApiCall expects.
@@ -587,7 +583,7 @@
__ li(t2, call_data);
}
- // Store js function and call data.
+ // Store JS function and call data.
__ sw(t1, MemOperand(sp, 1 * kPointerSize));
__ sw(t2, MemOperand(sp, 2 * kPointerSize));
@@ -747,7 +743,7 @@
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
__ InvokeFunction(optimization.constant_function(), arguments_,
- JUMP_FUNCTION, call_kind);
+ JUMP_FUNCTION, NullCallWrapper(), call_kind);
}
// Deferred code for fast API call case---clean preallocated space.
@@ -1037,9 +1033,8 @@
__ lw(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else {
Handle<Map> current_map(current->map());
- __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- // Branch on the result of the map check.
- __ Branch(miss, ne, scratch1, Operand(current_map));
+ __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
// object.
@@ -1070,8 +1065,8 @@
LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
// Check the holder map.
- __ lw(scratch1, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ Branch(miss, ne, scratch1, Operand(Handle<Map>(current->map())));
+ __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
+ DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1115,7 +1110,7 @@
Register scratch1,
Register scratch2,
Register scratch3,
- Handle<Object> value,
+ Handle<JSFunction> value,
Handle<String> name,
Label* miss) {
// Check that the receiver isn't a smi.
@@ -1127,7 +1122,7 @@
scratch1, scratch2, scratch3, name, miss);
// Return the constant value.
- __ li(v0, Operand(value));
+ __ LoadHeapObject(v0, value);
__ Ret();
}
@@ -1173,7 +1168,7 @@
__ EnterExitFrame(false, kApiStackSpace);
// Create AccessorInfo instance on the stack above the exit frame with
- // scratch2 (internal::Object **args_) as the data.
+ // scratch2 (internal::Object** args_) as the data.
__ sw(a2, MemOperand(sp, kPointerSize));
// a2 (second argument - see note above) = AccessorInfo&
__ Addu(a2, sp, kPointerSize);
@@ -1209,7 +1204,7 @@
// and CALLBACKS, so inline only them, other cases may be added
// later.
bool compile_followup_inline = false;
- if (lookup->IsProperty() && lookup->IsCacheable()) {
+ if (lookup->IsFound() && lookup->IsCacheable()) {
if (lookup->type() == FIELD) {
compile_followup_inline = true;
} else if (lookup->type() == CALLBACKS &&
@@ -1934,7 +1929,8 @@
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
+ __ InvokeFunction(
+ function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// a2: function name.
@@ -2067,7 +2063,8 @@
__ bind(&slow);
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
+ __ InvokeFunction(
+ function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// a2: function name.
@@ -2167,7 +2164,8 @@
// Tail call the full function. We do not have to patch the receiver
// because the function makes no use of it.
__ bind(&slow);
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION, CALL_AS_METHOD);
+ __ InvokeFunction(
+ function, arguments(), JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
__ bind(&miss);
// a2: function name.
@@ -2346,7 +2344,8 @@
CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
? CALL_AS_FUNCTION
: CALL_AS_METHOD;
- __ InvokeFunction(function, arguments(), JUMP_FUNCTION, call_kind);
+ __ InvokeFunction(
+ function, arguments(), JUMP_FUNCTION, NullCallWrapper(), call_kind);
// Handle call cache miss.
__ bind(&miss);
@@ -2430,7 +2429,7 @@
__ sw(a3, MemOperand(sp, argc * kPointerSize));
}
- // Setup the context (function already in r1).
+ // Set up the context (function already in r1).
__ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// Jump to the cached code (tail call).
@@ -2493,12 +2492,9 @@
// -----------------------------------
Label miss;
- // Check that the object isn't a smi.
- __ JumpIfSmi(a1, &miss);
-
// Check that the map of the object hasn't changed.
- __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
- __ Branch(&miss, ne, a3, Operand(Handle<Map>(object->map())));
+ __ CheckMap(a1, a3, Handle<Map>(object->map()), &miss,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
// Perform global security token check if needed.
if (object->IsJSGlobalProxy()) {
@@ -2540,12 +2536,9 @@
// -----------------------------------
Label miss;
- // Check that the object isn't a smi.
- __ JumpIfSmi(a1, &miss);
-
// Check that the map of the object hasn't changed.
- __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset));
- __ Branch(&miss, ne, a3, Operand(Handle<Map>(receiver->map())));
+ __ CheckMap(a1, a3, Handle<Map>(receiver->map()), &miss,
+ DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
// Perform global security token check if needed.
if (receiver->IsJSGlobalProxy()) {
@@ -2701,7 +2694,7 @@
Handle<Code> LoadStubCompiler::CompileLoadConstant(Handle<JSObject> object,
Handle<JSObject> holder,
- Handle<Object> value,
+ Handle<JSFunction> value,
Handle<String> name) {
// ----------- S t a t e -------------
// -- a0 : receiver
@@ -2839,7 +2832,7 @@
Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
- Handle<Object> value) {
+ Handle<JSFunction> value) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key