Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Unified Diff: src/codegen-arm.cc

Issue 1930: Adapt to new calling convention on ARM. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins-ia32.cc ('k') | src/disasm-arm.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, &not_too_big);
- __ mov(r0, Operand(Factory::false_value()));
- __ b(&end_of_expand_frame);
- __ bind(&not_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());
}
« no previous file with comments | « src/builtins-ia32.cc ('k') | src/disasm-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698