Index: src/codegen-arm.cc |
=================================================================== |
--- src/codegen-arm.cc (revision 288) |
+++ src/codegen-arm.cc (working copy) |
@@ -202,15 +202,17 @@ |
// index -2 corresponds to the activated closure, -1 corresponds |
// to the receiver |
ASSERT(-2 <= index && index < scope->num_parameters()); |
- int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize; |
- return MemOperand(pp, offset); |
+ int offset = (1 + scope->num_parameters() - index) * kPointerSize; |
+ return MemOperand(fp, offset); |
} |
MemOperand ParameterOperand(int index) const { |
return ParameterOperand(scope_, index); |
} |
- MemOperand FunctionOperand() const { return ParameterOperand(-2); } |
+ MemOperand FunctionOperand() const { |
+ return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset); |
+ } |
static MemOperand SlotOperand(MacroAssembler* masm, |
Scope* scope, |
@@ -305,8 +307,8 @@ |
void RecordStatementPosition(Node* node); |
// Activation frames |
- void EnterJSFrame(int argc); // preserves r1 |
- void ExitJSFrame(ExitJSFlag flag = RETURN); // preserves r0-r2 |
+ void EnterJSFrame(); |
+ void ExitJSFrame(); |
virtual void GenerateShiftDownAndTailCall(ZoneList<Expression*>* args); |
virtual void GenerateSetThisFunction(ZoneList<Expression*>* args); |
@@ -468,7 +470,7 @@ |
// cp: callee's context |
{ Comment cmnt(masm_, "[ enter JS frame"); |
- EnterJSFrame(scope->num_parameters()); |
+ EnterJSFrame(); |
} |
// tos: code slot |
#ifdef DEBUG |
@@ -526,9 +528,7 @@ |
Slot* slot = par->slot(); |
if (slot != NULL && slot->type() == Slot::CONTEXT) { |
ASSERT(!scope->is_global_scope()); // no parameters in global scope |
- int parameter_offset = |
- JavaScriptFrameConstants::kParam0Offset - i * kPointerSize; |
- __ ldr(r1, MemOperand(pp, parameter_offset)); |
+ __ ldr(r1, ParameterOperand(i)); |
// Loads r2 with context; used below in RecordWrite. |
__ str(r1, SlotOperand(slot, r2)); |
// Load the offset into r3. |
@@ -629,8 +629,13 @@ |
__ CallRuntime(Runtime::kTraceExit, 1); |
} |
+ // Tear down the frame which will restore the caller's frame pointer and the |
+ // link register. |
ExitJSFrame(); |
+ __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); |
+ __ mov(pc, lr); |
+ |
// Code generation state must be reset. |
scope_ = NULL; |
ASSERT(!has_cc()); |
@@ -978,6 +983,7 @@ |
// Skip write barrier if the written value is a smi. |
masm->tst(r0, Operand(kSmiTagMask)); |
masm->b(eq, &exit); |
+ may_skip_write = true; |
// r2 is loaded with context when calling SlotOperand above. |
int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
masm->mov(r3, Operand(offset)); |
@@ -1281,7 +1287,7 @@ |
__ push(r1); |
__ push(r0); |
__ mov(r0, Operand(1)); // set number of arguments |
- __ InvokeBuiltin("ADD", 1, JUMP_JS); |
+ __ InvokeBuiltin(Builtins::ADD, JUMP_JS); |
// done |
__ bind(&exit); |
break; |
@@ -1304,7 +1310,7 @@ |
__ push(r1); |
__ push(r0); |
__ mov(r0, Operand(1)); // set number of arguments |
- __ InvokeBuiltin("SUB", 1, JUMP_JS); |
+ __ InvokeBuiltin(Builtins::SUB, JUMP_JS); |
// done |
__ bind(&exit); |
break; |
@@ -1334,7 +1340,7 @@ |
__ push(r1); |
__ push(r0); |
__ mov(r0, Operand(1)); // set number of arguments |
- __ InvokeBuiltin("MUL", 1, JUMP_JS); |
+ __ InvokeBuiltin(Builtins::MUL, JUMP_JS); |
// done |
__ bind(&exit); |
break; |
@@ -1361,10 +1367,17 @@ |
__ push(r0); |
__ mov(r0, Operand(1)); // 1 argument (not counting receiver). |
switch (op_) { |
- case Token::BIT_OR: __ InvokeBuiltin("BIT_OR", 1, JUMP_JS); break; |
- case Token::BIT_AND: __ InvokeBuiltin("BIT_AND", 1, JUMP_JS); break; |
- case Token::BIT_XOR: __ InvokeBuiltin("BIT_XOR", 1, JUMP_JS); break; |
- default: UNREACHABLE(); |
+ case Token::BIT_OR: |
+ __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS); |
+ break; |
+ case Token::BIT_AND: |
+ __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS); |
+ break; |
+ case Token::BIT_XOR: |
+ __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS); |
+ break; |
+ default: |
+ UNREACHABLE(); |
} |
__ bind(&exit); |
break; |
@@ -1422,9 +1435,9 @@ |
__ push(r0); |
__ mov(r0, Operand(1)); // 1 argument (not counting receiver). |
switch (op_) { |
- case Token::SAR: __ InvokeBuiltin("SAR", 1, JUMP_JS); break; |
- case Token::SHR: __ InvokeBuiltin("SHR", 1, JUMP_JS); break; |
- case Token::SHL: __ InvokeBuiltin("SHL", 1, JUMP_JS); break; |
+ case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break; |
+ case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break; |
+ case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break; |
default: UNREACHABLE(); |
} |
__ bind(&exit); |
@@ -1480,7 +1493,7 @@ |
__ bind(&slow); |
__ push(r0); |
__ mov(r0, Operand(0)); // set number of arguments |
- __ InvokeBuiltin("UNARY_MINUS", 0, JUMP_JS); |
+ __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); |
__ bind(&done); |
masm->StubReturn(1); |
@@ -1516,45 +1529,15 @@ |
__ push(r0); |
__ mov(r0, Operand(0)); // set number of arguments |
switch (kind_) { |
- case ToNumber: __ InvokeBuiltin("TO_NUMBER", 0, JUMP_JS); break; |
- case Inc: __ InvokeBuiltin("INC", 0, JUMP_JS); break; |
- case Dec: __ InvokeBuiltin("DEC", 0, JUMP_JS); break; |
+ case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break; |
+ case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break; |
+ case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break; |
default: UNREACHABLE(); |
} |
masm->StubReturn(argc_); |
} |
-class JSExitStub : public CodeStub { |
- public: |
- enum Kind { Inc, Dec, ToNumber }; |
- |
- explicit JSExitStub(ExitJSFlag flag) : flag_(flag) { } |
- |
- private: |
- ExitJSFlag flag_; |
- |
- Major MajorKey() { return JSExit; } |
- int MinorKey() { return static_cast<int>(flag_); } |
- void Generate(MacroAssembler* masm); |
- |
- const char* GetName() { return "JSExitStub"; } |
- |
-#ifdef DEBUG |
- void Print() { |
- PrintF("JSExitStub flag %d)\n", static_cast<int>(flag_)); |
- } |
-#endif |
-}; |
- |
- |
-void JSExitStub::Generate(MacroAssembler* masm) { |
- __ ExitJSFrame(flag_); |
- masm->StubReturn(1); |
-} |
- |
- |
- |
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
// r0 holds exception |
ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code |
@@ -1701,7 +1684,7 @@ |
__ mov(r3, Operand(Top::context_address())); |
__ ldr(cp, MemOperand(r3)); |
__ mov(sp, Operand(fp)); // respect ABI stack constraint |
- __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | pc.bit()); |
+ __ ldm(ia, sp, fp.bit() | sp.bit() | pc.bit()); |
// check if we should retry or throw exception |
Label retry; |
@@ -1755,13 +1738,13 @@ |
// ip = sp + kPointerSize*args_len; |
__ add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); |
- // all JS callee-saved are saved and traversed by GC; push in reverse order: |
- // JS callee-saved, caller_pp, caller_fp, sp_on_exit (ip==pp), caller_pc |
- __ stm(db_w, sp, pp.bit() | fp.bit() | ip.bit() | lr.bit()); |
+ // push in reverse order: |
+ // caller_fp, sp_on_exit, caller_pc |
+ __ stm(db_w, sp, fp.bit() | ip.bit() | lr.bit()); |
__ mov(fp, Operand(sp)); // setup new frame pointer |
// Store the current context in top. |
- __ mov(ip, Operand(Top::context_address())); |
+ __ mov(ip, Operand(ExternalReference(Top::k_context_address))); |
__ str(cp, MemOperand(ip)); |
// remember top frame |
@@ -1838,33 +1821,40 @@ |
// Called from C, so do not pop argc and args on exit (preserve sp) |
// No need to save register-passed args |
// Save callee-saved registers (incl. cp, pp, and fp), sp, and lr |
- __ mov(ip, Operand(sp)); |
- __ stm(db_w, sp, kCalleeSaved | ip.bit() | lr.bit()); |
+ __ stm(db_w, sp, kCalleeSaved | lr.bit()); |
- // Setup frame pointer |
- __ mov(fp, Operand(sp)); |
- |
- // Add constructor mark. |
- __ mov(ip, Operand(is_construct ? 1 : 0)); |
- __ push(ip); |
- |
- // Move arguments into registers expected by Builtins::JSEntryTrampoline |
- // preserve r0-r3, set r4, r5-r7 may be clobbered |
- |
// Get address of argv, see stm above. |
- __ add(r4, sp, Operand((kNumCalleeSaved + 3)*kPointerSize)); |
+ // r0: code entry |
+ // r1: function |
+ // r2: receiver |
+ // r3: argc |
+ __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize)); |
__ ldr(r4, MemOperand(r4)); // argv |
- // Save copies of the top frame descriptors on the stack. |
- __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
- __ ldr(r6, MemOperand(ip)); |
- __ stm(db_w, sp, r6.bit()); |
+ // Push a frame with special values setup to mark it as an entry frame. |
+ // r0: code entry |
+ // r1: function |
+ // r2: receiver |
+ // r3: argc |
+ // r4: argv |
+ int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
+ __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used. |
+ __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL)); |
+ __ mov(r6, Operand(Smi::FromInt(marker))); |
+ __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
+ __ ldr(r5, MemOperand(r5)); |
+ __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit()); |
+ // Setup frame pointer for the frame to be pushed. |
+ __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); |
+ |
// Call a faked try-block that does the invoke. |
__ bl(&invoke); |
// Caught exception: Store result (exception) in the pending |
// exception field in the JSEnv and return a failure sentinel. |
+ // Coming in here the fp will be invalid because the PushTryHandler below |
+ // sets it to 0 to signal the existence of the JSEntry frame. |
__ mov(ip, Operand(Top::pending_exception_address())); |
__ str(r0, MemOperand(ip)); |
__ mov(r0, Operand(Handle<Failure>(Failure::Exception()))); |
@@ -1872,7 +1862,7 @@ |
// Invoke: Link this frame into the handler chain. |
__ bind(&invoke); |
- // Must preserve r0-r3, r5-r7 are available. |
+ // Must preserve r0-r4, r5-r7 are available. |
__ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
// If an exception not caught by another handler occurs, this handler returns |
// control to the code after the bl(&invoke) above, which restores all |
@@ -1920,18 +1910,18 @@ |
__ bind(&exit); // r0 holds result |
// Restore the top frame descriptors from the stack. |
- __ ldm(ia_w, sp, r3.bit()); |
+ __ pop(r3); |
__ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address))); |
__ str(r3, MemOperand(ip)); |
- // Remove constructor mark. |
- __ pop(); |
+ // Reset the stack to the callee saved registers. |
+ __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); |
- // Restore callee-saved registers, sp, and return. |
+ // Restore callee-saved registers and return. |
#ifdef DEBUG |
if (FLAG_debug_code) __ mov(lr, Operand(pc)); |
#endif |
- __ ldm(ia, sp, kCalleeSaved | sp.bit() | pc.bit()); |
+ __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); |
} |
@@ -1958,31 +1948,82 @@ |
void ArgumentsAccessStub::Generate(MacroAssembler* masm) { |
+ // ----------- S t a t e ------------- |
+ // -- r0: formal number of parameters for the calling function |
+ // -- r1: key (if value access) |
+ // -- lr: return address |
+ // ----------------------------------- |
+ |
+ // Check that the key is a smi for non-length accesses. |
+ Label slow; |
+ if (!is_length_) { |
+ __ tst(r1, Operand(kSmiTagMask)); |
+ __ b(ne, &slow); |
+ } |
+ |
+ // Check if the calling frame is an arguments adaptor frame. |
+ // r0: formal number of parameters |
+ // r1: key (if access) |
+ Label adaptor; |
+ __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
+ __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
+ __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL)); |
+ __ b(eq, &adaptor); |
+ |
+ static const int kParamDisplacement = |
+ StandardFrameConstants::kCallerSPOffset - kPointerSize; |
+ |
if (is_length_) { |
- __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); |
- __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
- __ Ret(); |
+ // Nothing to do: the formal length of parameters has been passed in r0 |
+ // by the calling function. |
} else { |
- // Check that the key is a smi. |
- Label slow; |
- __ tst(r0, Operand(kSmiTagMask)); |
- __ b(ne, &slow); |
+ // Check index against formal parameter count. Use unsigned comparison to |
+ // get the negative check for free. |
+ // r0: formal number of parameters |
+ // r1: index |
+ __ cmp(r1, r0); |
+ __ b(cs, &slow); |
- // Get the actual number of arguments passed and do bounds |
- // check. Use unsigned comparison to get negative check for free. |
- __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); |
- __ cmp(r0, Operand(r1, LSL, kSmiTagSize)); |
- __ b(hs, &slow); |
+ // Read the argument from the current frame. |
+ __ sub(r3, r0, r1); |
+ __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ ldr(r0, MemOperand(r3, kParamDisplacement)); |
+ } |
- // Load the argument directly from the stack and return. |
- __ sub(r1, pp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
- __ ldr(r0, MemOperand(r1, JavaScriptFrameConstants::kParam0Offset)); |
- __ Ret(); |
+ // Return to the calling function. |
+ __ mov(pc, lr); |
- // Slow-case: Handle non-smi or out-of-bounds access to arguments |
- // by calling the runtime system. |
+ // An arguments adaptor frame is present. Find the length or the actual |
+ // argument in the calling frame. |
+ // r0: formal number of parameters |
+ // r1: key |
+ // r2: adaptor frame pointer |
+ __ bind(&adaptor); |
+ // Read the arguments length from the adaptor frame. This is the result if |
+ // only accessing the length, otherwise it is used in accessing the value |
+ __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
+ |
+ if (!is_length_) { |
+ // Check index against actual arguments count. Use unsigned comparison to |
+ // get the negative check for free. |
+ // r0: actual number of parameter |
+ // r1: index |
+ // r2: adaptor frame point |
+ __ cmp(r1, r0); |
+ __ b(cs, &slow); |
+ |
+ // Read the argument from the adaptor frame. |
+ __ sub(r3, r0, r1); |
+ __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ ldr(r0, MemOperand(r3, kParamDisplacement)); |
+ } |
+ |
+ // Return to the calling function. |
+ __ mov(pc, lr); |
+ |
+ if (!is_length_) { |
__ bind(&slow); |
- __ push(r0); |
+ __ push(r1); |
__ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); |
} |
} |
@@ -2085,13 +2126,13 @@ |
case Token::DIV: { |
__ mov(r0, Operand(1)); |
- __ InvokeBuiltin("DIV", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::DIV, CALL_JS); |
break; |
} |
case Token::MOD: { |
__ mov(r0, Operand(1)); |
- __ InvokeBuiltin("MOD", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::MOD, CALL_JS); |
break; |
} |
@@ -2346,13 +2387,13 @@ |
__ push(r1); |
// Figure out which native to call and setup the arguments. |
- const char* native; |
+ Builtins::JavaScript native; |
int argc; |
if (cc == eq) { |
- native = strict ? "STRICT_EQUALS" : "EQUALS"; |
+ native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
argc = 1; |
} else { |
- native = "COMPARE"; |
+ native = Builtins::COMPARE; |
int ncr; // NaN compare result |
if (cc == lt || cc == le) { |
ncr = GREATER; |
@@ -2369,7 +2410,7 @@ |
// tagged as a small integer. |
__ push(r0); |
__ mov(r0, Operand(argc)); |
- __ InvokeBuiltin(native, argc, CALL_JS); |
+ __ InvokeBuiltin(native, CALL_JS); |
__ cmp(r0, Operand(0)); |
__ b(&exit); |
@@ -2426,7 +2467,7 @@ |
// Slow-case: Non-function called. |
masm->bind(&slow); |
masm->mov(r0, Operand(argc_)); // Setup the number of arguments. |
- masm->InvokeBuiltin("CALL_NON_FUNCTION", argc_, JUMP_JS); |
+ masm->InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); |
} |
@@ -2866,7 +2907,7 @@ |
__ bind(&primitive); |
__ push(r0); |
__ mov(r0, Operand(0)); |
- __ InvokeBuiltin("TO_OBJECT", 0, CALL_JS); |
+ __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
__ bind(&jsobject); |
@@ -2960,7 +3001,7 @@ |
__ push(r0); |
__ push(r3); // push entry |
__ mov(r0, Operand(1)); |
- __ InvokeBuiltin("FILTER_KEY", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); |
__ mov(r3, Operand(r0)); |
// If the property has been removed while iterating, we just skip it. |
@@ -3358,7 +3399,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ ldr(r1, MemOperand(pp, 0)); |
+ __ ldr(r1, FunctionOperand()); |
// Load the literals array of the function. |
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
@@ -3431,7 +3472,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ ldr(r1, MemOperand(pp, 0)); |
+ __ ldr(r1, FunctionOperand()); |
// Load the literals array of the function. |
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
@@ -3502,12 +3543,9 @@ |
// Call runtime to create the array literal. |
__ mov(r0, Operand(node->literals())); |
__ push(r0); |
- // TODO(1332579): The second argument to CreateArrayLiteral is |
- // supposed to be the literals array of the function of this frame. |
- // Until the new ARM calling convention is in place, that function |
- // is not always available. Therefore, on ARM we pass in the hole |
- // until the new calling convention is in place. |
- __ mov(r0, Operand(Factory::the_hole_value())); |
+ // Load the function of this frame. |
+ __ ldr(r0, FunctionOperand()); |
+ __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
__ push(r0); |
__ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
@@ -3760,6 +3798,9 @@ |
// r0: the number of arguments. |
__ mov(r0, Operand(args->length())); |
+ // Load the function into r1 as per calling convention. |
+ __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize)); |
+ |
// Call the construct call builtin that handles allocation and |
// constructor invocation. |
__ RecordPosition(position); |
@@ -3772,44 +3813,27 @@ |
void ArmCodeGenerator::GenerateSetThisFunction(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 1); |
- Load(args->at(0)); |
- __ ldr(r0, MemOperand(sp, 0)); |
- __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); |
+ __ stop("ArmCodeGenerator::GenerateSetThisFunction - unreachable"); |
} |
void ArmCodeGenerator::GenerateGetThisFunction(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 0); |
- __ ldr(r0, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateGetThisFunction - unreachable"); |
} |
void ArmCodeGenerator::GenerateSetThis(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 1); |
- Load(args->at(0)); |
- __ ldr(r0, MemOperand(sp, 0)); |
- __ str(r0, MemOperand(pp, JavaScriptFrameConstants::kReceiverOffset)); |
+ __ stop("ArmCodeGenerator::GenerateSetThis - unreachable"); |
} |
void ArmCodeGenerator::GenerateSetArgumentsLength(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 1); |
- Load(args->at(0)); |
- __ pop(r0); |
- __ mov(r0, Operand(r0, LSR, kSmiTagSize)); |
- __ str(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); |
- __ mov(r0, Operand(Smi::FromInt(0))); // return a meaningful value |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateSetArgumentsLength - unreachable"); |
} |
void ArmCodeGenerator::GenerateGetArgumentsLength(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 1); |
- __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset)); |
- __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateGetArgumentsLength - unreachable"); |
} |
@@ -3863,130 +3887,22 @@ |
void ArmCodeGenerator::GenerateTailCallWithArguments( |
ZoneList<Expression*>* args) { |
- // r0 = number of arguments (smi) |
- ASSERT(args->length() == 1); |
- Load(args->at(0)); |
- __ pop(r0); |
- __ mov(r0, Operand(r0, LSR, kSmiTagSize)); |
- |
- // r1 = new function (previously written to stack) |
- __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); |
- |
- // Reset parameter pointer and frame pointer to previous frame |
- ExitJSFrame(DO_NOT_RETURN); |
- |
- // Jump (tail-call) to the function in register r1. |
- __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
- __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
- __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset)); |
- __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ __ stop("ArmCodeGenerator::GenerateTailCallWithArguments - unreachable"); |
} |
void ArmCodeGenerator::GenerateSetArgument(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 3); |
- // r0 = args[i]; r1 = i |
- Comment cmnt(masm_, "[ GenerateSetArgument"); |
- Load(args->at(1)); // args[i] (value) |
- Load(args->at(0)); // i |
- __ pop(r1); // i |
- __ pop(r0); // value |
-#if defined(DEBUG) |
- { Label L; |
- __ tst(r1, Operand(kSmiTagMask)); |
- __ b(eq, &L); |
- __ stop("SMI expected"); |
- __ bind(&L); |
- } |
-#endif // defined(DEBUG) |
- __ add(r2, pp, Operand(JavaScriptFrameConstants::kParam0Offset)); |
- __ str(r0, |
- MemOperand(r2, r1, LSL, kPointerSizeLog2 - kSmiTagSize, NegOffset)); |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateSetArgument - unreachable"); |
} |
void ArmCodeGenerator::GenerateSquashFrame(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 2); |
- Load(args->at(0)); // old number of arguments |
- Load(args->at(1)); // new number of arguments, r1 > r0 |
- __ pop(r0); |
- __ mov(r0, Operand(r0, LSR, kSmiTagSize)); |
- __ pop(r1); |
- __ mov(r1, Operand(r1, LSR, kSmiTagSize)); |
- // r1 = number of words to move stack. |
- __ sub(r1, r1, Operand(r0)); |
- // r2 is source. |
- __ add(r2, fp, Operand(StandardFrameConstants::kCallerPCOffset)); |
- // Move down frame pointer fp. |
- __ add(fp, fp, Operand(r1, LSL, kPointerSizeLog2)); |
- // r1 is destination. |
- __ add(r1, fp, Operand(StandardFrameConstants::kCallerPCOffset)); |
- |
- Label move; |
- __ bind(&move); |
- __ ldr(r3, MemOperand(r2, -kPointerSize, PostIndex)); |
- __ str(r3, MemOperand(r1, -kPointerSize, PostIndex)); |
- __ cmp(r2, Operand(sp)); |
- __ b(ne, &move); |
- __ ldr(r3, MemOperand(r2)); |
- __ str(r3, MemOperand(r1)); |
- |
- // Move down stack pointer esp. |
- __ mov(sp, Operand(r1)); |
- // Put something GC-able in r0. |
- __ mov(r0, Operand(Smi::FromInt(0))); |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateSquashFrame - unreachable"); |
} |
void ArmCodeGenerator::GenerateExpandFrame(ZoneList<Expression*>* args) { |
- ASSERT(args->length() == 2); |
- Load(args->at(1)); |
- Load(args->at(0)); |
- __ pop(r0); // new number of arguments |
- __ pop(r1); // old number of arguments, r1 > r0 |
- __ mov(r1, Operand(r1, LSR, kSmiTagSize)); |
- |
- // r1 = number of words to move stack. |
- __ sub(r1, r1, Operand(r0, LSR, kSmiTagSize)); |
- Label end_of_expand_frame; |
- if (FLAG_check_stack) { |
- Label not_too_big; |
- __ sub(r2, sp, Operand(r1, LSL, kPointerSizeLog2)); |
- __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit())); |
- __ ldr(ip, MemOperand(ip)); |
- __ cmp(r2, Operand(ip)); |
- __ b(gt, ¬_too_big); |
- __ mov(r0, Operand(Factory::false_value())); |
- __ b(&end_of_expand_frame); |
- __ bind(¬_too_big); |
- } |
- // r3 is source. |
- __ mov(r3, Operand(sp)); |
- // r0 is copy limit + 1 word |
- __ add(r0, fp, |
- Operand(StandardFrameConstants::kCallerPCOffset + kPointerSize)); |
- // Move up frame pointer fp. |
- __ sub(fp, fp, Operand(r1, LSL, kPointerSizeLog2)); |
- // Move up stack pointer sp. |
- __ sub(sp, sp, Operand(r1, LSL, kPointerSizeLog2)); |
- // r1 is destination (r1 = source - r1). |
- __ mov(r2, Operand(0)); |
- __ sub(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); |
- __ add(r1, r3, Operand(r2)); |
- |
- Label move; |
- __ bind(&move); |
- __ ldr(r2, MemOperand(r3, kPointerSize, PostIndex)); |
- __ str(r2, MemOperand(r1, kPointerSize, PostIndex)); |
- __ cmp(r3, Operand(r0)); |
- __ b(ne, &move); |
- |
- // Put success value in top of stack |
- __ mov(r0, Operand(Factory::true_value())); |
- __ bind(&end_of_expand_frame); |
- __ push(r0); |
+ __ stop("ArmCodeGenerator::GenerateExpandFrame - unreachable"); |
} |
@@ -4008,7 +3924,6 @@ |
} |
- |
// This should generate code that performs a charCodeAt() call or returns |
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
// It is not yet implemented on ARM, so it always goes to the slow case. |
@@ -4019,11 +3934,23 @@ |
} |
- |
-// This is used in the implementation of apply on ia32 but it is not |
-// used on ARM yet. |
void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
- __ stop("ArmCodeGenerator::GenerateIsArray"); |
+ ASSERT(args->length() == 1); |
+ Load(args->at(0)); |
+ Label answer; |
+ // We need the CC bits to come out as not_equal in the case where the |
+ // object is a smi. This can't be done with the usual test opcode so |
+ // we use XOR to get the right CC bits. |
+ __ pop(r0); |
+ __ and_(r1, r0, Operand(kSmiTagMask)); |
+ __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
+ __ b(ne, &answer); |
+ // It is a heap object - get the map. |
+ __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
+ __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
+ // Check if the object is a JS array or not. |
+ __ cmp(r1, Operand(JS_ARRAY_TYPE)); |
+ __ bind(&answer); |
cc_reg_ = eq; |
} |
@@ -4045,11 +3972,11 @@ |
void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
- // Load the key onto the stack and set register r1 to the formal |
- // parameters count for the currently executing function. |
+ // Satisfy contract with ArgumentsAccessStub: |
+ // Load the key into r1 and the formal parameters count into r0. |
Load(args->at(0)); |
- __ pop(r0); |
- __ mov(r1, Operand(Smi::FromInt(scope_->num_parameters()))); |
+ __ pop(r1); |
+ __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
// Call the shared stub to get to arguments[key]. |
ArgumentsAccessStub stub(false); |
@@ -4073,46 +4000,12 @@ |
void ArmCodeGenerator::GenerateShiftDownAndTailCall( |
ZoneList<Expression*>* args) { |
- // r0 = number of arguments |
- ASSERT(args->length() == 1); |
- Load(args->at(0)); |
- __ pop(r0); |
- __ mov(r0, Operand(r0, LSR, kSmiTagSize)); |
- |
- // Get the 'this' function and exit the frame without returning. |
- __ ldr(r1, MemOperand(pp, JavaScriptFrameConstants::kFunctionOffset)); |
- ExitJSFrame(DO_NOT_RETURN); |
- // return address in lr |
- |
- // Move arguments one element down the stack. |
- Label move; |
- Label moved; |
- __ sub(r2, r0, Operand(0), SetCC); |
- __ b(eq, &moved); |
- __ bind(&move); |
- __ sub(ip, r2, Operand(1)); |
- __ ldr(r3, MemOperand(sp, ip, LSL, kPointerSizeLog2)); |
- __ str(r3, MemOperand(sp, r2, LSL, kPointerSizeLog2)); |
- __ sub(r2, r2, Operand(1), SetCC); |
- __ b(ne, &move); |
- __ bind(&moved); |
- |
- // Remove the TOS (copy of last argument) |
- __ pop(); |
- |
- // Jump (tail-call) to the function in register r1. |
- __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
- __ ldr(r1, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
- __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCodeOffset)); |
- __ add(pc, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); |
- |
- return; |
+ __ stop("ArmCodeGenerator::GenerateShiftDownAndTailCall - unreachable"); |
} |
void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) { |
- if (CheckForInlineRuntimeCall(node)) |
- return; |
+ if (CheckForInlineRuntimeCall(node)) return; |
ZoneList<Expression*>* args = node->arguments(); |
Comment cmnt(masm_, "[ CallRuntime"); |
@@ -4167,7 +4060,7 @@ |
Load(property->obj()); |
Load(property->key()); |
__ mov(r0, Operand(1)); // not counting receiver |
- __ InvokeBuiltin("DELETE", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
} else if (variable != NULL) { |
Slot* slot = variable->slot(); |
@@ -4176,7 +4069,7 @@ |
__ mov(r0, Operand(variable->name())); |
__ push(r0); |
__ mov(r0, Operand(1)); // not counting receiver |
- __ InvokeBuiltin("DELETE", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
} else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
// lookup the context holding the named variable |
@@ -4189,7 +4082,7 @@ |
__ mov(r0, Operand(variable->name())); |
__ push(r0); |
__ mov(r0, Operand(1)); // not counting receiver |
- __ InvokeBuiltin("DELETE", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
} else { |
// Default: Result of deleting non-global, not dynamically |
@@ -4237,7 +4130,7 @@ |
__ push(r0); |
__ mov(r0, Operand(0)); // not counting receiver |
- __ InvokeBuiltin("BIT_NOT", 0, CALL_JS); |
+ __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); |
__ b(&continue_label); |
__ bind(&smi_label); |
@@ -4260,7 +4153,7 @@ |
__ b(eq, &continue_label); |
__ push(r0); |
__ mov(r0, Operand(0)); // not counting receiver |
- __ InvokeBuiltin("TO_NUMBER", 0, CALL_JS); |
+ __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
__ bind(&continue_label); |
break; |
} |
@@ -4658,13 +4551,13 @@ |
case Token::IN: |
__ mov(r0, Operand(1)); // not counting receiver |
- __ InvokeBuiltin("IN", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::IN, CALL_JS); |
__ push(r0); |
break; |
case Token::INSTANCEOF: |
__ mov(r0, Operand(1)); // not counting receiver |
- __ InvokeBuiltin("INSTANCE_OF", 1, CALL_JS); |
+ __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_JS); |
__ push(r0); |
break; |
@@ -4683,14 +4576,31 @@ |
} |
-void ArmCodeGenerator::EnterJSFrame(int argc) { |
- __ EnterJSFrame(argc); |
+void ArmCodeGenerator::EnterJSFrame() { |
+#if defined(DEBUG) |
+ { Label done, fail; |
+ __ tst(r1, Operand(kSmiTagMask)); |
+ __ b(eq, &fail); |
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
+ __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
+ __ b(eq, &done); |
+ __ bind(&fail); |
+ __ stop("ArmCodeGenerator::EnterJSFrame - r1 not a function"); |
+ __ bind(&done); |
+ } |
+#endif // DEBUG |
+ |
+ __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
+ __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. |
} |
-void ArmCodeGenerator::ExitJSFrame(ExitJSFlag flag) { |
- JSExitStub stub(flag); |
- __ CallJSExitStub(&stub); |
+void ArmCodeGenerator::ExitJSFrame() { |
+ // Drop the execution stack down to the frame pointer and restore the caller |
+ // frame pointer and return address. |
+ __ mov(sp, fp); |
+ __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
} |