summaryrefslogtreecommitdiff
path: root/deps/v8/src/mips/code-stubs-mips.cc
diff options
context:
space:
mode:
authorAli Ijaz Sheikh <ofrobots@google.com>2016-04-07 14:06:55 -0700
committerJames M Snell <jasnell@gmail.com>2016-04-26 12:16:03 -0700
commita42453b08568f9b2b2b7474a4d0fb3b4e5e531e6 (patch)
treee420165eb9bd9e3972af67730045066c3518a36f /deps/v8/src/mips/code-stubs-mips.cc
parente4abf8a135e7abc1519c7dd1d3ea2d00f236d242 (diff)
downloadnode-new-a42453b08568f9b2b2b7474a4d0fb3b4e5e531e6.tar.gz
deps: upgrade V8 to 5.0.71.32
* Pick up the branch head for V8 5.0 stable [1] * Edit v8 gitignore to allow trace_event copy * Update V8 DEP trace_event as per deps/v8/DEPS [2] [1] https://chromium.googlesource.com/v8/v8.git/+/3c67831 [2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/4b09207e447ae5bd34643b4c6321bee7b76d35f9 Ref: https://github.com/nodejs/node/pull/5945 PR-URL: https://github.com/nodejs/node/pull/6111 Reviewed-By: targos - Michaƫl Zasso <mic.besace@gmail.com> Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'deps/v8/src/mips/code-stubs-mips.cc')
-rw-r--r--deps/v8/src/mips/code-stubs-mips.cc1348
1 files changed, 772 insertions, 576 deletions
diff --git a/deps/v8/src/mips/code-stubs-mips.cc b/deps/v8/src/mips/code-stubs-mips.cc
index f88d3bd5b4..77dbcb122d 100644
--- a/deps/v8/src/mips/code-stubs-mips.cc
+++ b/deps/v8/src/mips/code-stubs-mips.cc
@@ -91,9 +91,8 @@ void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
#define __ ACCESS_MASM(masm)
-
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
- Condition cc, Strength strength);
+ Condition cc);
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
Register lhs,
Register rhs,
@@ -275,7 +274,7 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
// Equality is almost reflexive (everything but NaN), so this is a test
// for "identity and not NaN".
static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
- Condition cc, Strength strength) {
+ Condition cc) {
Label not_identical;
Label heap_number, return_equal;
Register exp_mask_reg = t5;
@@ -296,29 +295,15 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow,
__ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
// Call runtime on identical SIMD values since we must throw a TypeError.
__ Branch(slow, eq, t4, Operand(SIMD128_VALUE_TYPE));
- if (is_strong(strength)) {
- // Call the runtime on anything that is converted in the semantics, since
- // we need to throw a TypeError. Smis have already been ruled out.
- __ Branch(&return_equal, eq, t4, Operand(HEAP_NUMBER_TYPE));
- __ And(t4, t4, Operand(kIsNotStringMask));
- __ Branch(slow, ne, t4, Operand(zero_reg));
- }
} else {
__ Branch(&heap_number, eq, t4, Operand(HEAP_NUMBER_TYPE));
// Comparing JS objects with <=, >= is complicated.
if (cc != eq) {
- __ Branch(slow, greater, t4, Operand(FIRST_JS_RECEIVER_TYPE));
- // Call runtime on identical symbols since we need to throw a TypeError.
- __ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
- // Call runtime on identical SIMD values since we must throw a TypeError.
- __ Branch(slow, eq, t4, Operand(SIMD128_VALUE_TYPE));
- if (is_strong(strength)) {
- // Call the runtime on anything that is converted in the semantics,
- // since we need to throw a TypeError. Smis and heap numbers have
- // already been ruled out.
- __ And(t4, t4, Operand(kIsNotStringMask));
- __ Branch(slow, ne, t4, Operand(zero_reg));
- }
+ __ Branch(slow, greater, t4, Operand(FIRST_JS_RECEIVER_TYPE));
+ // Call runtime on identical symbols since we need to throw a TypeError.
+ __ Branch(slow, eq, t4, Operand(SYMBOL_TYPE));
+ // Call runtime on identical SIMD values since we must throw a TypeError.
+ __ Branch(slow, eq, t4, Operand(SIMD128_VALUE_TYPE));
// Normally here we fall through to return_equal, but undefined is
// special: (undefined == undefined) == true, but
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
@@ -514,45 +499,55 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
// Fast negative check for internalized-to-internalized equality.
static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
- Register lhs,
- Register rhs,
+ Register lhs, Register rhs,
Label* possible_strings,
- Label* not_both_strings) {
+ Label* runtime_call) {
DCHECK((lhs.is(a0) && rhs.is(a1)) ||
(lhs.is(a1) && rhs.is(a0)));
// a2 is object type of rhs.
- Label object_test;
+ Label object_test, return_unequal, undetectable;
STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
__ And(at, a2, Operand(kIsNotStringMask));
__ Branch(&object_test, ne, at, Operand(zero_reg));
__ And(at, a2, Operand(kIsNotInternalizedMask));
__ Branch(possible_strings, ne, at, Operand(zero_reg));
__ GetObjectType(rhs, a3, a3);
- __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE));
+ __ Branch(runtime_call, ge, a3, Operand(FIRST_NONSTRING_TYPE));
__ And(at, a3, Operand(kIsNotInternalizedMask));
__ Branch(possible_strings, ne, at, Operand(zero_reg));
- // Both are internalized strings. We already checked they weren't the same
- // pointer so they are not equal.
+ // Both are internalized. We already checked they weren't the same pointer so
+ // they are not equal. Return non-equal by returning the non-zero object
+ // pointer in v0.
__ Ret(USE_DELAY_SLOT);
- __ li(v0, Operand(1)); // Non-zero indicates not equal.
+ __ mov(v0, a0); // In delay slot.
__ bind(&object_test);
- __ Branch(not_both_strings, lt, a2, Operand(FIRST_JS_RECEIVER_TYPE));
- __ GetObjectType(rhs, a2, a3);
- __ Branch(not_both_strings, lt, a3, Operand(FIRST_JS_RECEIVER_TYPE));
-
- // If both objects are undetectable, they are equal. Otherwise, they
- // are not equal, since they are different objects and an object is not
- // equal to undefined.
- __ lw(a3, FieldMemOperand(lhs, HeapObject::kMapOffset));
- __ lbu(a2, FieldMemOperand(a2, Map::kBitFieldOffset));
- __ lbu(a3, FieldMemOperand(a3, Map::kBitFieldOffset));
- __ and_(a0, a2, a3);
- __ And(a0, a0, Operand(1 << Map::kIsUndetectable));
+ __ lw(a2, FieldMemOperand(lhs, HeapObject::kMapOffset));
+ __ lw(a3, FieldMemOperand(rhs, HeapObject::kMapOffset));
+ __ lbu(t0, FieldMemOperand(a2, Map::kBitFieldOffset));
+ __ lbu(t1, FieldMemOperand(a3, Map::kBitFieldOffset));
+ __ And(at, t0, Operand(1 << Map::kIsUndetectable));
+ __ Branch(&undetectable, ne, at, Operand(zero_reg));
+ __ And(at, t1, Operand(1 << Map::kIsUndetectable));
+ __ Branch(&return_unequal, ne, at, Operand(zero_reg));
+
+ __ GetInstanceType(a2, a2);
+ __ Branch(runtime_call, lt, a2, Operand(FIRST_JS_RECEIVER_TYPE));
+ __ GetInstanceType(a3, a3);
+ __ Branch(runtime_call, lt, a3, Operand(FIRST_JS_RECEIVER_TYPE));
+
+ __ bind(&return_unequal);
+ // Return non-equal by returning the non-zero object pointer in v0.
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a0); // In delay slot.
+
+ __ bind(&undetectable);
+ __ And(at, t1, Operand(1 << Map::kIsUndetectable));
+ __ Branch(&return_unequal, eq, at, Operand(zero_reg));
__ Ret(USE_DELAY_SLOT);
- __ xori(v0, a0, 1 << Map::kIsUndetectable);
+ __ li(v0, Operand(EQUAL)); // In delay slot.
}
@@ -603,7 +598,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
// Handle the case where the objects are identical. Either returns the answer
// or goes to slow. Only falls through if the objects were not identical.
- EmitIdenticalObjectComparison(masm, &slow, cc, strength());
+ EmitIdenticalObjectComparison(masm, &slow, cc);
// If either is a Smi (we know that not both are), then they can only
// be strictly equal if the other is a HeapNumber.
@@ -742,8 +737,7 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
// Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
// tagged as a small integer.
- __ TailCallRuntime(is_strong(strength()) ? Runtime::kCompare_Strong
- : Runtime::kCompare);
+ __ TailCallRuntime(Runtime::kCompare);
}
__ bind(&miss);
@@ -973,7 +967,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ cvt_d_w(double_exponent, single_scratch);
// Returning or bailing out.
- Counters* counters = isolate()->counters();
if (exponent_type() == ON_STACK) {
// The arguments are still on the stack.
__ bind(&call_runtime);
@@ -987,7 +980,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ sdc1(double_result,
FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
DCHECK(heapnumber.is(v0));
- __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
__ DropAndRet(2);
} else {
__ push(ra);
@@ -1003,7 +995,6 @@ void MathPowStub::Generate(MacroAssembler* masm) {
__ MovFromFloatResult(double_result);
__ bind(&done);
- __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
__ Ret();
}
}
@@ -1075,8 +1066,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
__ mov(s1, a2);
} else {
// Compute the argv pointer in a callee-saved register.
- __ sll(s1, a0, kPointerSizeLog2);
- __ Addu(s1, sp, s1);
+ __ Lsa(s1, sp, a0, kPointerSizeLog2);
__ Subu(s1, s1, kPointerSize);
}
@@ -1092,48 +1082,77 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// a0 = argc
__ mov(s0, a0);
__ mov(s2, a1);
- // a1 = argv (set in the delay slot after find_ra below).
// We are calling compiled C/C++ code. a0 and a1 hold our two arguments. We
// also need to reserve the 4 argument slots on the stack.
__ AssertStackIsAligned();
- __ li(a2, Operand(ExternalReference::isolate_address(isolate())));
+ int frame_alignment = MacroAssembler::ActivationFrameAlignment();
+ int frame_alignment_mask = frame_alignment - 1;
+ int result_stack_size;
+ if (result_size() <= 2) {
+ // a0 = argc, a1 = argv, a2 = isolate
+ __ li(a2, Operand(ExternalReference::isolate_address(isolate())));
+ __ mov(a1, s1);
+ result_stack_size = 0;
+ } else {
+ DCHECK_EQ(3, result_size());
+ // Allocate additional space for the result.
+ result_stack_size =
+ ((result_size() * kPointerSize) + frame_alignment_mask) &
+ ~frame_alignment_mask;
+ __ Subu(sp, sp, Operand(result_stack_size));
+
+ // a0 = hidden result argument, a1 = argc, a2 = argv, a3 = isolate.
+ __ li(a3, Operand(ExternalReference::isolate_address(isolate())));
+ __ mov(a2, s1);
+ __ mov(a1, a0);
+ __ mov(a0, sp);
+ }
// To let the GC traverse the return address of the exit frames, we need to
// know where the return address is. The CEntryStub is unmovable, so
// we can store the address on the stack to be able to find it again and
// we never have to restore it, because it will not change.
{ Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
- // This branch-and-link sequence is needed to find the current PC on mips,
- // saved to the ra register.
- // Use masm-> here instead of the double-underscore macro since extra
- // coverage code can interfere with the proper calculation of ra.
+ int kNumInstructionsToJump = 4;
Label find_ra;
- masm->bal(&find_ra); // bal exposes branch delay slot.
- masm->mov(a1, s1);
- masm->bind(&find_ra);
-
// Adjust the value in ra to point to the correct return location, 2nd
// instruction past the real call into C code (the jalr(t9)), and push it.
// This is the return address of the exit frame.
- const int kNumInstructionsToJump = 5;
- masm->Addu(ra, ra, kNumInstructionsToJump * kPointerSize);
- masm->sw(ra, MemOperand(sp)); // This spot was reserved in EnterExitFrame.
+ if (kArchVariant >= kMips32r6) {
+ __ addiupc(ra, kNumInstructionsToJump + 1);
+ } else {
+ // This branch-and-link sequence is needed to find the current PC on mips
+ // before r6, saved to the ra register.
+ __ bal(&find_ra); // bal exposes branch delay slot.
+ __ Addu(ra, ra, kNumInstructionsToJump * Instruction::kInstrSize);
+ }
+ __ bind(&find_ra);
+
+ // This spot was reserved in EnterExitFrame.
+ __ sw(ra, MemOperand(sp, result_stack_size));
// Stack space reservation moved to the branch delay slot below.
// Stack is still aligned.
// Call the C routine.
- masm->mov(t9, s2); // Function pointer to t9 to conform to ABI for PIC.
- masm->jalr(t9);
+ __ mov(t9, s2); // Function pointer to t9 to conform to ABI for PIC.
+ __ jalr(t9);
// Set up sp in the delay slot.
- masm->addiu(sp, sp, -kCArgsSlotsSize);
+ __ addiu(sp, sp, -kCArgsSlotsSize);
// Make sure the stored 'ra' points to this position.
DCHECK_EQ(kNumInstructionsToJump,
masm->InstructionsGeneratedSince(&find_ra));
}
-
+ if (result_size() > 2) {
+ DCHECK_EQ(3, result_size());
+ // Read result values stored on stack.
+ __ lw(a0, MemOperand(v0, 2 * kPointerSize));
+ __ lw(v1, MemOperand(v0, 1 * kPointerSize));
+ __ lw(v0, MemOperand(v0, 0 * kPointerSize));
+ }
+ // Result returned in v0, v1:v0 or a0:v1:v0 - do not destroy these registers!
// Check result for exception sentinel.
Label exception_returned;
@@ -1556,303 +1575,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
}
-void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
- // The displacement is the offset of the last parameter (if any)
- // relative to the frame pointer.
- const int kDisplacement =
- StandardFrameConstants::kCallerSPOffset - kPointerSize;
- DCHECK(a1.is(ArgumentsAccessReadDescriptor::index()));
- DCHECK(a0.is(ArgumentsAccessReadDescriptor::parameter_count()));
-
- // Check that the key is a smiGenerateReadElement.
- Label slow;
- __ JumpIfNotSmi(a1, &slow);
-
- // Check if the calling frame is an arguments adaptor frame.
- Label adaptor;
- __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
- __ Branch(&adaptor,
- eq,
- a3,
- Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Check index (a1) against formal parameters count limit passed in
- // through register a0. Use unsigned comparison to get negative
- // check for free.
- __ Branch(&slow, hs, a1, Operand(a0));
-
- // Read the argument from the stack and return it.
- __ subu(a3, a0, a1);
- __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(a3, fp, Operand(t3));
- __ Ret(USE_DELAY_SLOT);
- __ lw(v0, MemOperand(a3, kDisplacement));
-
- // Arguments adaptor case: Check index (a1) against actual arguments
- // limit found in the arguments adaptor frame. Use unsigned
- // comparison to get negative check for free.
- __ bind(&adaptor);
- __ lw(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ Branch(&slow, Ugreater_equal, a1, Operand(a0));
-
- // Read the argument from the adaptor frame and return it.
- __ subu(a3, a0, a1);
- __ sll(t3, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(a3, a2, Operand(t3));
- __ Ret(USE_DELAY_SLOT);
- __ lw(v0, MemOperand(a3, kDisplacement));
-
- // Slow-case: Handle non-smi or out-of-bounds access to arguments
- // by calling the runtime system.
- __ bind(&slow);
- __ push(a1);
- __ TailCallRuntime(Runtime::kArguments);
-}
-
-
-void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
- // a1 : function
- // a2 : number of parameters (tagged)
- // a3 : parameters pointer
-
- DCHECK(a1.is(ArgumentsAccessNewDescriptor::function()));
- DCHECK(a2.is(ArgumentsAccessNewDescriptor::parameter_count()));
- DCHECK(a3.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
-
- // Check if the calling frame is an arguments adaptor frame.
- Label runtime;
- __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(a0, MemOperand(t0, StandardFrameConstants::kContextOffset));
- __ Branch(&runtime, ne, a0,
- Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Patch the arguments.length and the parameters pointer in the current frame.
- __ lw(a2, MemOperand(t0, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ sll(t3, a2, 1);
- __ Addu(t0, t0, Operand(t3));
- __ addiu(a3, t0, StandardFrameConstants::kCallerSPOffset);
-
- __ bind(&runtime);
- __ Push(a1, a3, a2);
- __ TailCallRuntime(Runtime::kNewSloppyArguments);
-}
-
-
-void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
- // a1 : function
- // a2 : number of parameters (tagged)
- // a3 : parameters pointer
- // Registers used over whole function:
- // t1 : arguments count (tagged)
- // t2 : mapped parameter count (tagged)
-
- DCHECK(a1.is(ArgumentsAccessNewDescriptor::function()));
- DCHECK(a2.is(ArgumentsAccessNewDescriptor::parameter_count()));
- DCHECK(a3.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
-
- // Check if the calling frame is an arguments adaptor frame.
- Label adaptor_frame, try_allocate, runtime;
- __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(a0, MemOperand(t0, StandardFrameConstants::kContextOffset));
- __ Branch(&adaptor_frame, eq, a0,
- Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // No adaptor, parameter count = argument count.
- __ mov(t1, a2);
- __ Branch(USE_DELAY_SLOT, &try_allocate);
- __ mov(t2, a2); // In delay slot.
-
- // We have an adaptor frame. Patch the parameters pointer.
- __ bind(&adaptor_frame);
- __ lw(t1, MemOperand(t0, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ sll(t6, t1, 1);
- __ Addu(t0, t0, Operand(t6));
- __ Addu(a3, t0, Operand(StandardFrameConstants::kCallerSPOffset));
-
- // t1 = argument count (tagged)
- // t2 = parameter count (tagged)
- // Compute the mapped parameter count = min(t2, t1) in t2.
- __ mov(t2, a2);
- __ Branch(&try_allocate, le, t2, Operand(t1));
- __ mov(t2, t1);
-
- __ bind(&try_allocate);
-
- // Compute the sizes of backing store, parameter map, and arguments object.
- // 1. Parameter map, has 2 extra words containing context and backing store.
- const int kParameterMapHeaderSize =
- FixedArray::kHeaderSize + 2 * kPointerSize;
- // If there are no mapped parameters, we do not need the parameter_map.
- Label param_map_size;
- DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
- __ Branch(USE_DELAY_SLOT, &param_map_size, eq, t2, Operand(zero_reg));
- __ mov(t5, zero_reg); // In delay slot: param map size = 0 when t2 == 0.
- __ sll(t5, t2, 1);
- __ addiu(t5, t5, kParameterMapHeaderSize);
- __ bind(&param_map_size);
-
- // 2. Backing store.
- __ sll(t6, t1, 1);
- __ Addu(t5, t5, Operand(t6));
- __ Addu(t5, t5, Operand(FixedArray::kHeaderSize));
-
- // 3. Arguments object.
- __ Addu(t5, t5, Operand(Heap::kSloppyArgumentsObjectSize));
-
- // Do the allocation of all three objects in one go.
- __ Allocate(t5, v0, t5, t0, &runtime, TAG_OBJECT);
-
- // v0 = address of new object(s) (tagged)
- // a2 = argument count (smi-tagged)
- // Get the arguments boilerplate from the current native context into t0.
- const int kNormalOffset =
- Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
- const int kAliasedOffset =
- Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
-
- __ lw(t0, NativeContextMemOperand());
- Label skip2_ne, skip2_eq;
- __ Branch(&skip2_ne, ne, t2, Operand(zero_reg));
- __ lw(t0, MemOperand(t0, kNormalOffset));
- __ bind(&skip2_ne);
-
- __ Branch(&skip2_eq, eq, t2, Operand(zero_reg));
- __ lw(t0, MemOperand(t0, kAliasedOffset));
- __ bind(&skip2_eq);
-
- // v0 = address of new object (tagged)
- // a2 = argument count (smi-tagged)
- // t0 = address of arguments map (tagged)
- // t2 = mapped parameter count (tagged)
- __ sw(t0, FieldMemOperand(v0, JSObject::kMapOffset));
- __ LoadRoot(t5, Heap::kEmptyFixedArrayRootIndex);
- __ sw(t5, FieldMemOperand(v0, JSObject::kPropertiesOffset));
- __ sw(t5, FieldMemOperand(v0, JSObject::kElementsOffset));
-
- // Set up the callee in-object property.
- STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
- __ AssertNotSmi(a1);
- const int kCalleeOffset = JSObject::kHeaderSize +
- Heap::kArgumentsCalleeIndex * kPointerSize;
- __ sw(a1, FieldMemOperand(v0, kCalleeOffset));
-
- // Use the length (smi tagged) and set that as an in-object property too.
- __ AssertSmi(t1);
- STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
- const int kLengthOffset = JSObject::kHeaderSize +
- Heap::kArgumentsLengthIndex * kPointerSize;
- __ sw(t1, FieldMemOperand(v0, kLengthOffset));
-
- // 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::kSloppyArgumentsObjectSize));
- __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
-
- // v0 = address of new object (tagged)
- // a2 = argument count (tagged)
- // t0 = address of parameter map or backing store (tagged)
- // t2 = mapped parameter count (tagged)
- // Initialize parameter map. If there are no mapped arguments, we're done.
- Label skip_parameter_map;
- Label skip3;
- __ Branch(&skip3, ne, t2, Operand(Smi::FromInt(0)));
- // Move backing store address to a1, because it is
- // expected there when filling in the unmapped arguments.
- __ mov(a1, t0);
- __ bind(&skip3);
-
- __ Branch(&skip_parameter_map, eq, t2, Operand(Smi::FromInt(0)));
-
- __ LoadRoot(t1, Heap::kSloppyArgumentsElementsMapRootIndex);
- __ sw(t1, FieldMemOperand(t0, FixedArray::kMapOffset));
- __ Addu(t1, t2, Operand(Smi::FromInt(2)));
- __ sw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
- __ sw(cp, FieldMemOperand(t0, FixedArray::kHeaderSize + 0 * kPointerSize));
- __ sll(t6, t2, 1);
- __ Addu(t1, t0, Operand(t6));
- __ Addu(t1, t1, Operand(kParameterMapHeaderSize));
- __ sw(t1, FieldMemOperand(t0, FixedArray::kHeaderSize + 1 * kPointerSize));
-
- // Copy the parameter slots and the holes in the arguments.
- // We need to fill in mapped_parameter_count slots. They index the context,
- // where parameters are stored in reverse order, at
- // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
- // The mapped parameter thus need to get indices
- // MIN_CONTEXT_SLOTS+parameter_count-1 ..
- // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
- // We loop from right to left.
- Label parameters_loop, parameters_test;
- __ mov(t1, t2);
- __ Addu(t5, a2, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
- __ Subu(t5, t5, Operand(t2));
- __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
- __ sll(t6, t1, 1);
- __ Addu(a1, t0, Operand(t6));
- __ Addu(a1, a1, Operand(kParameterMapHeaderSize));
-
- // a1 = address of backing store (tagged)
- // t0 = address of parameter map (tagged)
- // a0 = temporary scratch (a.o., for address calculation)
- // t1 = loop variable (tagged)
- // t3 = the hole value
- __ jmp(&parameters_test);
-
- __ bind(&parameters_loop);
- __ Subu(t1, t1, Operand(Smi::FromInt(1)));
- __ sll(a0, t1, 1);
- __ Addu(a0, a0, Operand(kParameterMapHeaderSize - kHeapObjectTag));
- __ Addu(t6, t0, a0);
- __ sw(t5, MemOperand(t6));
- __ Subu(a0, a0, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
- __ Addu(t6, a1, a0);
- __ sw(t3, MemOperand(t6));
- __ Addu(t5, t5, Operand(Smi::FromInt(1)));
- __ bind(&parameters_test);
- __ Branch(&parameters_loop, ne, t1, Operand(Smi::FromInt(0)));
-
- // t1 = argument count (tagged).
- __ lw(t1, FieldMemOperand(v0, kLengthOffset));
-
- __ bind(&skip_parameter_map);
- // v0 = address of new object (tagged)
- // a1 = address of backing store (tagged)
- // t1 = argument count (tagged)
- // t2 = mapped parameter count (tagged)
- // t5 = scratch
- // Copy arguments header and remaining slots (if there are any).
- __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex);
- __ sw(t5, FieldMemOperand(a1, FixedArray::kMapOffset));
- __ sw(t1, FieldMemOperand(a1, FixedArray::kLengthOffset));
-
- Label arguments_loop, arguments_test;
- __ sll(t6, t2, 1);
- __ Subu(a3, a3, Operand(t6));
- __ jmp(&arguments_test);
-
- __ bind(&arguments_loop);
- __ Subu(a3, a3, Operand(kPointerSize));
- __ lw(t0, MemOperand(a3, 0));
- __ sll(t6, t2, 1);
- __ Addu(t5, a1, Operand(t6));
- __ sw(t0, FieldMemOperand(t5, FixedArray::kHeaderSize));
- __ Addu(t2, t2, Operand(Smi::FromInt(1)));
-
- __ bind(&arguments_test);
- __ Branch(&arguments_loop, lt, t2, Operand(t1));
-
- // Return.
- __ Ret();
-
- // Do the runtime call to allocate the arguments object.
- // t1 = argument count (tagged)
- __ bind(&runtime);
- __ Push(a1, a3, t1);
- __ TailCallRuntime(Runtime::kNewSloppyArguments);
-}
-
-
void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
// Return address is in ra.
Label slow;
@@ -1876,121 +1598,6 @@ void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
}
-void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
- // a1 : function
- // a2 : number of parameters (tagged)
- // a3 : parameters pointer
-
- DCHECK(a1.is(ArgumentsAccessNewDescriptor::function()));
- DCHECK(a2.is(ArgumentsAccessNewDescriptor::parameter_count()));
- DCHECK(a3.is(ArgumentsAccessNewDescriptor::parameter_pointer()));
-
- // Check if the calling frame is an arguments adaptor frame.
- Label try_allocate, runtime;
- __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(a0, MemOperand(t0, StandardFrameConstants::kContextOffset));
- __ Branch(&try_allocate, ne, a0,
- Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Patch the arguments.length and the parameters pointer.
- __ lw(a2, MemOperand(t0, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ sll(at, a2, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t0, t0, Operand(at));
- __ Addu(a3, t0, Operand(StandardFrameConstants::kCallerSPOffset));
-
- // Try the new space allocation. Start out with computing the size
- // of the arguments object and the elements array in words.
- Label add_arguments_object;
- __ bind(&try_allocate);
- __ SmiUntag(t5, a2);
- __ Branch(&add_arguments_object, eq, a2, Operand(zero_reg));
-
- __ Addu(t5, t5, Operand(FixedArray::kHeaderSize / kPointerSize));
- __ bind(&add_arguments_object);
- __ Addu(t5, t5, Operand(Heap::kStrictArgumentsObjectSize / kPointerSize));
-
- // Do the allocation of both objects in one go.
- __ Allocate(t5, v0, t0, t1, &runtime,
- static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
-
- // Get the arguments boilerplate from the current native context.
- __ LoadNativeContextSlot(Context::STRICT_ARGUMENTS_MAP_INDEX, t0);
-
- __ sw(t0, FieldMemOperand(v0, JSObject::kMapOffset));
- __ LoadRoot(t1, Heap::kEmptyFixedArrayRootIndex);
- __ sw(t1, FieldMemOperand(v0, JSObject::kPropertiesOffset));
- __ sw(t1, FieldMemOperand(v0, JSObject::kElementsOffset));
-
- // Get the length (smi tagged) and set that as an in-object property too.
- STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
- __ AssertSmi(a2);
- __ sw(a2,
- FieldMemOperand(v0, JSObject::kHeaderSize +
- Heap::kArgumentsLengthIndex * kPointerSize));
-
- Label done;
- __ Branch(&done, eq, a2, Operand(zero_reg));
-
- // Set up the elements pointer in the allocated arguments object and
- // initialize the header in the elements fixed array.
- __ Addu(t0, v0, Operand(Heap::kStrictArgumentsObjectSize));
- __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
- __ LoadRoot(t1, Heap::kFixedArrayMapRootIndex);
- __ sw(t1, FieldMemOperand(t0, FixedArray::kMapOffset));
- __ sw(a2, FieldMemOperand(t0, FixedArray::kLengthOffset));
- __ SmiUntag(a2);
-
- // Copy the fixed array slots.
- Label loop;
- // Set up t0 to point to the first array slot.
- __ Addu(t0, t0, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
- __ bind(&loop);
- // Pre-decrement a3 with kPointerSize on each iteration.
- // Pre-decrement in order to skip receiver.
- __ Addu(a3, a3, Operand(-kPointerSize));
- __ lw(t1, MemOperand(a3));
- // Post-increment t0 with kPointerSize on each iteration.
- __ sw(t1, MemOperand(t0));
- __ Addu(t0, t0, Operand(kPointerSize));
- __ Subu(a2, a2, Operand(1));
- __ Branch(&loop, ne, a2, Operand(zero_reg));
-
- // Return.
- __ bind(&done);
- __ Ret();
-
- // Do the runtime call to allocate the arguments object.
- __ bind(&runtime);
- __ Push(a1, a3, a2);
- __ TailCallRuntime(Runtime::kNewStrictArguments);
-}
-
-
-void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
- // a2 : number of parameters (tagged)
- // a3 : parameters pointer
- // a1 : rest parameter index (tagged)
- // Check if the calling frame is an arguments adaptor frame.
-
- Label runtime;
- __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(t1, MemOperand(t0, StandardFrameConstants::kContextOffset));
- __ Branch(&runtime, ne, t1,
- Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Patch the arguments.length and the parameters pointer.
- __ lw(a2, MemOperand(t0, ArgumentsAdaptorFrameConstants::kLengthOffset));
- __ sll(t1, a2, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(a3, t0, Operand(t1));
- __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
-
- // Do the runtime call to allocate the arguments object.
- __ bind(&runtime);
- __ Push(a2, a3, a1);
- __ TailCallRuntime(Runtime::kNewRestParam);
-}
-
-
void RegExpExecStub::Generate(MacroAssembler* masm) {
// Just jump directly to runtime if native RegExp is not selected at compile
// time or if regexp entry in generated code is turned off runtime switch or
@@ -2461,8 +2068,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
masm->isolate()->heap()->uninitialized_symbol());
// Load the cache state into t2.
- __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t2, a2, Operand(t2));
+ __ Lsa(t2, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(t2, FieldMemOperand(t2, FixedArray::kHeaderSize));
// A monomorphic cache hit or an already megamorphic state: invoke the
@@ -2506,8 +2112,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// MegamorphicSentinel is an immortal immovable object (undefined) so no
// write-barrier is needed.
__ bind(&megamorphic);
- __ sll(t2, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t2, a2, Operand(t2));
+ __ Lsa(t2, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sw(at, FieldMemOperand(t2, FixedArray::kHeaderSize));
__ jmp(&done);
@@ -2547,8 +2152,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
GenerateRecordCallTarget(masm);
- __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t1, a2, at);
+ __ Lsa(t1, a2, a3, kPointerSizeLog2 - kSmiTagSize);
Label feedback_register_initialized;
// Put the AllocationSite from the feedback vector into a2, or undefined.
__ lw(a2, FieldMemOperand(t1, FixedArray::kHeaderSize));
@@ -2587,8 +2191,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ li(a0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
- __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(at, a2, Operand(at));
+ __ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ Addu(a3, a3, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ sw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
@@ -2609,8 +2212,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
ParameterCount actual(argc);
// The checks. First, does r1 match the recorded monomorphic target?
- __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t0, a2, Operand(t0));
+ __ Lsa(t0, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(t0, FieldMemOperand(t0, FixedArray::kHeaderSize));
// We don't know that we have a weak cell. We might have a private symbol
@@ -2635,14 +2237,14 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ JumpIfSmi(a1, &extra_checks_or_miss);
// Increment the call count for monomorphic function calls.
- __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(at, a2, Operand(at));
+ __ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ Addu(a3, a3, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ sw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ bind(&call_function);
- __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode()),
+ __ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
+ tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
@@ -2676,13 +2278,12 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ AssertNotSmi(t0);
__ GetObjectType(t0, t1, t1);
__ Branch(&miss, ne, t1, Operand(JS_FUNCTION_TYPE));
- __ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(t0, a2, Operand(t0));
+ __ Lsa(t0, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
__ bind(&call);
- __ Jump(masm->isolate()->builtins()->Call(convert_mode()),
+ __ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
__ li(a0, Operand(argc)); // In delay slot.
@@ -2708,8 +2309,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Branch(&miss, ne, t0, Operand(t1));
// Initialize the call counter.
- __ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(at, a2, Operand(at));
+ __ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ li(t0, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ sw(t0, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
@@ -2873,8 +2473,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
// At this point code register contains smi tagged one-byte char code.
STATIC_ASSERT(kSmiTag == 0);
- __ sll(t0, code_, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(result_, result_, t0);
+ __ Lsa(result_, result_, code_, kPointerSizeLog2 - kSmiTagSize);
__ lw(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
__ LoadRoot(t0, Heap::kUndefinedValueRootIndex);
__ Branch(&slow_case_, eq, result_, Operand(t0));
@@ -3131,8 +2730,7 @@ void SubStringStub::Generate(MacroAssembler* masm) {
// Locate first character of substring to copy.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
- __ sll(t0, a3, 1);
- __ Addu(t1, t1, t0);
+ __ Lsa(t1, t1, a3, 1);
// Locate first character of result.
__ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
@@ -3259,6 +2857,39 @@ void ToStringStub::Generate(MacroAssembler* masm) {
}
+void ToNameStub::Generate(MacroAssembler* masm) {
+ // The ToName stub takes on argument in a0.
+ Label is_number;
+ __ JumpIfSmi(a0, &is_number);
+
+ Label not_name;
+ STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
+ __ GetObjectType(a0, a1, a1);
+ // a0: receiver
+ // a1: receiver instance type
+ __ Branch(&not_name, gt, a1, Operand(LAST_NAME_TYPE));
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a0);
+ __ bind(&not_name);
+
+ Label not_heap_number;
+ __ Branch(&not_heap_number, ne, a1, Operand(HEAP_NUMBER_TYPE));
+ __ bind(&is_number);
+ NumberToStringStub stub(isolate());
+ __ TailCallStub(&stub);
+ __ bind(&not_heap_number);
+
+ Label not_oddball;
+ __ Branch(&not_oddball, ne, a1, Operand(ODDBALL_TYPE));
+ __ Ret(USE_DELAY_SLOT);
+ __ lw(v0, FieldMemOperand(a0, Oddball::kToStringOffset));
+ __ bind(&not_oddball);
+
+ __ push(a0); // Push argument.
+ __ TailCallRuntime(Runtime::kToName);
+}
+
+
void StringHelper::GenerateFlatOneByteStringEquals(
MacroAssembler* masm, Register left, Register right, Register scratch1,
Register scratch2, Register scratch3) {
@@ -3431,18 +3062,14 @@ void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
__ CheckMap(a1, a2, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
__ CheckMap(a0, a3, Heap::kBooleanMapRootIndex, &miss, DO_SMI_CHECK);
- if (op() != Token::EQ_STRICT && is_strong(strength())) {
- __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion);
- } else {
- if (!Token::IsEqualityOp(op())) {
- __ lw(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
- __ AssertSmi(a1);
- __ lw(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
- __ AssertSmi(a0);
- }
- __ Ret(USE_DELAY_SLOT);
- __ Subu(v0, a1, a0);
+ if (!Token::IsEqualityOp(op())) {
+ __ lw(a1, FieldMemOperand(a1, Oddball::kToNumberOffset));
+ __ AssertSmi(a1);
+ __ lw(a0, FieldMemOperand(a0, Oddball::kToNumberOffset));
+ __ AssertSmi(a0);
}
+ __ Ret(USE_DELAY_SLOT);
+ __ Subu(v0, a1, a0);
__ bind(&miss);
GenerateMiss(masm);
@@ -3540,7 +3167,7 @@ void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
__ bind(&unordered);
__ bind(&generic_stub);
- CompareICStub stub(isolate(), op(), strength(), CompareICState::GENERIC,
+ CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
CompareICState::GENERIC, CompareICState::GENERIC);
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
@@ -3770,8 +3397,6 @@ void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) {
if (Token::IsEqualityOp(op())) {
__ Ret(USE_DELAY_SLOT);
__ subu(v0, a0, a1);
- } else if (is_strong(strength())) {
- __ TailCallRuntime(Runtime::kThrowStrongModeImplicitConversion);
} else {
if (op() == Token::LT || op() == Token::LTE) {
__ li(a2, Operand(Smi::FromInt(GREATER)));
@@ -3867,15 +3492,13 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
- __ sll(at, index, 1);
- __ Addu(index, index, at);
+ __ Lsa(index, index, index, 1);
Register entity_name = scratch0;
// Having undefined at this place means the name is not contained.
STATIC_ASSERT(kSmiTagSize == 1);
Register tmp = properties;
- __ sll(scratch0, index, 1);
- __ Addu(tmp, properties, scratch0);
+ __ Lsa(tmp, properties, index, 1);
__ lw(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
DCHECK(!tmp.is(entity_name));
@@ -3965,12 +3588,10 @@ void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm,
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// scratch2 = scratch2 * 3.
- __ sll(at, scratch2, 1);
- __ Addu(scratch2, scratch2, at);
+ __ Lsa(scratch2, scratch2, scratch2, 1);
// Check if the key is identical to the name.
- __ sll(at, scratch2, 2);
- __ Addu(scratch2, elements, at);
+ __ Lsa(scratch2, elements, scratch2, 2);
__ lw(at, FieldMemOperand(scratch2, kElementsStartOffset));
__ Branch(done, eq, name, Operand(at));
}
@@ -4051,14 +3672,10 @@ void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
// Scale the index by multiplying by the entry size.
STATIC_ASSERT(NameDictionary::kEntrySize == 3);
// index *= 3.
- __ mov(at, index);
- __ sll(index, index, 1);
- __ Addu(index, index, at);
-
+ __ Lsa(index, index, index, 1);
STATIC_ASSERT(kSmiTagSize == 1);
- __ sll(index, index, 2);
- __ Addu(index, index, dictionary);
+ __ Lsa(index, dictionary, index, 2);
__ lw(entry_key, FieldMemOperand(index, kElementsStartOffset));
// Having undefined at this place means the name is not contained.
@@ -4158,11 +3775,8 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
regs_.scratch0(),
&dont_need_remembered_set);
- __ CheckPageFlag(regs_.object(),
- regs_.scratch0(),
- 1 << MemoryChunk::SCAN_ON_SCAVENGE,
- ne,
- &dont_need_remembered_set);
+ __ JumpIfInNewSpace(regs_.object(), regs_.scratch0(),
+ &dont_need_remembered_set);
// First notify the incremental marker if necessary, then update the
// remembered set.
@@ -4382,8 +3996,7 @@ static void HandleArrayCases(MacroAssembler* masm, Register feedback,
// aka feedback scratch2
// also need receiver_map
// use cached_map (scratch1) to look in the weak map values.
- __ sll(at, length, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(too_far, feedback, Operand(at));
+ __ Lsa(too_far, feedback, length, kPointerSizeLog2 - kSmiTagSize);
__ Addu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ Addu(pointer_reg, feedback,
Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
@@ -4419,8 +4032,7 @@ static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
__ Branch(try_array, ne, cached_map, Operand(receiver_map));
Register handler = feedback;
- __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(handler, vector, Operand(at));
+ __ Lsa(handler, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(handler,
FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
__ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
@@ -4437,8 +4049,7 @@ void LoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver_map = t1;
Register scratch1 = t4;
- __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(at));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
// Try to quickly handle the monomorphic case without knowing for sure
@@ -4493,8 +4104,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver_map = t1;
Register scratch1 = t4;
- __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(at));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
// Try to quickly handle the monomorphic case without knowing for sure
@@ -4530,8 +4140,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ Branch(&miss, ne, key, Operand(feedback));
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
- __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(at));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback,
FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
HandleArrayCases(masm, feedback, receiver_map, scratch1, t5, false, &miss);
@@ -4579,8 +4188,7 @@ void VectorStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver_map = t2;
Register scratch1 = t5;
- __ sll(scratch1, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(scratch1));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
// Try to quickly handle the monomorphic case without knowing for sure
@@ -4652,8 +4260,7 @@ static void HandlePolymorphicStoreCase(MacroAssembler* masm, Register feedback,
// aka feedback scratch2
// also need receiver_map
// use cached_map (scratch1) to look in the weak map values.
- __ sll(scratch1, too_far, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(too_far, feedback, Operand(scratch1));
+ __ Lsa(too_far, feedback, too_far, kPointerSizeLog2 - kSmiTagSize);
__ Addu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ Addu(pointer_reg, feedback,
Operand(FixedArray::OffsetOfElementAt(0) - kHeapObjectTag));
@@ -4702,8 +4309,7 @@ void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver_map = t2;
Register scratch1 = t5;
- __ sll(scratch1, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(scratch1));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
// Try to quickly handle the monomorphic case without knowing for sure
@@ -4742,8 +4348,7 @@ void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
__ Branch(&miss, ne, key, Operand(feedback));
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
- __ sll(scratch1, slot, kPointerSizeLog2 - kSmiTagSize);
- __ Addu(feedback, vector, Operand(scratch1));
+ __ Lsa(feedback, vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(feedback,
FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
HandleArrayCases(masm, feedback, receiver_map, scratch1, scratch2, false,
@@ -5050,8 +4655,7 @@ void ArrayConstructorStub::Generate(MacroAssembler* masm) {
switch (argument_count()) {
case ANY:
case MORE_THAN_ONE:
- __ sll(at, a0, kPointerSizeLog2);
- __ addu(at, sp, at);
+ __ Lsa(at, sp, a0, kPointerSizeLog2);
__ sw(a1, MemOperand(at));
__ li(at, Operand(3));
__ addu(a0, a0, at);
@@ -5144,6 +4748,592 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
}
+void FastNewObjectStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a1 : target
+ // -- a3 : new target
+ // -- cp : context
+ // -- ra : return address
+ // -----------------------------------
+ __ AssertFunction(a1);
+ __ AssertReceiver(a3);
+
+ // Verify that the new target is a JSFunction.
+ Label new_object;
+ __ GetObjectType(a3, a2, a2);
+ __ Branch(&new_object, ne, a2, Operand(JS_FUNCTION_TYPE));
+
+ // Load the initial map and verify that it's in fact a map.
+ __ lw(a2, FieldMemOperand(a3, JSFunction::kPrototypeOrInitialMapOffset));
+ __ JumpIfSmi(a2, &new_object);
+ __ GetObjectType(a2, a0, a0);
+ __ Branch(&new_object, ne, a0, Operand(MAP_TYPE));
+
+ // Fall back to runtime if the target differs from the new target's
+ // initial map constructor.
+ __ lw(a0, FieldMemOperand(a2, Map::kConstructorOrBackPointerOffset));
+ __ Branch(&new_object, ne, a0, Operand(a1));
+
+ // Allocate the JSObject on the heap.
+ Label allocate, done_allocate;
+ __ lbu(t0, FieldMemOperand(a2, Map::kInstanceSizeOffset));
+ __ Allocate(t0, v0, t1, a0, &allocate, SIZE_IN_WORDS);
+ __ bind(&done_allocate);
+
+ // Initialize the JSObject fields.
+ __ sw(a2, MemOperand(v0, JSObject::kMapOffset));
+ __ LoadRoot(a3, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(a3, MemOperand(v0, JSObject::kPropertiesOffset));
+ __ sw(a3, MemOperand(v0, JSObject::kElementsOffset));
+ STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize);
+ __ Addu(a1, v0, Operand(JSObject::kHeaderSize));
+
+ // ----------- S t a t e -------------
+ // -- v0 : result (untagged)
+ // -- a1 : result fields (untagged)
+ // -- t1 : result end (untagged)
+ // -- a2 : initial map
+ // -- cp : context
+ // -- ra : return address
+ // -----------------------------------
+
+ // Perform in-object slack tracking if requested.
+ Label slack_tracking;
+ STATIC_ASSERT(Map::kNoSlackTracking == 0);
+ __ lw(a3, FieldMemOperand(a2, Map::kBitField3Offset));
+ __ And(at, a3, Operand(Map::ConstructionCounter::kMask));
+ __ Branch(USE_DELAY_SLOT, &slack_tracking, ne, at, Operand(0));
+ __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); // In delay slot.
+ {
+ // Initialize all in-object fields with undefined.
+ __ InitializeFieldsWithFiller(a1, t1, a0);
+
+ // Add the object tag to make the JSObject real.
+ STATIC_ASSERT(kHeapObjectTag == 1);
+ __ Ret(USE_DELAY_SLOT);
+ __ Addu(v0, v0, Operand(kHeapObjectTag)); // In delay slot.
+ }
+ __ bind(&slack_tracking);
+ {
+ // Decrease generous allocation count.
+ STATIC_ASSERT(Map::ConstructionCounter::kNext == 32);
+ __ Subu(a3, a3, Operand(1 << Map::ConstructionCounter::kShift));
+ __ sw(a3, FieldMemOperand(a2, Map::kBitField3Offset));
+
+ // Initialize the in-object fields with undefined.
+ __ lbu(t0, FieldMemOperand(a2, Map::kUnusedPropertyFieldsOffset));
+ __ sll(t0, t0, kPointerSizeLog2);
+ __ subu(t0, t1, t0);
+ __ InitializeFieldsWithFiller(a1, t0, a0);
+
+ // Initialize the remaining (reserved) fields with one pointer filler map.
+ __ LoadRoot(a0, Heap::kOnePointerFillerMapRootIndex);
+ __ InitializeFieldsWithFiller(a1, t1, a0);
+
+ // Check if we can finalize the instance size.
+ Label finalize;
+ STATIC_ASSERT(Map::kSlackTrackingCounterEnd == 1);
+ __ And(a3, a3, Operand(Map::ConstructionCounter::kMask));
+ __ Branch(USE_DELAY_SLOT, &finalize, eq, a3, Operand(zero_reg));
+ STATIC_ASSERT(kHeapObjectTag == 1);
+ __ Addu(v0, v0, Operand(kHeapObjectTag)); // In delay slot.
+ __ Ret();
+
+ // Finalize the instance size.
+ __ bind(&finalize);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(v0, a2);
+ __ CallRuntime(Runtime::kFinalizeInstanceSize);
+ __ Pop(v0);
+ }
+ __ Ret();
+ }
+
+ // Fall back to %AllocateInNewSpace.
+ __ bind(&allocate);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagSize == 1);
+ __ sll(t0, t0, kPointerSizeLog2 + kSmiTagSize);
+ __ Push(a2, t0);
+ __ CallRuntime(Runtime::kAllocateInNewSpace);
+ __ Pop(a2);
+ }
+ STATIC_ASSERT(kHeapObjectTag == 1);
+ __ Subu(v0, v0, Operand(kHeapObjectTag));
+ __ lbu(t1, FieldMemOperand(a2, Map::kInstanceSizeOffset));
+ __ Lsa(t1, v0, t1, kPointerSizeLog2);
+ __ jmp(&done_allocate);
+
+ // Fall back to %NewObject.
+ __ bind(&new_object);
+ __ Push(a1, a3);
+ __ TailCallRuntime(Runtime::kNewObject);
+}
+
+
+void FastNewRestParameterStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a1 : function
+ // -- cp : context
+ // -- fp : frame pointer
+ // -- ra : return address
+ // -----------------------------------
+ __ AssertFunction(a1);
+
+ // For Ignition we need to skip all possible handler/stub frames until
+ // we reach the JavaScript frame for the function (similar to what the
+ // runtime fallback implementation does). So make a2 point to that
+ // JavaScript frame.
+ {
+ Label loop, loop_entry;
+ __ Branch(USE_DELAY_SLOT, &loop_entry);
+ __ mov(a2, fp); // In delay slot.
+ __ bind(&loop);
+ __ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
+ __ bind(&loop_entry);
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+ __ Branch(&loop, ne, a1, Operand(a3));
+ }
+
+ // Check if we have rest parameters (only possible if we have an
+ // arguments adaptor frame below the function frame).
+ Label no_rest_parameters;
+ __ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
+ __ Branch(&no_rest_parameters, ne, a3,
+ Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+
+ // Check if the arguments adaptor frame contains more arguments than
+ // specified by the function's internal formal parameter count.
+ Label rest_parameters;
+ __ lw(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
+ __ lw(a1, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a1,
+ FieldMemOperand(a1, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ Subu(a0, a0, Operand(a1));
+ __ Branch(&rest_parameters, gt, a0, Operand(zero_reg));
+
+ // Return an empty rest parameter array.
+ __ bind(&no_rest_parameters);
+ {
+ // ----------- S t a t e -------------
+ // -- cp : context
+ // -- ra : return address
+ // -----------------------------------
+
+ // Allocate an empty rest parameter array.
+ Label allocate, done_allocate;
+ __ Allocate(JSArray::kSize, v0, a0, a1, &allocate, TAG_OBJECT);
+ __ bind(&done_allocate);
+
+ // Setup the rest parameter array in v0.
+ __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, a1);
+ __ sw(a1, FieldMemOperand(v0, JSArray::kMapOffset));
+ __ LoadRoot(a1, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(a1, FieldMemOperand(v0, JSArray::kPropertiesOffset));
+ __ sw(a1, FieldMemOperand(v0, JSArray::kElementsOffset));
+ __ Move(a1, Smi::FromInt(0));
+ __ Ret(USE_DELAY_SLOT);
+ __ sw(a1, FieldMemOperand(v0, JSArray::kLengthOffset)); // In delay slot
+ STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
+
+ // Fall back to %AllocateInNewSpace.
+ __ bind(&allocate);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ Push(Smi::FromInt(JSArray::kSize));
+ __ CallRuntime(Runtime::kAllocateInNewSpace);
+ }
+ __ jmp(&done_allocate);
+ }
+
+ __ bind(&rest_parameters);
+ {
+ // Compute the pointer to the first rest parameter (skippping the receiver).
+ __ Lsa(a2, a2, a0, kPointerSizeLog2 - 1);
+ __ Addu(a2, a2, Operand(StandardFrameConstants::kCallerSPOffset -
+ 1 * kPointerSize));
+
+ // ----------- S t a t e -------------
+ // -- cp : context
+ // -- a0 : number of rest parameters (tagged)
+ // -- a2 : pointer to first rest parameters
+ // -- ra : return address
+ // -----------------------------------
+
+ // Allocate space for the rest parameter array plus the backing store.
+ Label allocate, done_allocate;
+ __ li(a1, Operand(JSArray::kSize + FixedArray::kHeaderSize));
+ __ Lsa(a1, a1, a0, kPointerSizeLog2 - 1);
+ __ Allocate(a1, v0, a3, t0, &allocate, TAG_OBJECT);
+ __ bind(&done_allocate);
+
+ // Setup the elements array in v0.
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ sw(at, FieldMemOperand(v0, FixedArray::kMapOffset));
+ __ sw(a0, FieldMemOperand(v0, FixedArray::kLengthOffset));
+ __ Addu(a3, v0, Operand(FixedArray::kHeaderSize));
+ {
+ Label loop, done_loop;
+ __ sll(at, a0, kPointerSizeLog2 - 1);
+ __ Addu(a1, a3, at);
+ __ bind(&loop);
+ __ Branch(&done_loop, eq, a1, Operand(a3));
+ __ lw(at, MemOperand(a2, 0 * kPointerSize));
+ __ sw(at, FieldMemOperand(a3, 0 * kPointerSize));
+ __ Subu(a2, a2, Operand(1 * kPointerSize));
+ __ Addu(a3, a3, Operand(1 * kPointerSize));
+ __ jmp(&loop);
+ __ bind(&done_loop);
+ }
+
+ // Setup the rest parameter array in a3.
+ __ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, at);
+ __ sw(at, FieldMemOperand(a3, JSArray::kMapOffset));
+ __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(at, FieldMemOperand(a3, JSArray::kPropertiesOffset));
+ __ sw(v0, FieldMemOperand(a3, JSArray::kElementsOffset));
+ __ sw(a0, FieldMemOperand(a3, JSArray::kLengthOffset));
+ STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a3); // In delay slot
+
+ // Fall back to %AllocateInNewSpace.
+ __ bind(&allocate);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ SmiTag(a1);
+ __ Push(a0, a2, a1);
+ __ CallRuntime(Runtime::kAllocateInNewSpace);
+ __ Pop(a0, a2);
+ }
+ __ jmp(&done_allocate);
+ }
+}
+
+
+void FastNewSloppyArgumentsStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a1 : function
+ // -- cp : context
+ // -- fp : frame pointer
+ // -- ra : return address
+ // -----------------------------------
+ __ AssertFunction(a1);
+
+ // TODO(bmeurer): Cleanup to match the FastNewStrictArgumentsStub.
+ __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a2,
+ FieldMemOperand(a2, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ Lsa(a3, fp, a2, kPointerSizeLog2 - 1);
+ __ Addu(a3, a3, Operand(StandardFrameConstants::kCallerSPOffset));
+
+ // a1 : function
+ // a2 : number of parameters (tagged)
+ // a3 : parameters pointer
+ // Registers used over whole function:
+ // t1 : arguments count (tagged)
+ // t2 : mapped parameter count (tagged)
+
+ // Check if the calling frame is an arguments adaptor frame.
+ Label adaptor_frame, try_allocate, runtime;
+ __ lw(t0, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+ __ lw(a0, MemOperand(t0, StandardFrameConstants::kContextOffset));
+ __ Branch(&adaptor_frame, eq, a0,
+ Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+
+ // No adaptor, parameter count = argument count.
+ __ mov(t1, a2);
+ __ Branch(USE_DELAY_SLOT, &try_allocate);
+ __ mov(t2, a2); // In delay slot.
+
+ // We have an adaptor frame. Patch the parameters pointer.
+ __ bind(&adaptor_frame);
+ __ lw(t1, MemOperand(t0, ArgumentsAdaptorFrameConstants::kLengthOffset));
+ __ Lsa(t0, t0, t1, 1);
+ __ Addu(a3, t0, Operand(StandardFrameConstants::kCallerSPOffset));
+
+ // t1 = argument count (tagged)
+ // t2 = parameter count (tagged)
+ // Compute the mapped parameter count = min(t2, t1) in t2.
+ __ mov(t2, a2);
+ __ Branch(&try_allocate, le, t2, Operand(t1));
+ __ mov(t2, t1);
+
+ __ bind(&try_allocate);
+
+ // Compute the sizes of backing store, parameter map, and arguments object.
+ // 1. Parameter map, has 2 extra words containing context and backing store.
+ const int kParameterMapHeaderSize =
+ FixedArray::kHeaderSize + 2 * kPointerSize;
+ // If there are no mapped parameters, we do not need the parameter_map.
+ Label param_map_size;
+ DCHECK_EQ(static_cast<Smi*>(0), Smi::FromInt(0));
+ __ Branch(USE_DELAY_SLOT, &param_map_size, eq, t2, Operand(zero_reg));
+ __ mov(t5, zero_reg); // In delay slot: param map size = 0 when t2 == 0.
+ __ sll(t5, t2, 1);
+ __ addiu(t5, t5, kParameterMapHeaderSize);
+ __ bind(&param_map_size);
+
+ // 2. Backing store.
+ __ Lsa(t5, t5, t1, 1);
+ __ Addu(t5, t5, Operand(FixedArray::kHeaderSize));
+
+ // 3. Arguments object.
+ __ Addu(t5, t5, Operand(JSSloppyArgumentsObject::kSize));
+
+ // Do the allocation of all three objects in one go.
+ __ Allocate(t5, v0, t5, t0, &runtime, TAG_OBJECT);
+
+ // v0 = address of new object(s) (tagged)
+ // a2 = argument count (smi-tagged)
+ // Get the arguments boilerplate from the current native context into t0.
+ const int kNormalOffset =
+ Context::SlotOffset(Context::SLOPPY_ARGUMENTS_MAP_INDEX);
+ const int kAliasedOffset =
+ Context::SlotOffset(Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
+
+ __ lw(t0, NativeContextMemOperand());
+ Label skip2_ne, skip2_eq;
+ __ Branch(&skip2_ne, ne, t2, Operand(zero_reg));
+ __ lw(t0, MemOperand(t0, kNormalOffset));
+ __ bind(&skip2_ne);
+
+ __ Branch(&skip2_eq, eq, t2, Operand(zero_reg));
+ __ lw(t0, MemOperand(t0, kAliasedOffset));
+ __ bind(&skip2_eq);
+
+ // v0 = address of new object (tagged)
+ // a2 = argument count (smi-tagged)
+ // t0 = address of arguments map (tagged)
+ // t2 = mapped parameter count (tagged)
+ __ sw(t0, FieldMemOperand(v0, JSObject::kMapOffset));
+ __ LoadRoot(t5, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(t5, FieldMemOperand(v0, JSObject::kPropertiesOffset));
+ __ sw(t5, FieldMemOperand(v0, JSObject::kElementsOffset));
+
+ // Set up the callee in-object property.
+ __ AssertNotSmi(a1);
+ __ sw(a1, FieldMemOperand(v0, JSSloppyArgumentsObject::kCalleeOffset));
+
+ // Use the length (smi tagged) and set that as an in-object property too.
+ __ AssertSmi(t1);
+ __ sw(t1, FieldMemOperand(v0, JSSloppyArgumentsObject::kLengthOffset));
+
+ // 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(JSSloppyArgumentsObject::kSize));
+ __ sw(t0, FieldMemOperand(v0, JSObject::kElementsOffset));
+
+ // v0 = address of new object (tagged)
+ // a2 = argument count (tagged)
+ // t0 = address of parameter map or backing store (tagged)
+ // t2 = mapped parameter count (tagged)
+ // Initialize parameter map. If there are no mapped arguments, we're done.
+ Label skip_parameter_map;
+ Label skip3;
+ __ Branch(&skip3, ne, t2, Operand(Smi::FromInt(0)));
+ // Move backing store address to a1, because it is
+ // expected there when filling in the unmapped arguments.
+ __ mov(a1, t0);
+ __ bind(&skip3);
+
+ __ Branch(&skip_parameter_map, eq, t2, Operand(Smi::FromInt(0)));
+
+ __ LoadRoot(t1, Heap::kSloppyArgumentsElementsMapRootIndex);
+ __ sw(t1, FieldMemOperand(t0, FixedArray::kMapOffset));
+ __ Addu(t1, t2, Operand(Smi::FromInt(2)));
+ __ sw(t1, FieldMemOperand(t0, FixedArray::kLengthOffset));
+ __ sw(cp, FieldMemOperand(t0, FixedArray::kHeaderSize + 0 * kPointerSize));
+ __ Lsa(t1, t0, t2, 1);
+ __ Addu(t1, t1, Operand(kParameterMapHeaderSize));
+ __ sw(t1, FieldMemOperand(t0, FixedArray::kHeaderSize + 1 * kPointerSize));
+
+ // Copy the parameter slots and the holes in the arguments.
+ // We need to fill in mapped_parameter_count slots. They index the context,
+ // where parameters are stored in reverse order, at
+ // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1
+ // The mapped parameter thus need to get indices
+ // MIN_CONTEXT_SLOTS+parameter_count-1 ..
+ // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count
+ // We loop from right to left.
+ Label parameters_loop, parameters_test;
+ __ mov(t1, t2);
+ __ Addu(t5, a2, Operand(Smi::FromInt(Context::MIN_CONTEXT_SLOTS)));
+ __ Subu(t5, t5, Operand(t2));
+ __ LoadRoot(t3, Heap::kTheHoleValueRootIndex);
+ __ Lsa(a1, t0, t1, 1);
+ __ Addu(a1, a1, Operand(kParameterMapHeaderSize));
+
+ // a1 = address of backing store (tagged)
+ // t0 = address of parameter map (tagged)
+ // a0 = temporary scratch (a.o., for address calculation)
+ // t1 = loop variable (tagged)
+ // t3 = the hole value
+ __ jmp(&parameters_test);
+
+ __ bind(&parameters_loop);
+ __ Subu(t1, t1, Operand(Smi::FromInt(1)));
+ __ sll(a0, t1, 1);
+ __ Addu(a0, a0, Operand(kParameterMapHeaderSize - kHeapObjectTag));
+ __ Addu(t6, t0, a0);
+ __ sw(t5, MemOperand(t6));
+ __ Subu(a0, a0, Operand(kParameterMapHeaderSize - FixedArray::kHeaderSize));
+ __ Addu(t6, a1, a0);
+ __ sw(t3, MemOperand(t6));
+ __ Addu(t5, t5, Operand(Smi::FromInt(1)));
+ __ bind(&parameters_test);
+ __ Branch(&parameters_loop, ne, t1, Operand(Smi::FromInt(0)));
+
+ // t1 = argument count (tagged).
+ __ lw(t1, FieldMemOperand(v0, JSSloppyArgumentsObject::kLengthOffset));
+
+ __ bind(&skip_parameter_map);
+ // v0 = address of new object (tagged)
+ // a1 = address of backing store (tagged)
+ // t1 = argument count (tagged)
+ // t2 = mapped parameter count (tagged)
+ // t5 = scratch
+ // Copy arguments header and remaining slots (if there are any).
+ __ LoadRoot(t5, Heap::kFixedArrayMapRootIndex);
+ __ sw(t5, FieldMemOperand(a1, FixedArray::kMapOffset));
+ __ sw(t1, FieldMemOperand(a1, FixedArray::kLengthOffset));
+
+ Label arguments_loop, arguments_test;
+ __ sll(t6, t2, 1);
+ __ Subu(a3, a3, Operand(t6));
+ __ jmp(&arguments_test);
+
+ __ bind(&arguments_loop);
+ __ Subu(a3, a3, Operand(kPointerSize));
+ __ lw(t0, MemOperand(a3, 0));
+ __ Lsa(t5, a1, t2, 1);
+ __ sw(t0, FieldMemOperand(t5, FixedArray::kHeaderSize));
+ __ Addu(t2, t2, Operand(Smi::FromInt(1)));
+
+ __ bind(&arguments_test);
+ __ Branch(&arguments_loop, lt, t2, Operand(t1));
+
+ // Return.
+ __ Ret();
+
+ // Do the runtime call to allocate the arguments object.
+ // t1 = argument count (tagged)
+ __ bind(&runtime);
+ __ Push(a1, a3, t1);
+ __ TailCallRuntime(Runtime::kNewSloppyArguments);
+}
+
+
+void FastNewStrictArgumentsStub::Generate(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- a1 : function
+ // -- cp : context
+ // -- fp : frame pointer
+ // -- ra : return address
+ // -----------------------------------
+ __ AssertFunction(a1);
+
+ // For Ignition we need to skip all possible handler/stub frames until
+ // we reach the JavaScript frame for the function (similar to what the
+ // runtime fallback implementation does). So make a2 point to that
+ // JavaScript frame.
+ {
+ Label loop, loop_entry;
+ __ Branch(USE_DELAY_SLOT, &loop_entry);
+ __ mov(a2, fp); // In delay slot.
+ __ bind(&loop);
+ __ lw(a2, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
+ __ bind(&loop_entry);
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
+ __ Branch(&loop, ne, a1, Operand(a3));
+ }
+
+ // Check if we have an arguments adaptor frame below the function frame.
+ Label arguments_adaptor, arguments_done;
+ __ lw(a3, MemOperand(a2, StandardFrameConstants::kCallerFPOffset));
+ __ lw(a0, MemOperand(a3, StandardFrameConstants::kContextOffset));
+ __ Branch(&arguments_adaptor, eq, a0,
+ Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+ {
+ __ lw(a1, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+ __ lw(a0,
+ FieldMemOperand(a1, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ Lsa(a2, a2, a0, kPointerSizeLog2 - 1);
+ __ Addu(a2, a2, Operand(StandardFrameConstants::kCallerSPOffset -
+ 1 * kPointerSize));
+ }
+ __ Branch(&arguments_done);
+ __ bind(&arguments_adaptor);
+ {
+ __ lw(a0, MemOperand(a3, ArgumentsAdaptorFrameConstants::kLengthOffset));
+ __ Lsa(a2, a3, a0, kPointerSizeLog2 - 1);
+ __ Addu(a2, a2, Operand(StandardFrameConstants::kCallerSPOffset -
+ 1 * kPointerSize));
+ }
+ __ bind(&arguments_done);
+
+ // ----------- S t a t e -------------
+ // -- cp : context
+ // -- a0 : number of rest parameters (tagged)
+ // -- a2 : pointer to first rest parameters
+ // -- ra : return address
+ // -----------------------------------
+
+ // Allocate space for the strict arguments object plus the backing store.
+ Label allocate, done_allocate;
+ __ li(a1, Operand(JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize));
+ __ Lsa(a1, a1, a0, kPointerSizeLog2 - 1);
+ __ Allocate(a1, v0, a3, t0, &allocate, TAG_OBJECT);
+ __ bind(&done_allocate);
+
+ // Setup the elements array in v0.
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ sw(at, FieldMemOperand(v0, FixedArray::kMapOffset));
+ __ sw(a0, FieldMemOperand(v0, FixedArray::kLengthOffset));
+ __ Addu(a3, v0, Operand(FixedArray::kHeaderSize));
+ {
+ Label loop, done_loop;
+ __ sll(at, a0, kPointerSizeLog2 - 1);
+ __ Addu(a1, a3, at);
+ __ bind(&loop);
+ __ Branch(&done_loop, eq, a1, Operand(a3));
+ __ lw(at, MemOperand(a2, 0 * kPointerSize));
+ __ sw(at, FieldMemOperand(a3, 0 * kPointerSize));
+ __ Subu(a2, a2, Operand(1 * kPointerSize));
+ __ Addu(a3, a3, Operand(1 * kPointerSize));
+ __ Branch(&loop);
+ __ bind(&done_loop);
+ }
+
+ // Setup the strict arguments object in a3.
+ __ LoadNativeContextSlot(Context::STRICT_ARGUMENTS_MAP_INDEX, at);
+ __ sw(at, FieldMemOperand(a3, JSStrictArgumentsObject::kMapOffset));
+ __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
+ __ sw(at, FieldMemOperand(a3, JSStrictArgumentsObject::kPropertiesOffset));
+ __ sw(v0, FieldMemOperand(a3, JSStrictArgumentsObject::kElementsOffset));
+ __ sw(a0, FieldMemOperand(a3, JSStrictArgumentsObject::kLengthOffset));
+ STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize);
+ __ Ret(USE_DELAY_SLOT);
+ __ mov(v0, a3); // In delay slot
+
+ // Fall back to %AllocateInNewSpace.
+ __ bind(&allocate);
+ {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ __ SmiTag(a1);
+ __ Push(a0, a2, a1);
+ __ CallRuntime(Runtime::kAllocateInNewSpace);
+ __ Pop(a0, a2);
+ }
+ __ jmp(&done_allocate);
+}
+
+
void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
Register context_reg = cp;
Register slot_reg = a2;
@@ -5157,8 +5347,7 @@ void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
}
// Load the PropertyCell value at the specified slot.
- __ sll(at, slot_reg, kPointerSizeLog2);
- __ Addu(at, at, Operand(context_reg));
+ __ Lsa(at, context_reg, slot_reg, kPointerSizeLog2);
__ lw(result_reg, ContextMemOperand(at, 0));
__ lw(result_reg, FieldMemOperand(result_reg, PropertyCell::kValueOffset));
@@ -5196,8 +5385,7 @@ void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) {
}
// Load the PropertyCell at the specified slot.
- __ sll(at, slot_reg, kPointerSizeLog2);
- __ Addu(at, at, Operand(context_reg));
+ __ Lsa(at, context_reg, slot_reg, kPointerSizeLog2);
__ lw(cell_reg, ContextMemOperand(at, 0));
// Load PropertyDetails for the cell (actually only the cell_type and kind).
@@ -5424,11 +5612,10 @@ static void CallApiFunctionAndReturn(
__ jmp(&leave_exit_frame);
}
-
static void CallApiFunctionStubHelper(MacroAssembler* masm,
const ParameterCount& argc,
bool return_first_arg,
- bool call_data_undefined) {
+ bool call_data_undefined, bool is_lazy) {
// ----------- S t a t e -------------
// -- a0 : callee
// -- t0 : call_data
@@ -5464,8 +5651,10 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm,
// Save context, callee and call data.
__ Push(context, callee, call_data);
- // Load context from callee.
- __ lw(context, FieldMemOperand(callee, JSFunction::kContextOffset));
+ if (!is_lazy) {
+ // Load context from callee.
+ __ lw(context, FieldMemOperand(callee, JSFunction::kContextOffset));
+ }
Register scratch = call_data;
if (!call_data_undefined) {
@@ -5546,7 +5735,7 @@ static void CallApiFunctionStubHelper(MacroAssembler* masm,
void CallApiFunctionStub::Generate(MacroAssembler* masm) {
bool call_data_undefined = this->call_data_undefined();
CallApiFunctionStubHelper(masm, ParameterCount(a3), false,
- call_data_undefined);
+ call_data_undefined, false);
}
@@ -5554,41 +5743,48 @@ void CallApiAccessorStub::Generate(MacroAssembler* masm) {
bool is_store = this->is_store();
int argc = this->argc();
bool call_data_undefined = this->call_data_undefined();
+ bool is_lazy = this->is_lazy();
CallApiFunctionStubHelper(masm, ParameterCount(argc), is_store,
- call_data_undefined);
+ call_data_undefined, is_lazy);
}
void CallApiGetterStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
- // -- sp[0] : name
- // -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
+ // -- sp[0] : name
+ // -- sp[4 .. (4 + kArgsLength*4)] : v8::PropertyCallbackInfo::args_
// -- ...
- // -- a2 : api_function_address
+ // -- a2 : api_function_address
// -----------------------------------
Register api_function_address = ApiGetterDescriptor::function_address();
DCHECK(api_function_address.is(a2));
- __ mov(a0, sp); // a0 = Handle<Name>
- __ Addu(a1, a0, Operand(1 * kPointerSize)); // a1 = PCA
+ // v8::PropertyCallbackInfo::args_ array and name handle.
+ const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
+
+ // Load address of v8::PropertyAccessorInfo::args_ array and name handle.
+ __ mov(a0, sp); // a0 = Handle<Name>
+ __ Addu(a1, a0, Operand(1 * kPointerSize)); // a1 = v8::PCI::args_
const int kApiStackSpace = 1;
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
- // Create PropertyAccessorInfo instance on the stack above the exit frame with
- // a1 (internal::Object** args_) as the data.
+ // Create v8::PropertyCallbackInfo object on the stack and initialize
+ // it's args_ field.
__ sw(a1, MemOperand(sp, 1 * kPointerSize));
- __ Addu(a1, sp, Operand(1 * kPointerSize)); // a1 = AccessorInfo&
-
- const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
+ __ Addu(a1, sp, Operand(1 * kPointerSize)); // a1 = v8::PropertyCallbackInfo&
ExternalReference thunk_ref =
ExternalReference::invoke_accessor_getter_callback(isolate());
+
+ // +3 is to skip prolog, return address and name handle.
+ MemOperand return_value_operand(
+ fp, (PropertyCallbackArguments::kReturnValueOffset + 3) * kPointerSize);
CallApiFunctionAndReturn(masm, api_function_address, thunk_ref,
kStackUnwindSpace, kInvalidStackOffset,
- MemOperand(fp, 6 * kPointerSize), NULL);
+ return_value_operand, NULL);
}