Index: src/macro-assembler-arm.cc |
=================================================================== |
--- src/macro-assembler-arm.cc (revision 288) |
+++ src/macro-assembler-arm.cc (working copy) |
@@ -249,94 +249,28 @@ |
} |
-void MacroAssembler::EnterJSFrame(int argc) { |
- // Generate code entering a JS function called from a JS function |
- // stack: receiver, arguments |
- // r0: number of arguments (not including function, nor receiver) |
- // r1: preserved |
- // sp: stack pointer |
- // fp: frame pointer |
- // cp: callee's context |
- // pp: caller's parameter pointer |
- // lr: return address |
+void MacroAssembler::EnterInternalFrame() { |
+ // r0-r3: preserved |
+ int type = StackFrame::INTERNAL; |
- // compute parameter pointer before making changes |
- // ip = sp + kPointerSize*(args_len+1); // +1 for receiver |
- add(ip, sp, Operand(r0, LSL, kPointerSizeLog2)); |
- add(ip, ip, Operand(kPointerSize)); |
+ stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); |
+ mov(ip, Operand(Smi::FromInt(type))); |
+ push(ip); |
+ mov(ip, Operand(0)); |
+ push(ip); // Push an empty code cache slot. |
+ add(fp, sp, Operand(3 * kPointerSize)); // Adjust FP to point to saved FP. |
+} |
- // push extra parameters if we don't have enough |
- // (this can only happen if argc > 0 to begin with) |
- if (argc > 0) { |
- Label loop, done; |
- // assume enough arguments to be the most common case |
- sub(r2, r0, Operand(argc), SetCC); // number of missing arguments |
- b(ge, &done); // enough arguments |
- |
- // not enough arguments |
- mov(r3, Operand(Factory::undefined_value())); |
- bind(&loop); |
- push(r3); |
- add(r2, r2, Operand(1), SetCC); |
- b(lt, &loop); |
- |
- bind(&done); |
- } |
- |
- mov(r3, Operand(r0)); // args_len to be saved |
- mov(r2, Operand(cp)); // context to be saved |
- |
- // push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp, |
- // sp_on_exit (ip == pp, may be patched on exit), return address |
- stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() | |
- ip.bit() | lr.bit()); |
- |
- // Setup new frame pointer. |
- add(fp, sp, Operand(-StandardFrameConstants::kContextOffset)); |
- mov(pp, Operand(ip)); // setup new parameter pointer |
- mov(r0, Operand(0)); // spare slot to store caller code object during GC |
- push(r0); |
+void MacroAssembler::ExitInternalFrame() { |
+ // r0: preserved |
// r1: preserved |
-} |
+ // r2: preserved |
- |
-void MacroAssembler::ExitJSFrame(ExitJSFlag flag) { |
- // r0: result |
- // sp: stack pointer |
- // fp: frame pointer |
- // pp: parameter pointer |
- |
- if (flag == DO_NOT_RETURN) { |
- add(r3, fp, Operand(JavaScriptFrameConstants::kSavedRegistersOffset)); |
- } |
- |
- if (flag == DO_NOT_RETURN) { |
- // restore sp as caller_sp (not as pp) |
- str(r3, MemOperand(fp, JavaScriptFrameConstants::kSPOnExitOffset)); |
- } |
- |
- if (flag == DO_NOT_RETURN && generating_stub()) { |
- // If we're generating a stub, we need to preserve the link |
- // register to be able to return to the place the stub was called |
- // from. |
- mov(ip, Operand(lr)); |
- } |
- |
- mov(sp, Operand(fp)); // respect ABI stack constraint |
- ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | |
- ((flag == RETURN) ? pc.bit() : lr.bit())); |
- |
- if (flag == DO_NOT_RETURN && generating_stub()) { |
- // Return to the place where the stub was called without |
- // clobbering the value of the link register. |
- mov(pc, Operand(ip)); |
- } |
- |
- // r0: result |
- // sp: points to function arg (if return) or to last arg (if no return) |
- // fp: restored frame pointer |
- // pp: restored parameter pointer |
+ // 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()); |
} |
@@ -346,13 +280,58 @@ |
Register code_reg, |
Label* done, |
InvokeFlag flag) { |
- if (actual.is_immediate()) { |
- mov(r0, Operand(actual.immediate())); // Push the number of arguments. |
+ bool definitely_matches = false; |
+ Label regular_invoke; |
+ |
+ // Check whether the expected and actual arguments count match. If not, |
+ // setup registers according to contract with ArgumentsAdaptorTrampoline: |
+ // r0: actual arguments count |
+ // r1: function (passed through to callee) |
+ // r2: expected arguments count |
+ // r3: callee code entry |
+ |
+ // The code below is made a lot easier because the calling code already sets |
+ // up actual and expected registers according to the contract if values are |
+ // passed in registers. |
+ ASSERT(actual.is_immediate() || actual.reg().is(r0)); |
+ ASSERT(expected.is_immediate() || expected.reg().is(r2)); |
+ ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(r3)); |
+ |
+ if (expected.is_immediate()) { |
+ ASSERT(actual.is_immediate()); |
+ if (expected.immediate() == actual.immediate()) { |
+ definitely_matches = true; |
+ } else { |
+ mov(r0, Operand(actual.immediate())); |
+ mov(r2, Operand(expected.immediate())); |
+ } |
} else { |
- if (!actual.reg().is(r0)) { |
- mov(r0, Operand(actual.reg())); |
+ if (actual.is_immediate()) { |
+ cmp(expected.reg(), Operand(actual.immediate())); |
+ b(eq, ®ular_invoke); |
+ mov(r0, Operand(actual.immediate())); |
+ } else { |
+ cmp(expected.reg(), Operand(actual.reg())); |
+ b(eq, ®ular_invoke); |
} |
} |
+ |
+ if (!definitely_matches) { |
+ if (!code_constant.is_null()) { |
+ mov(r3, Operand(code_constant)); |
+ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ } |
+ |
+ Handle<Code> adaptor = |
+ Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
+ if (flag == CALL_FUNCTION) { |
+ Call(adaptor, code_target); |
+ b(done); |
+ } else { |
+ Jump(adaptor, code_target); |
+ } |
+ bind(®ular_invoke); |
+ } |
} |
@@ -402,19 +381,9 @@ |
// Contract with called JS functions requires that function is passed in r1. |
ASSERT(fun.is(r1)); |
- Register code_reg = r3; |
Register expected_reg = r2; |
+ Register code_reg = r3; |
- // Make sure that the code and expected registers do not collide with the |
- // actual register being passed in. |
- if (actual.is_reg()) { |
- if (actual.reg().is(code_reg)) { |
- code_reg = r4; |
- } else if (actual.reg().is(expected_reg)) { |
- expected_reg = r4; |
- } |
- } |
- |
ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); |
ldr(expected_reg, |
@@ -507,7 +476,7 @@ |
mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS |
push(r0); |
} else { |
- // Must preserve r0-r3, r5-r7 are available. |
+ // Must preserve r0-r4, r5-r7 are available. |
ASSERT(try_location == IN_JS_ENTRY); |
// The parameter pointer is meaningless here and fp does not point to a JS |
// frame. So we save NULL for both pp and fp. We expect the code throwing an |
@@ -688,39 +657,60 @@ |
} |
-void MacroAssembler::InvokeBuiltin(const char* name, |
- int argc, |
- InvokeJSFlags flags) { |
- Handle<String> symbol = Factory::LookupAsciiSymbol(name); |
- Object* object = Top::security_context_builtins()->GetProperty(*symbol); |
- bool unresolved = true; |
- Code* code = Builtins::builtin(Builtins::Illegal); |
+Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id, |
+ bool* resolved) { |
+ // Contract with compiled functions is that the function is passed in r1. |
+ int builtins_offset = |
+ JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); |
+ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
+ ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); |
+ ldr(r1, FieldMemOperand(r1, builtins_offset)); |
- if (object->IsJSFunction()) { |
- Handle<JSFunction> function(JSFunction::cast(object)); |
- if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) { |
- code = function->code(); |
- unresolved = false; |
- } |
- } |
+ return Builtins::GetCode(id, resolved); |
+} |
+ |
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
+ InvokeJSFlags flags) { |
+ bool resolved; |
+ Handle<Code> code = ResolveBuiltin(id, &resolved); |
+ |
if (flags == CALL_JS) { |
- Call(Handle<Code>(code), code_target); |
+ Call(code, code_target); |
} else { |
ASSERT(flags == JUMP_JS); |
- Jump(Handle<Code>(code), code_target); |
+ Jump(code, code_target); |
} |
- if (unresolved) { |
+ if (!resolved) { |
+ const char* name = Builtins::GetName(id); |
+ int argc = Builtins::GetArgumentsCount(id); |
uint32_t flags = |
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | |
- Bootstrapper::FixupFlagsIsPCRelative::encode(false); |
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true); |
Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; |
unresolved_.Add(entry); |
} |
} |
+void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { |
+ bool resolved; |
+ Handle<Code> code = ResolveBuiltin(id, &resolved); |
+ |
+ mov(target, Operand(code)); |
+ if (!resolved) { |
+ const char* name = Builtins::GetName(id); |
+ int argc = Builtins::GetArgumentsCount(id); |
+ uint32_t flags = |
+ Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | |
+ Bootstrapper::FixupFlagsIsPCRelative::encode(true); |
+ Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; |
+ unresolved_.Add(entry); |
+ } |
+} |
+ |
+ |
void MacroAssembler::Assert(Condition cc, const char* msg) { |
if (FLAG_debug_code) |
Check(cc, msg); |