Commit c5ee9618 authored by iposva@chromium.org's avatar iposva@chromium.org

Adapt to new calling convention on ARM:

- Simplified frame entry and frame exit code.
- Added ArgumentsAdaptorTrampoline and check for matching argument counts in the InvokePrologue.
- Removed definition and uses of USE_OLD_CALLING_CONVENTIONS.
- Changed MacroAssembler::InvokeBuiltin to match ia32 version.
- Start introducing convenience instructions in the ARM assembler as needed. These instructions take all Register parameters to avoid extra typing of "Operand(reg)".


To keep the architectures in sync these changes have been made to the ia32 files:
- Changed MacroAssembler::EnterFrame(StackFrame::Type type) to MacroAssembler::EnterInternalFrame().


These parts are still missing:
- unimplemented: Builtins::Generate_FunctionApply - large limit
- unimplemented: Builtins::Generate_ArgumentsAdaptorTrampoline - non-function call
- The files have not been lint'd yet.


Review URL: http://codereview.chromium.org/1930

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@289 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b6ad5305
......@@ -459,6 +459,10 @@ class Assembler : public Malloced {
void sub(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void sub(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al) {
sub(dst, src1, Operand(src2), s, cond);
}
void rsb(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
......@@ -476,18 +480,31 @@ class Assembler : public Malloced {
SBit s = LeaveCC, Condition cond = al);
void tst(Register src1, const Operand& src2, Condition cond = al);
void tst(Register src1, Register src2, Condition cond = al) {
tst(src1, Operand(src2), cond);
}
void teq(Register src1, const Operand& src2, Condition cond = al);
void cmp(Register src1, const Operand& src2, Condition cond = al);
void cmp(Register src1, Register src2, Condition cond = al) {
cmp(src1, Operand(src2), cond);
}
void cmn(Register src1, const Operand& src2, Condition cond = al);
void orr(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void orr(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al) {
orr(dst, src1, Operand(src2), s, cond);
}
void mov(Register dst, const Operand& src,
SBit s = LeaveCC, Condition cond = al);
void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
mov(dst, Operand(src), s, cond);
}
void bic(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
......
......@@ -961,7 +961,6 @@ bool Genesis::InstallNatives() {
InstallNativeFunctions();
#ifndef USE_OLD_CALLING_CONVENTIONS
// TODO(1240778): Get rid of the JS implementation of
// Function.prototype.call and simply create a function with the
// faked formal parameter count (-1) and use the illegal builtin as
......@@ -990,7 +989,6 @@ bool Genesis::InstallNatives() {
Handle<JSFunction>::cast(GetProperty(proto, Factory::apply_symbol()));
apply->shared()->set_code(Builtins::builtin(Builtins::FunctionApply));
}
#endif
// Make sure that the builtins object has fast properties.
// If the ASSERT below fails, please increase the expected number of
......
This diff is collapsed.
......@@ -54,8 +54,13 @@ DEFINE_bool(inline_new, true, "use fast inline allocation");
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax: number of arguments
// -- edi: constructor function
// -----------------------------------
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Store a smi-tagged arguments count on the stack.
__ shl(eax, kSmiTagSize);
......@@ -296,7 +301,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Restore the arguments count and exit the internal frame.
__ bind(&exit);
__ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
// Remove caller arguments from the stack and return.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
......@@ -318,7 +323,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ xor_(esi, Operand(esi)); // clear esi
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Load the previous frame pointer (ebx) to access C arguments
__ mov(ebx, Operand(ebp, 0));
......@@ -362,7 +367,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Exit the JS frame. Notice that this also removes the empty
// context and the function left on the stack by the code
// invocation.
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
__ ret(1 * kPointerSize); // remove receiver
}
......@@ -378,7 +383,7 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
__ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(Operand(ebp, 2 * kPointerSize)); // push arguments
......@@ -482,7 +487,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ mov(edi, Operand(ebp, 4 * kPointerSize));
__ InvokeFunction(edi, actual, CALL_FUNCTION);
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
......@@ -586,8 +591,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
// Mark the adaptor frame as special by overwriting the context slot
// in the stack with a sentinel.
// Call the entry point.
Label return_site;
__ bind(&invoke);
__ call(Operand(edx));
......@@ -661,7 +665,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ j(less_equal, &done);
__ bind(&call_to_object);
__ EnterFrame(StackFrame::INTERNAL); // preserves eax, ebx, edi
__ EnterInternalFrame(); // preserves eax, ebx, edi
// Store the arguments count on the stack (smi tagged).
ASSERT(kSmiTag == 0);
......@@ -678,7 +682,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ pop(eax);
__ shr(eax, kSmiTagSize);
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
__ jmp(&patch_receiver);
// Use the global object from the called function as the receiver.
......@@ -747,7 +751,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ SaveRegistersToMemory(kJSCallerSaved);
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC.
......@@ -767,7 +771,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ PopRegistersToMemory(pointer_regs);
// Get rid of the internal frame.
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
// If this call did not replace a call but patched other code then there will
// be an unwanted return address left on the stack. Here we get rid of that.
......
......@@ -155,6 +155,28 @@ bool Builtins::IsArgumentsAdaptorCall(Address pc) {
}
Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
Code* code = Builtins::builtin(Builtins::Illegal);
*resolved = false;
if (Top::security_context() != NULL) {
Object* object = Top::security_context_builtins()->javascript_builtin(id);
if (object->IsJSFunction()) {
Handle<JSFunction> function(JSFunction::cast(object));
// Make sure the number of parameters match the formal parameter count.
ASSERT(function->shared()->formal_parameter_count() ==
Builtins::GetArgumentsCount(id));
if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
code = function->code();
*resolved = true;
}
}
}
return Handle<Code>(code);
}
BUILTIN_0(Illegal) {
UNREACHABLE();
}
......@@ -354,13 +376,8 @@ BUILTIN_0(HandleApiCall) {
// TODO(1238487): This is not nice. We need to get rid of this
// kludgy behavior and start handling API calls in a more direct
// way - maybe compile specialized stubs lazily?.
#ifdef USE_OLD_CALLING_CONVENTIONS
Handle<JSFunction> function =
Handle<JSFunction>(JSFunction::cast(__argv__[1]));
#else
Handle<JSFunction> function =
Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
#endif
if (is_construct) {
Handle<FunctionTemplateInfo> desc =
......
......@@ -185,6 +185,7 @@ class Builtins : public AllStatic {
static const char* GetName(JavaScript id) { return javascript_names_[id]; }
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
static Handle<Code> GetCode(JavaScript id, bool* resolved);
static int NumberOfJavaScriptBuiltins() { return id_count; }
// Called from stub-cache.cc.
......
This diff is collapsed.
......@@ -56,7 +56,6 @@ class Decoder {
: converter_(converter),
out_buffer_(out_buffer),
out_buffer_pos_(0) {
ASSERT(out_buffer_size_ > 0);
out_buffer_[out_buffer_pos_] = '\0';
}
......@@ -96,7 +95,6 @@ class Decoder {
// Append the ch to the output buffer.
void Decoder::PrintChar(const char ch) {
ASSERT(out_buffer_pos_ < out_buffer_size_);
out_buffer_[out_buffer_pos_++] = ch;
}
......@@ -430,7 +428,6 @@ void Decoder::Format(Instr* instr, const char* format) {
}
cur = *format++;
}
ASSERT(out_buffer_pos_ < out_buffer_size_);
out_buffer_[out_buffer_pos_] = '\0';
}
......
......@@ -36,22 +36,16 @@ namespace v8 { namespace internal {
StackFrame::Type StackFrame::ComputeType(State* state) {
ASSERT(state->fp != NULL);
if (state->pp == NULL) {
if (Memory::Address_at(state->fp +
EntryFrameConstants::kConstructMarkOffset) != 0) {
return ENTRY_CONSTRUCT;
} else {
return ENTRY;
}
} else if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
return ARGUMENTS_ADAPTOR;
} else if (
Memory::Object_at(state->fp +
StandardFrameConstants::kFunctionOffset)->IsSmi()) {
return INTERNAL;
} else {
return JAVA_SCRIPT;
}
// The marker and function offsets overlap. If the marker isn't a
// smi then the frame is a JavaScript frame -- and the marker is
// really the function.
const int offset = StandardFrameConstants::kMarkerOffset;
Object* marker = Memory::Object_at(state->fp + offset);
if (!marker->IsSmi()) return JAVA_SCRIPT;
return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
}
......@@ -69,7 +63,6 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
// Fill in the state.
state->sp = sp;
state->fp = fp;
state->pp = fp + ExitFrameConstants::kPPDisplacement;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
return type;
}
......@@ -81,43 +74,49 @@ void ExitFrame::Iterate(ObjectVisitor* v) const {
int JavaScriptFrame::GetProvidedParametersCount() const {
const int offset = JavaScriptFrameConstants::kArgsLengthOffset;
int result = Memory::int_at(fp() + offset);
// We never remove extra parameters provided on the stack; we only
// fill in undefined values for parameters not provided.
ASSERT(0 <= result && result <= ComputeParametersCount());
return result;
return ComputeParametersCount();
}
Address JavaScriptFrame::GetCallerStackPointer() const {
return state_.pp;
int arguments;
if (Heap::gc_state() != Heap::NOT_IN_GC) {
// The arguments for cooked frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
// this rather strange decision is that we cannot access the
// function during mark-compact GCs when the stack is cooked.
// In fact accessing heap objects (like function->shared() below)
// at all during GC is problematic.
arguments = 0;
} else {
// Compute the number of arguments by getting the number of formal
// parameters of the function. We must remember to take the
// receiver into account (+1).
JSFunction* function = JSFunction::cast(this->function());
arguments = function->shared()->formal_parameter_count() + 1;
}
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments * kPointerSize);
}
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
// Argument adaptor frames aren't used on ARM (yet).
UNIMPLEMENTED();
return 0;
const int arguments = Smi::cast(GetExpression(0))->value();
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments + 1) * kPointerSize;
}
Address InternalFrame::GetCallerStackPointer() const {
return state_.pp;
// Internal frames have no arguments. The stack pointer of the
// caller is at a fixed offset from the frame pointer.
return fp() + StandardFrameConstants::kCallerSPOffset;
}
Code* JavaScriptFrame::FindCode() const {
const int offset = StandardFrameConstants::kCodeOffset;
Object* code = Memory::Object_at(fp() + offset);
if (code == NULL) {
// The code object isn't set; find it and set it.
code = Heap::FindCodeObject(pc());
ASSERT(!code->IsFailure());
Memory::Object_at(fp() + offset) = code;
}
ASSERT(code != NULL);
return Code::cast(code);
JSFunction* function = JSFunction::cast(this->function());
return function->shared()->code();
}
......
......@@ -93,8 +93,7 @@ class StackHandlerConstants : public AllStatic {
class EntryFrameConstants : public AllStatic {
public:
static const int kCallerFPOffset = -2 * kPointerSize;
static const int kConstructMarkOffset = -1 * kPointerSize;
static const int kCallerFPOffset = -3 * kPointerSize;
};
......@@ -110,29 +109,23 @@ class ExitFrameConstants : public AllStatic {
// Let the parameters pointer for exit frames point just below the
// frame structure on the stack.
static const int kPPDisplacement = 4 * kPointerSize;
static const int kPPDisplacement = 3 * kPointerSize;
// The caller fields are below the frame pointer on the stack.
static const int kCallerPPOffset = +0 * kPointerSize;
static const int kCallerFPOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +3 * kPointerSize;
static const int kCallerFPOffset = +0 * kPointerSize;
static const int kCallerPPOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +2 * kPointerSize;
};
class StandardFrameConstants : public AllStatic {
public:
static const int kExpressionsOffset = -4 * kPointerSize;
static const int kCodeOffset = -3 * kPointerSize;
static const int kContextOffset = -2 * kPointerSize;
static const int kCallerPPOffset = 0 * kPointerSize;
static const int kCallerFPOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +3 * kPointerSize;
// TODO(1233523): This is - of course - faked. The ARM port does not
// yet pass the callee function in a register, but the
// StackFrame::ComputeType code uses the field to figure out if a
// frame is a real JavaScript frame or an internal frame.
static const int kFunctionOffset = kContextOffset;
static const int kExpressionsOffset = -3 * kPointerSize;
static const int kMarkerOffset = -2 * kPointerSize;
static const int kContextOffset = -1 * kPointerSize;
static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerPCOffset = +1 * kPointerSize;
static const int kCallerSPOffset = +2 * kPointerSize;
};
......@@ -140,34 +133,32 @@ class JavaScriptFrameConstants : public AllStatic {
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
static const int kArgsLengthOffset = -1 * kPointerSize;
// 0 * kPointerSize : StandardFrameConstants::kCallerPPOffset
// 1 * kPointersize : StandardFrameConstents::kCallerFPOffset
static const int kSPOnExitOffset = +2 * kPointerSize;
// 3 * kPointerSize : StandardFrameConstants::kCallerPCOffset
static const int kSavedRegistersOffset = +4 * kPointerSize;
static const int kSavedRegistersOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// PP-relative.
static const int kParam0Offset = -2 * kPointerSize;
static const int kReceiverOffset = -1 * kPointerSize;
static const int kFunctionOffset = 0 * kPointerSize;
};
class InternalFrameConstants : public AllStatic {
class ArgumentsAdaptorFrameConstants : public AllStatic {
public:
static const int kCodeOffset = StandardFrameConstants::kCodeOffset;
static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
};
inline Address StandardFrame::caller_pp() const {
return Memory::Address_at(fp() + StandardFrameConstants::kCallerPPOffset);
}
class InternalFrameConstants : public AllStatic {
public:
static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
};
inline Object* JavaScriptFrame::function() const {
const int offset = JavaScriptFrameConstants::kFunctionOffset;
return Memory::Object_at(pp() + offset);
Object* result = Memory::Object_at(fp() + offset);
ASSERT(result->IsJSFunction());
return result;
}
......
......@@ -254,9 +254,6 @@ StackFrame::Type ExitFrame::GetCallerState(State* state) const {
// Setup the caller state.
state->sp = pp();
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
#ifdef USE_OLD_CALLING_CONVENTIONS
state->pp = Memory::Address_at(fp() + ExitFrameConstants::kCallerPPOffset);
#endif
state->pc_address
= reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
return ComputeType(state);
......@@ -293,9 +290,6 @@ int StandardFrame::ComputeExpressionsCount() const {
StackFrame::Type StandardFrame::GetCallerState(State* state) const {
state->sp = caller_sp();
state->fp = caller_fp();
#ifdef USE_OLD_CALLING_CONVENTIONS
state->pp = caller_pp();
#endif
state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
return ComputeType(state);
}
......
......@@ -164,9 +164,6 @@ class StackFrame BASE_EMBEDDED {
struct State {
Address sp;
Address fp;
#ifdef USE_OLD_CALLING_CONVENTIONS
Address pp;
#endif
Address* pc_address;
};
......@@ -187,13 +184,9 @@ class StackFrame BASE_EMBEDDED {
// Compute the stack frame type for the given state.
static Type ComputeType(State* state);
protected:
// TODO(1233523): Once the ARM code uses the new calling
// conventions, we should be able to make state_ private again.
State state_;
private:
const StackFrameIterator* iterator_;
State state_;
// Get the type and the state of the calling frame.
virtual Type GetCallerState(State* state) const = 0;
......@@ -338,9 +331,6 @@ class StandardFrame: public StackFrame {
// Accessors.
inline Address caller_sp() const;
inline Address caller_fp() const;
#ifdef USE_OLD_CALLING_CONVENTIONS
inline Address caller_pp() const;
#endif
inline Address caller_pc() const;
// Computes the address of the PC field in the standard frame given
......
......@@ -44,13 +44,6 @@ typedef unsigned __int64 uint64_t;
#endif
// TODO(1233523): Get rid of this code that conditionally introduces a
// macro to allow us to check for platforms that use the old
// non-adapted arguments calling conventions.
#if defined(ARM) || defined(__arm__) || defined(__thumb__)
#define USE_OLD_CALLING_CONVENTIONS
#endif
namespace v8 { namespace internal {
// Support for alternative bool type. This is only enabled if the code is
......
......@@ -407,17 +407,15 @@ void CallIC::Generate(MacroAssembler* masm,
// -- lr: return address
// -----------------------------------
// Setup number of arguments for EnterJSFrame.
__ mov(r0, Operand(argc));
// Get the receiver of the function from the stack into r1.
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
__ EnterJSFrame(0);
__ pop(); // remove the code slot
// Get the receiver of the function from the stack.
__ ldr(r2, MemOperand(sp, argc * kPointerSize));
// Get the name of the function to call from the stack.
__ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
__ EnterInternalFrame();
// Push the receiver and the name of the function.
__ ldr(r0, MemOperand(pp, 0));
__ mov(r2, Operand(0)); // code slot == 0
__ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
__ stm(db_w, sp, r1.bit() | r2.bit());
// Call the entry.
__ mov(r0, Operand(2));
......@@ -429,7 +427,7 @@ void CallIC::Generate(MacroAssembler* masm,
// Move result to r1.
__ mov(r1, Operand(r0));
__ ExitJSFrame(DO_NOT_RETURN);
__ ExitInternalFrame();
// Patch the function on the stack; 1 ~ receiver.
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
......
......@@ -518,7 +518,7 @@ void CallIC::Generate(MacroAssembler* masm,
__ mov(ebx, Operand(esp, (argc + 2) * kPointerSize));
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Push the receiver and the name of the function.
__ push(Operand(edx));
......@@ -532,7 +532,7 @@ void CallIC::Generate(MacroAssembler* masm,
// Move result to edi and exit the internal frame.
__ mov(Operand(edi), eax);
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
// Invoke the function.
ParameterCount actual(argc);
......
......@@ -249,94 +249,28 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
}
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
// 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));
// 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
void MacroAssembler::EnterInternalFrame() {
// r0-r3: preserved
int type = StackFrame::INTERNAL;
// 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);
// r1: preserved
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.
}
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));
}
void MacroAssembler::ExitInternalFrame() {
// r0: preserved
// r1: preserved
// r2: preserved
// 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 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
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, &regular_invoke);
mov(r0, Operand(actual.immediate()));
} else {
cmp(expected.reg(), Operand(actual.reg()));
b(eq, &regular_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(&regular_invoke);
}
}
......@@ -402,18 +381,8 @@ void MacroAssembler::InvokeFunction(Register fun,
// Contract with called JS functions requires that function is passed in r1.
ASSERT(fun.is(r1));
Register code_reg = r3;
Register expected_reg = r2;
// 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;
}
}
Register code_reg = r3;
ldr(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
......@@ -507,7 +476,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
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,33 +657,54 @@ void MacroAssembler::JumpToBuiltin(const ExternalReference& builtin) {
}
void MacroAssembler::InvokeBuiltin(const char* name,
int argc,
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));
return Builtins::GetCode(id, resolved);
}
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
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);
if (object->IsJSFunction()) {
Handle<JSFunction> function(JSFunction::cast(object));
if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
code = function->code();
unresolved = false;
}
}
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(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(false);
Bootstrapper::FixupFlagsIsPCRelative::encode(true);
Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
unresolved_.Add(entry);
}
......
......@@ -98,21 +98,13 @@ class MacroAssembler: public Assembler {
// ---------------------------------------------------------------------------
// Activation frames
void EnterJSFrame(int argc);
void ExitJSFrame(ExitJSFlag flag);
void EnterInternalFrame();
void ExitInternalFrame();
// ---------------------------------------------------------------------------
// JavaScript invokes
// Helper functions for generating invokes.
void InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,
Register code_reg,
Label* done,
InvokeFlag flag);
// Invoke the JavaScript function code by either calling or jumping.
void InvokeCode(Register code,
const ParameterCount& expected,
......@@ -131,6 +123,7 @@ class MacroAssembler: public Assembler {
const ParameterCount& actual,
InvokeFlag flag);
// ---------------------------------------------------------------------------
// Debugger Support
......@@ -200,7 +193,11 @@ class MacroAssembler: public Assembler {
// Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve.
void InvokeBuiltin(const char* name, int argc, InvokeJSFlags flags);
void InvokeBuiltin(Builtins::JavaScript id, InvokeJSFlags flags);
// Store the code object for the given builtin in the target register and
// setup the function in r1.
void GetBuiltinEntry(Register target, Builtins::JavaScript id);
struct Unresolved {
int pc;
......@@ -233,6 +230,18 @@ class MacroAssembler: public Assembler {
List<Unresolved> unresolved_;
bool generating_stub_;
bool allow_stub_calls_;
// Helper functions for generating invokes.
void InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,
Register code_reg,
Label* done,
InvokeFlag flag);
// Get the code for the given builtin. Returns if able to resolve
// the function in the 'resolved' flag.
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
};
......
......@@ -319,21 +319,20 @@ void MacroAssembler::FCmp() {
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
ASSERT(type != StackFrame::JAVA_SCRIPT);
void MacroAssembler::EnterInternalFrame() {
int type = StackFrame::INTERNAL;
push(ebp);
mov(ebp, Operand(esp));
push(esi);
push(Immediate(Smi::FromInt(type)));
if (type == StackFrame::INTERNAL) {
push(Immediate(0));
}
push(Immediate(0)); // Push an empty code cache slot.
}
void MacroAssembler::ExitFrame(StackFrame::Type type) {
ASSERT(type != StackFrame::JAVA_SCRIPT);
void MacroAssembler::ExitInternalFrame() {
if (FLAG_debug_code) {
StackFrame::Type type = StackFrame::INTERNAL;
cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(type)));
Check(equal, "stack frame types must match");
......@@ -727,24 +726,8 @@ Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
mov(edi, FieldOperand(edx, builtins_offset));
Code* code = Builtins::builtin(Builtins::Illegal);
*resolved = false;
if (Top::security_context() != NULL) {
Object* object = Top::security_context_builtins()->javascript_builtin(id);
if (object->IsJSFunction()) {
Handle<JSFunction> function(JSFunction::cast(object));
// Make sure the number of parameters match the formal parameter count.
ASSERT(function->shared()->formal_parameter_count() ==
Builtins::GetArgumentsCount(id));
if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
code = function->code();
*resolved = true;
}
}
}
return Handle<Code>(code);
return Builtins::GetCode(id, resolved);
}
......
......@@ -88,8 +88,8 @@ class MacroAssembler: public Assembler {
// Enter or exit a stack frame of the given type. Cannot be used to
// construct or leave JavaScript frames.
void EnterFrame(StackFrame::Type type);
void ExitFrame(StackFrame::Type type);
void EnterInternalFrame();
void ExitInternalFrame();
// ---------------------------------------------------------------------------
......@@ -120,10 +120,6 @@ class MacroAssembler: public Assembler {
// Store the code object for the given builtin in the target register.
void GetBuiltinEntry(Register target, Builtins::JavaScript id);
// Get the code for the given builtin. Returns if able to resolve
// the function in the 'resolved' flag.
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
// Expression support
void Set(Register dst, const Immediate& x);
void Set(const Operand& dst, const Immediate& x);
......@@ -251,6 +247,10 @@ class MacroAssembler: public Assembler {
const Operand& code_operand,
Label* done,
InvokeFlag flag);
// Get the code for the given builtin. Returns if able to resolve
// the function in the 'resolved' flag.
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
};
......
......@@ -159,22 +159,9 @@ static Object* Runtime_CreateArrayLiteral(Arguments args) {
// literal.
ASSERT(args.length() == 2);
CONVERT_CHECKED(FixedArray, elements, args[0]);
#ifdef USE_OLD_CALLING_CONVENTIONS
ASSERT(args[1]->IsTheHole());
// TODO(1332579): Pass in the literals array from the function once
// the new calling convention is in place on ARM. Currently, we
// retrieve the array constructor from the global context. This is
// a security problem since the global object might have been
// reinitialized and the array constructor from the global context
// might be from a context that we are not allowed to access.
JSFunction* constructor =
JSFunction::cast(Top::context()->global_context()->array_function());
#else
CONVERT_CHECKED(FixedArray, literals, args[1]);
const int kArrayFunIndex = JSFunction::kLiteralArrayFunctionIndex;
JSFunction* constructor = JSFunction::cast(literals->get(kArrayFunIndex));
#endif
// Create the JSArray.
Object* object = Heap::AllocateJSObject(constructor);
......
......@@ -40,8 +40,9 @@ namespace assembler { namespace arm {
using ::v8::internal::Object;
using ::v8::internal::PrintF;
using ::v8:: internal::ReadLine;
using ::v8:: internal::DeleteArray;
using ::v8::internal::OS;
using ::v8::internal::ReadLine;
using ::v8::internal::DeleteArray;
DEFINE_bool(trace_sim, false, "trace simulator execution");
......@@ -1392,7 +1393,7 @@ void Simulator::InstructionDecode(Instr* instr) {
}
DEFINE_int(stop_sim_at, -1, "Simulator stop after x number of instructions");
DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions");
//
......@@ -1400,16 +1401,30 @@ void Simulator::execute() {
// Get the PC to simulate. Cannot use the accessor here as we need the
// raw PC value and not the one used as input to arithmetic instructions.
int program_counter = get_pc();
while (program_counter != end_sim_pc) {
Instr* instr = reinterpret_cast<Instr*>(program_counter);
icount_++;
if (icount_ == FLAG_stop_sim_at) {
Debugger dbg(this);
dbg.Debug();
} else {
if (FLAG_stop_sim_at == 0) {
// Fast version of the dispatch loop without checking whether the simulator
// should be stopping at a particular executed instruction.
while (program_counter != end_sim_pc) {
Instr* instr = reinterpret_cast<Instr*>(program_counter);
icount_++;
InstructionDecode(instr);
program_counter = get_pc();
}
} else {
// FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
// we reach the particular instuction count.
while (program_counter != end_sim_pc) {
Instr* instr = reinterpret_cast<Instr*>(program_counter);
icount_++;
if (icount_ == FLAG_stop_sim_at) {
Debugger dbg(this);
dbg.Debug();
} else {
InstructionDecode(instr);
}
program_counter = get_pc();
}
program_counter = get_pc();
}
}
......
......@@ -154,25 +154,34 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
// ----------- S t a t e -------------
// -- r1: function
// -- lr: return address
// -----------------------------------
HandleScope scope;
// Enter the JS frame but don't add additional arguments.
__ EnterJSFrame(0);
// Enter an internal frame.
__ EnterInternalFrame();
// Preserve the function.
__ push(r1);
// Push the function on the stack and call the runtime function.
__ ldr(r0, MemOperand(pp, 0));
__ push(r0);
// Push the function on the stack as the argument to the runtime function.
__ push(r1);
__ CallRuntime(Runtime::kLazyCompile, 1);
// Move result to r1 and restore number of arguments.
__ mov(r1, Operand(r0));
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
// Calculate the entry point.
__ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
// Restore saved function.
__ pop(r1);
__ ExitJSFrame(DO_NOT_RETURN);
// Tear down temporary frame.
__ ExitInternalFrame();
// Do a tail-call of the compiled function.
__ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(r1);
__ Jump(r2);
return GetCodeWithFlags(flags);
}
......@@ -202,30 +211,23 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// Get the properties array of the holder and get the function from the field.
int offset = index * kPointerSize + Array::kHeaderSize;
__ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset));
__ ldr(r3, FieldMemOperand(r3, offset));
__ ldr(r1, FieldMemOperand(reg, JSObject::kPropertiesOffset));
__ ldr(r1, FieldMemOperand(r1, offset));
// Check that the function really is a function.
__ tst(r3, Operand(kSmiTagMask));
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss);
// Get the map.
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
__ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(ne, &miss);
// TODO(1233523): remove r0 after changing Jump to InvokeCode
// Setup argument length register.
__ mov(r0, Operand(argc));
// Patch the function on the stack; 1 ~ receiver.
__ str(r3, MemOperand(sp, (argc + 1) * kPointerSize));
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
// Setup the context and jump to the call code of the function (tail call).
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
__ ldr(r2, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset));
__ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(r2);
// Invoke the function.
__ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
// Handle call cache miss.
__ bind(&miss);
......@@ -330,11 +332,11 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
}
// Get the function and setup the context.
__ mov(r3, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
__ mov(r1, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Patch the function on the stack; 1 ~ receiver.
__ str(r3, MemOperand(sp, (argc + 1) * kPointerSize));
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
// Jump to the cached code (tail call).
Handle<Code> code(function->code());
......
......@@ -467,7 +467,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
HandleScope scope;
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Push a copy of the function onto the stack.
__ push(edi);
......@@ -476,7 +476,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
__ CallRuntime(Runtime::kLazyCompile, 1);
__ pop(edi);
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
// Do a tail-call of the compiled function.
__ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
......@@ -666,7 +666,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
__ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
// Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL);
__ EnterInternalFrame();
// Push arguments on the expression stack.
__ push(edx); // receiver
......@@ -687,7 +687,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
__ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
// Exit frame.
__ ExitFrame(StackFrame::INTERNAL);
__ ExitInternalFrame();
// Check that the function really is a function.
__ test(edi, Immediate(kSmiTagMask));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment