| 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());
|
| }
|
|
|
|
|
|
|