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 { ...@@ -459,6 +459,10 @@ class Assembler : public Malloced {
void sub(Register dst, Register src1, const Operand& src2, void sub(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al); 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, void rsb(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al); SBit s = LeaveCC, Condition cond = al);
...@@ -476,18 +480,31 @@ class Assembler : public Malloced { ...@@ -476,18 +480,31 @@ class Assembler : public Malloced {
SBit s = LeaveCC, Condition cond = al); SBit s = LeaveCC, Condition cond = al);
void tst(Register src1, const Operand& src2, 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 teq(Register src1, const Operand& src2, Condition cond = al);
void cmp(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 cmn(Register src1, const Operand& src2, Condition cond = al);
void orr(Register dst, Register src1, const Operand& src2, void orr(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al); 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, void mov(Register dst, const Operand& src,
SBit s = LeaveCC, Condition cond = al); 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, void bic(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al); SBit s = LeaveCC, Condition cond = al);
......
...@@ -961,7 +961,6 @@ bool Genesis::InstallNatives() { ...@@ -961,7 +961,6 @@ bool Genesis::InstallNatives() {
InstallNativeFunctions(); InstallNativeFunctions();
#ifndef USE_OLD_CALLING_CONVENTIONS
// TODO(1240778): Get rid of the JS implementation of // TODO(1240778): Get rid of the JS implementation of
// Function.prototype.call and simply create a function with the // Function.prototype.call and simply create a function with the
// faked formal parameter count (-1) and use the illegal builtin as // faked formal parameter count (-1) and use the illegal builtin as
...@@ -990,7 +989,6 @@ bool Genesis::InstallNatives() { ...@@ -990,7 +989,6 @@ bool Genesis::InstallNatives() {
Handle<JSFunction>::cast(GetProperty(proto, Factory::apply_symbol())); Handle<JSFunction>::cast(GetProperty(proto, Factory::apply_symbol()));
apply->shared()->set_code(Builtins::builtin(Builtins::FunctionApply)); apply->shared()->set_code(Builtins::builtin(Builtins::FunctionApply));
} }
#endif
// Make sure that the builtins object has fast properties. // Make sure that the builtins object has fast properties.
// If the ASSERT below fails, please increase the expected number of // 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"); ...@@ -54,8 +54,13 @@ DEFINE_bool(inline_new, true, "use fast inline allocation");
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax: number of arguments
// -- edi: constructor function
// -----------------------------------
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Store a smi-tagged arguments count on the stack. // Store a smi-tagged arguments count on the stack.
__ shl(eax, kSmiTagSize); __ shl(eax, kSmiTagSize);
...@@ -296,7 +301,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { ...@@ -296,7 +301,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Restore the arguments count and exit the internal frame. // Restore the arguments count and exit the internal frame.
__ bind(&exit); __ bind(&exit);
__ mov(ebx, Operand(esp, kPointerSize)); // get arguments count __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
// Remove caller arguments from the stack and return. // Remove caller arguments from the stack and return.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
...@@ -318,7 +323,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -318,7 +323,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ xor_(esi, Operand(esi)); // clear esi __ xor_(esi, Operand(esi)); // clear esi
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Load the previous frame pointer (ebx) to access C arguments // Load the previous frame pointer (ebx) to access C arguments
__ mov(ebx, Operand(ebp, 0)); __ mov(ebx, Operand(ebp, 0));
...@@ -362,7 +367,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -362,7 +367,7 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// Exit the JS frame. Notice that this also removes the empty // Exit the JS frame. Notice that this also removes the empty
// context and the function left on the stack by the code // context and the function left on the stack by the code
// invocation. // invocation.
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
__ ret(1 * kPointerSize); // remove receiver __ ret(1 * kPointerSize); // remove receiver
} }
...@@ -378,7 +383,7 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { ...@@ -378,7 +383,7 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
void Builtins::Generate_FunctionApply(MacroAssembler* masm) { void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
__ push(Operand(ebp, 4 * kPointerSize)); // push this __ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(Operand(ebp, 2 * kPointerSize)); // push arguments __ push(Operand(ebp, 2 * kPointerSize)); // push arguments
...@@ -482,7 +487,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) { ...@@ -482,7 +487,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ mov(edi, Operand(ebp, 4 * kPointerSize)); __ mov(edi, Operand(ebp, 4 * kPointerSize));
__ InvokeFunction(edi, actual, CALL_FUNCTION); __ InvokeFunction(edi, actual, CALL_FUNCTION);
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments __ ret(3 * kPointerSize); // remove this, receiver, and arguments
} }
...@@ -586,8 +591,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -586,8 +591,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
} }
// Mark the adaptor frame as special by overwriting the context slot // Call the entry point.
// in the stack with a sentinel.
Label return_site; Label return_site;
__ bind(&invoke); __ bind(&invoke);
__ call(Operand(edx)); __ call(Operand(edx));
...@@ -661,7 +665,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -661,7 +665,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ j(less_equal, &done); __ j(less_equal, &done);
__ bind(&call_to_object); __ 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). // Store the arguments count on the stack (smi tagged).
ASSERT(kSmiTag == 0); ASSERT(kSmiTag == 0);
...@@ -678,7 +682,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { ...@@ -678,7 +682,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ pop(eax); __ pop(eax);
__ shr(eax, kSmiTagSize); __ shr(eax, kSmiTagSize);
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
__ jmp(&patch_receiver); __ jmp(&patch_receiver);
// Use the global object from the called function as the receiver. // Use the global object from the called function as the receiver.
...@@ -747,7 +751,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -747,7 +751,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ SaveRegistersToMemory(kJSCallerSaved); __ SaveRegistersToMemory(kJSCallerSaved);
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to // Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC. // make sure that these are correctly updated during GC.
...@@ -767,7 +771,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm, ...@@ -767,7 +771,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ PopRegistersToMemory(pointer_regs); __ PopRegistersToMemory(pointer_regs);
// Get rid of the internal frame. // 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 // 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. // be an unwanted return address left on the stack. Here we get rid of that.
......
...@@ -155,6 +155,28 @@ bool Builtins::IsArgumentsAdaptorCall(Address pc) { ...@@ -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) { BUILTIN_0(Illegal) {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -354,13 +376,8 @@ BUILTIN_0(HandleApiCall) { ...@@ -354,13 +376,8 @@ BUILTIN_0(HandleApiCall) {
// TODO(1238487): This is not nice. We need to get rid of this // TODO(1238487): This is not nice. We need to get rid of this
// kludgy behavior and start handling API calls in a more direct // kludgy behavior and start handling API calls in a more direct
// way - maybe compile specialized stubs lazily?. // 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> function =
Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function)); Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
#endif
if (is_construct) { if (is_construct) {
Handle<FunctionTemplateInfo> desc = Handle<FunctionTemplateInfo> desc =
......
...@@ -185,6 +185,7 @@ class Builtins : public AllStatic { ...@@ -185,6 +185,7 @@ class Builtins : public AllStatic {
static const char* GetName(JavaScript id) { return javascript_names_[id]; } static const char* GetName(JavaScript id) { return javascript_names_[id]; }
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; } static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
static Handle<Code> GetCode(JavaScript id, bool* resolved);
static int NumberOfJavaScriptBuiltins() { return id_count; } static int NumberOfJavaScriptBuiltins() { return id_count; }
// Called from stub-cache.cc. // Called from stub-cache.cc.
......
This diff is collapsed.
...@@ -56,7 +56,6 @@ class Decoder { ...@@ -56,7 +56,6 @@ class Decoder {
: converter_(converter), : converter_(converter),
out_buffer_(out_buffer), out_buffer_(out_buffer),
out_buffer_pos_(0) { out_buffer_pos_(0) {
ASSERT(out_buffer_size_ > 0);
out_buffer_[out_buffer_pos_] = '\0'; out_buffer_[out_buffer_pos_] = '\0';
} }
...@@ -96,7 +95,6 @@ class Decoder { ...@@ -96,7 +95,6 @@ class Decoder {
// Append the ch to the output buffer. // Append the ch to the output buffer.
void Decoder::PrintChar(const char ch) { void Decoder::PrintChar(const char ch) {
ASSERT(out_buffer_pos_ < out_buffer_size_);
out_buffer_[out_buffer_pos_++] = ch; out_buffer_[out_buffer_pos_++] = ch;
} }
...@@ -430,7 +428,6 @@ void Decoder::Format(Instr* instr, const char* format) { ...@@ -430,7 +428,6 @@ void Decoder::Format(Instr* instr, const char* format) {
} }
cur = *format++; cur = *format++;
} }
ASSERT(out_buffer_pos_ < out_buffer_size_);
out_buffer_[out_buffer_pos_] = '\0'; out_buffer_[out_buffer_pos_] = '\0';
} }
......
...@@ -36,22 +36,16 @@ namespace v8 { namespace internal { ...@@ -36,22 +36,16 @@ namespace v8 { namespace internal {
StackFrame::Type StackFrame::ComputeType(State* state) { StackFrame::Type StackFrame::ComputeType(State* state) {
ASSERT(state->fp != NULL); ASSERT(state->fp != NULL);
if (state->pp == NULL) { if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
if (Memory::Address_at(state->fp +
EntryFrameConstants::kConstructMarkOffset) != 0) {
return ENTRY_CONSTRUCT;
} else {
return ENTRY;
}
} else if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
return ARGUMENTS_ADAPTOR; 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) { ...@@ -69,7 +63,6 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
// Fill in the state. // Fill in the state.
state->sp = sp; state->sp = sp;
state->fp = fp; state->fp = fp;
state->pp = fp + ExitFrameConstants::kPPDisplacement;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize); state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
return type; return type;
} }
...@@ -81,43 +74,49 @@ void ExitFrame::Iterate(ObjectVisitor* v) const { ...@@ -81,43 +74,49 @@ void ExitFrame::Iterate(ObjectVisitor* v) const {
int JavaScriptFrame::GetProvidedParametersCount() const { int JavaScriptFrame::GetProvidedParametersCount() const {
const int offset = JavaScriptFrameConstants::kArgsLengthOffset; return ComputeParametersCount();
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;
} }
Address JavaScriptFrame::GetCallerStackPointer() const { 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 { Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
// Argument adaptor frames aren't used on ARM (yet). const int arguments = Smi::cast(GetExpression(0))->value();
UNIMPLEMENTED(); const int offset = StandardFrameConstants::kCallerSPOffset;
return 0; return fp() + offset + (arguments + 1) * kPointerSize;
} }
Address InternalFrame::GetCallerStackPointer() const { 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 { Code* JavaScriptFrame::FindCode() const {
const int offset = StandardFrameConstants::kCodeOffset; JSFunction* function = JSFunction::cast(this->function());
Object* code = Memory::Object_at(fp() + offset); return function->shared()->code();
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);
} }
......
...@@ -93,8 +93,7 @@ class StackHandlerConstants : public AllStatic { ...@@ -93,8 +93,7 @@ class StackHandlerConstants : public AllStatic {
class EntryFrameConstants : public AllStatic { class EntryFrameConstants : public AllStatic {
public: public:
static const int kCallerFPOffset = -2 * kPointerSize; static const int kCallerFPOffset = -3 * kPointerSize;
static const int kConstructMarkOffset = -1 * kPointerSize;
}; };
...@@ -110,29 +109,23 @@ class ExitFrameConstants : public AllStatic { ...@@ -110,29 +109,23 @@ class ExitFrameConstants : public AllStatic {
// Let the parameters pointer for exit frames point just below the // Let the parameters pointer for exit frames point just below the
// frame structure on the stack. // 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. // The caller fields are below the frame pointer on the stack.
static const int kCallerPPOffset = +0 * kPointerSize; static const int kCallerFPOffset = +0 * kPointerSize;
static const int kCallerFPOffset = +1 * kPointerSize; static const int kCallerPPOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +3 * kPointerSize; static const int kCallerPCOffset = +2 * kPointerSize;
}; };
class StandardFrameConstants : public AllStatic { class StandardFrameConstants : public AllStatic {
public: public:
static const int kExpressionsOffset = -4 * kPointerSize; static const int kExpressionsOffset = -3 * kPointerSize;
static const int kCodeOffset = -3 * kPointerSize; static const int kMarkerOffset = -2 * kPointerSize;
static const int kContextOffset = -2 * kPointerSize; static const int kContextOffset = -1 * kPointerSize;
static const int kCallerPPOffset = 0 * kPointerSize; static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerFPOffset = +1 * kPointerSize; static const int kCallerPCOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +3 * kPointerSize; static const int kCallerSPOffset = +2 * 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;
}; };
...@@ -140,34 +133,32 @@ class JavaScriptFrameConstants : public AllStatic { ...@@ -140,34 +133,32 @@ class JavaScriptFrameConstants : public AllStatic {
public: public:
// FP-relative. // FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset; static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
static const int kArgsLengthOffset = -1 * kPointerSize; static const int kSavedRegistersOffset = +2 * kPointerSize;
// 0 * kPointerSize : StandardFrameConstants::kCallerPPOffset static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// 1 * kPointersize : StandardFrameConstents::kCallerFPOffset
static const int kSPOnExitOffset = +2 * kPointerSize;
// 3 * kPointerSize : StandardFrameConstants::kCallerPCOffset
static const int kSavedRegistersOffset = +4 * kPointerSize;
// PP-relative. // PP-relative.
static const int kParam0Offset = -2 * kPointerSize; static const int kParam0Offset = -2 * kPointerSize;
static const int kReceiverOffset = -1 * kPointerSize; static const int kReceiverOffset = -1 * kPointerSize;
static const int kFunctionOffset = 0 * kPointerSize;
}; };
class InternalFrameConstants : public AllStatic { class ArgumentsAdaptorFrameConstants : public AllStatic {
public: public:
static const int kCodeOffset = StandardFrameConstants::kCodeOffset; static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
}; };
inline Address StandardFrame::caller_pp() const { class InternalFrameConstants : public AllStatic {
return Memory::Address_at(fp() + StandardFrameConstants::kCallerPPOffset); public:
} static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
};
inline Object* JavaScriptFrame::function() const { inline Object* JavaScriptFrame::function() const {
const int offset = JavaScriptFrameConstants::kFunctionOffset; 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 { ...@@ -254,9 +254,6 @@ StackFrame::Type ExitFrame::GetCallerState(State* state) const {
// Setup the caller state. // Setup the caller state.
state->sp = pp(); state->sp = pp();
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset); 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 state->pc_address
= reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset); = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
return ComputeType(state); return ComputeType(state);
...@@ -293,9 +290,6 @@ int StandardFrame::ComputeExpressionsCount() const { ...@@ -293,9 +290,6 @@ int StandardFrame::ComputeExpressionsCount() const {
StackFrame::Type StandardFrame::GetCallerState(State* state) const { StackFrame::Type StandardFrame::GetCallerState(State* state) const {
state->sp = caller_sp(); state->sp = caller_sp();
state->fp = caller_fp(); state->fp = caller_fp();
#ifdef USE_OLD_CALLING_CONVENTIONS
state->pp = caller_pp();
#endif
state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp())); state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
return ComputeType(state); return ComputeType(state);
} }
......
...@@ -164,9 +164,6 @@ class StackFrame BASE_EMBEDDED { ...@@ -164,9 +164,6 @@ class StackFrame BASE_EMBEDDED {
struct State { struct State {
Address sp; Address sp;
Address fp; Address fp;
#ifdef USE_OLD_CALLING_CONVENTIONS
Address pp;
#endif
Address* pc_address; Address* pc_address;
}; };
...@@ -187,13 +184,9 @@ class StackFrame BASE_EMBEDDED { ...@@ -187,13 +184,9 @@ class StackFrame BASE_EMBEDDED {
// Compute the stack frame type for the given state. // Compute the stack frame type for the given state.
static Type ComputeType(State* 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: private:
const StackFrameIterator* iterator_; const StackFrameIterator* iterator_;
State state_;
// Get the type and the state of the calling frame. // Get the type and the state of the calling frame.
virtual Type GetCallerState(State* state) const = 0; virtual Type GetCallerState(State* state) const = 0;
...@@ -338,9 +331,6 @@ class StandardFrame: public StackFrame { ...@@ -338,9 +331,6 @@ class StandardFrame: public StackFrame {
// Accessors. // Accessors.
inline Address caller_sp() const; inline Address caller_sp() const;
inline Address caller_fp() const; inline Address caller_fp() const;
#ifdef USE_OLD_CALLING_CONVENTIONS
inline Address caller_pp() const;
#endif
inline Address caller_pc() const; inline Address caller_pc() const;
// Computes the address of the PC field in the standard frame given // Computes the address of the PC field in the standard frame given
......
...@@ -44,13 +44,6 @@ typedef unsigned __int64 uint64_t; ...@@ -44,13 +44,6 @@ typedef unsigned __int64 uint64_t;
#endif #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 { namespace v8 { namespace internal {
// Support for alternative bool type. This is only enabled if the code is // Support for alternative bool type. This is only enabled if the code is
......
...@@ -407,17 +407,15 @@ void CallIC::Generate(MacroAssembler* masm, ...@@ -407,17 +407,15 @@ void CallIC::Generate(MacroAssembler* masm,
// -- lr: return address // -- lr: return address
// ----------------------------------- // -----------------------------------
// Setup number of arguments for EnterJSFrame. // Get the receiver of the function from the stack.
__ mov(r0, Operand(argc)); __ ldr(r2, MemOperand(sp, argc * kPointerSize));
// Get the receiver of the function from the stack into r1. // Get the name of the function to call from the stack.
__ ldr(r1, MemOperand(sp, argc * kPointerSize)); __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
__ EnterJSFrame(0);
__ pop(); // remove the code slot __ EnterInternalFrame();
// Push the receiver and the name of the function. // Push the receiver and the name of the function.
__ ldr(r0, MemOperand(pp, 0)); __ stm(db_w, sp, r1.bit() | r2.bit());
__ mov(r2, Operand(0)); // code slot == 0
__ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
// Call the entry. // Call the entry.
__ mov(r0, Operand(2)); __ mov(r0, Operand(2));
...@@ -429,7 +427,7 @@ void CallIC::Generate(MacroAssembler* masm, ...@@ -429,7 +427,7 @@ void CallIC::Generate(MacroAssembler* masm,
// Move result to r1. // Move result to r1.
__ mov(r1, Operand(r0)); __ mov(r1, Operand(r0));
__ ExitJSFrame(DO_NOT_RETURN); __ ExitInternalFrame();
// Patch the function on the stack; 1 ~ receiver. // Patch the function on the stack; 1 ~ receiver.
__ str(r1, MemOperand(sp, (argc + 1) * kPointerSize)); __ str(r1, MemOperand(sp, (argc + 1) * kPointerSize));
......
...@@ -518,7 +518,7 @@ void CallIC::Generate(MacroAssembler* masm, ...@@ -518,7 +518,7 @@ void CallIC::Generate(MacroAssembler* masm,
__ mov(ebx, Operand(esp, (argc + 2) * kPointerSize)); __ mov(ebx, Operand(esp, (argc + 2) * kPointerSize));
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Push the receiver and the name of the function. // Push the receiver and the name of the function.
__ push(Operand(edx)); __ push(Operand(edx));
...@@ -532,7 +532,7 @@ void CallIC::Generate(MacroAssembler* masm, ...@@ -532,7 +532,7 @@ void CallIC::Generate(MacroAssembler* masm,
// Move result to edi and exit the internal frame. // Move result to edi and exit the internal frame.
__ mov(Operand(edi), eax); __ mov(Operand(edi), eax);
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
// Invoke the function. // Invoke the function.
ParameterCount actual(argc); ParameterCount actual(argc);
......
...@@ -249,94 +249,28 @@ void MacroAssembler::RecordWrite(Register object, Register offset, ...@@ -249,94 +249,28 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
} }
void MacroAssembler::EnterJSFrame(int argc) { void MacroAssembler::EnterInternalFrame() {
// Generate code entering a JS function called from a JS function // r0-r3: preserved
// stack: receiver, arguments int type = StackFrame::INTERNAL;
// 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
// push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp, stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
// sp_on_exit (ip == pp, may be patched on exit), return address mov(ip, Operand(Smi::FromInt(type)));
stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() | push(ip);
ip.bit() | lr.bit()); mov(ip, Operand(0));
push(ip); // Push an empty code cache slot.
// Setup new frame pointer. add(fp, sp, Operand(3 * kPointerSize)); // Adjust FP to point to saved FP.
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
} }
void MacroAssembler::ExitJSFrame(ExitJSFlag flag) { void MacroAssembler::ExitInternalFrame() {
// r0: result // r0: preserved
// sp: stack pointer // r1: preserved
// fp: frame pointer // r2: preserved
// 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 // Drop the execution stack down to the frame pointer and restore the caller
// sp: points to function arg (if return) or to last arg (if no return) // frame pointer and return address.
// fp: restored frame pointer mov(sp, fp);
// pp: restored parameter pointer ldm(ia_w, sp, fp.bit() | lr.bit());
} }
...@@ -346,13 +280,58 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -346,13 +280,58 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Register code_reg, Register code_reg,
Label* done, Label* done,
InvokeFlag flag) { InvokeFlag flag) {
if (actual.is_immediate()) { bool definitely_matches = false;
mov(r0, Operand(actual.immediate())); // Push the number of arguments. 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 { } else {
if (!actual.reg().is(r0)) { if (actual.is_immediate()) {
mov(r0, Operand(actual.reg())); 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, ...@@ -402,18 +381,8 @@ void MacroAssembler::InvokeFunction(Register fun,
// Contract with called JS functions requires that function is passed in r1. // Contract with called JS functions requires that function is passed in r1.
ASSERT(fun.is(r1)); ASSERT(fun.is(r1));
Register code_reg = r3;
Register expected_reg = r2; 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(code_reg, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
...@@ -507,7 +476,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location, ...@@ -507,7 +476,7 @@ void MacroAssembler::PushTryHandler(CodeLocation try_location,
mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS mov(r0, Operand(Smi::FromInt(StackHandler::kCodeNotPresent))); // new TOS
push(r0); push(r0);
} else { } else {
// Must preserve r0-r3, r5-r7 are available. // Must preserve r0-r4, r5-r7 are available.
ASSERT(try_location == IN_JS_ENTRY); ASSERT(try_location == IN_JS_ENTRY);
// The parameter pointer is meaningless here and fp does not point to a JS // 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 // 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) { ...@@ -688,33 +657,54 @@ void MacroAssembler::JumpToBuiltin(const ExternalReference& builtin) {
} }
void MacroAssembler::InvokeBuiltin(const char* name, Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
int argc, 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) { InvokeJSFlags flags) {
Handle<String> symbol = Factory::LookupAsciiSymbol(name); bool resolved;
Object* object = Top::security_context_builtins()->GetProperty(*symbol); Handle<Code> code = ResolveBuiltin(id, &resolved);
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;
}
}
if (flags == CALL_JS) { if (flags == CALL_JS) {
Call(Handle<Code>(code), code_target); Call(code, code_target);
} else { } else {
ASSERT(flags == JUMP_JS); 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 = uint32_t flags =
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
Bootstrapper::FixupFlagsIsPCRelative::encode(false); Bootstrapper::FixupFlagsIsPCRelative::encode(true);
Unresolved entry = { pc_offset() - sizeof(Instr), flags, name }; Unresolved entry = { pc_offset() - sizeof(Instr), flags, name };
unresolved_.Add(entry); unresolved_.Add(entry);
} }
......
...@@ -98,21 +98,13 @@ class MacroAssembler: public Assembler { ...@@ -98,21 +98,13 @@ class MacroAssembler: public Assembler {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Activation frames // Activation frames
void EnterJSFrame(int argc); void EnterInternalFrame();
void ExitJSFrame(ExitJSFlag flag); void ExitInternalFrame();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// JavaScript invokes // 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. // Invoke the JavaScript function code by either calling or jumping.
void InvokeCode(Register code, void InvokeCode(Register code,
const ParameterCount& expected, const ParameterCount& expected,
...@@ -131,6 +123,7 @@ class MacroAssembler: public Assembler { ...@@ -131,6 +123,7 @@ class MacroAssembler: public Assembler {
const ParameterCount& actual, const ParameterCount& actual,
InvokeFlag flag); InvokeFlag flag);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Debugger Support // Debugger Support
...@@ -200,7 +193,11 @@ class MacroAssembler: public Assembler { ...@@ -200,7 +193,11 @@ class MacroAssembler: public Assembler {
// Invoke specified builtin JavaScript function. Adds an entry to // Invoke specified builtin JavaScript function. Adds an entry to
// the unresolved list if the name does not resolve. // 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 { struct Unresolved {
int pc; int pc;
...@@ -233,6 +230,18 @@ class MacroAssembler: public Assembler { ...@@ -233,6 +230,18 @@ class MacroAssembler: public Assembler {
List<Unresolved> unresolved_; List<Unresolved> unresolved_;
bool generating_stub_; bool generating_stub_;
bool allow_stub_calls_; 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() { ...@@ -319,21 +319,20 @@ void MacroAssembler::FCmp() {
} }
void MacroAssembler::EnterFrame(StackFrame::Type type) { void MacroAssembler::EnterInternalFrame() {
ASSERT(type != StackFrame::JAVA_SCRIPT); int type = StackFrame::INTERNAL;
push(ebp); push(ebp);
mov(ebp, Operand(esp)); mov(ebp, Operand(esp));
push(esi); push(esi);
push(Immediate(Smi::FromInt(type))); push(Immediate(Smi::FromInt(type)));
if (type == StackFrame::INTERNAL) { push(Immediate(0)); // Push an empty code cache slot.
push(Immediate(0));
}
} }
void MacroAssembler::ExitFrame(StackFrame::Type type) { void MacroAssembler::ExitInternalFrame() {
ASSERT(type != StackFrame::JAVA_SCRIPT);
if (FLAG_debug_code) { if (FLAG_debug_code) {
StackFrame::Type type = StackFrame::INTERNAL;
cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset), cmp(Operand(ebp, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(type))); Immediate(Smi::FromInt(type)));
Check(equal, "stack frame types must match"); Check(equal, "stack frame types must match");
...@@ -727,24 +726,8 @@ Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id, ...@@ -727,24 +726,8 @@ Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
mov(edi, FieldOperand(edx, builtins_offset)); 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 { ...@@ -88,8 +88,8 @@ class MacroAssembler: public Assembler {
// Enter or exit a stack frame of the given type. Cannot be used to // Enter or exit a stack frame of the given type. Cannot be used to
// construct or leave JavaScript frames. // construct or leave JavaScript frames.
void EnterFrame(StackFrame::Type type); void EnterInternalFrame();
void ExitFrame(StackFrame::Type type); void ExitInternalFrame();
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -120,10 +120,6 @@ class MacroAssembler: public Assembler { ...@@ -120,10 +120,6 @@ class MacroAssembler: public Assembler {
// Store the code object for the given builtin in the target register. // Store the code object for the given builtin in the target register.
void GetBuiltinEntry(Register target, Builtins::JavaScript id); 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 // Expression support
void Set(Register dst, const Immediate& x); void Set(Register dst, const Immediate& x);
void Set(const Operand& dst, const Immediate& x); void Set(const Operand& dst, const Immediate& x);
...@@ -251,6 +247,10 @@ class MacroAssembler: public Assembler { ...@@ -251,6 +247,10 @@ class MacroAssembler: public Assembler {
const Operand& code_operand, const Operand& code_operand,
Label* done, Label* done,
InvokeFlag flag); 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) { ...@@ -159,22 +159,9 @@ static Object* Runtime_CreateArrayLiteral(Arguments args) {
// literal. // literal.
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_CHECKED(FixedArray, elements, args[0]); 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]); CONVERT_CHECKED(FixedArray, literals, args[1]);
const int kArrayFunIndex = JSFunction::kLiteralArrayFunctionIndex; const int kArrayFunIndex = JSFunction::kLiteralArrayFunctionIndex;
JSFunction* constructor = JSFunction::cast(literals->get(kArrayFunIndex)); JSFunction* constructor = JSFunction::cast(literals->get(kArrayFunIndex));
#endif
// Create the JSArray. // Create the JSArray.
Object* object = Heap::AllocateJSObject(constructor); Object* object = Heap::AllocateJSObject(constructor);
......
...@@ -40,8 +40,9 @@ namespace assembler { namespace arm { ...@@ -40,8 +40,9 @@ namespace assembler { namespace arm {
using ::v8::internal::Object; using ::v8::internal::Object;
using ::v8::internal::PrintF; using ::v8::internal::PrintF;
using ::v8:: internal::ReadLine; using ::v8::internal::OS;
using ::v8:: internal::DeleteArray; using ::v8::internal::ReadLine;
using ::v8::internal::DeleteArray;
DEFINE_bool(trace_sim, false, "trace simulator execution"); DEFINE_bool(trace_sim, false, "trace simulator execution");
...@@ -1392,7 +1393,7 @@ void Simulator::InstructionDecode(Instr* instr) { ...@@ -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() { ...@@ -1400,16 +1401,30 @@ void Simulator::execute() {
// Get the PC to simulate. Cannot use the accessor here as we need the // 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. // raw PC value and not the one used as input to arithmetic instructions.
int program_counter = get_pc(); int program_counter = get_pc();
while (program_counter != end_sim_pc) {
Instr* instr = reinterpret_cast<Instr*>(program_counter); if (FLAG_stop_sim_at == 0) {
icount_++; // Fast version of the dispatch loop without checking whether the simulator
if (icount_ == FLAG_stop_sim_at) { // should be stopping at a particular executed instruction.
Debugger dbg(this); while (program_counter != end_sim_pc) {
dbg.Debug(); Instr* instr = reinterpret_cast<Instr*>(program_counter);
} else { icount_++;
InstructionDecode(instr); 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, ...@@ -154,25 +154,34 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
// ----------- S t a t e -------------
// -- r1: function
// -- lr: return address
// -----------------------------------
HandleScope scope; HandleScope scope;
// Enter the JS frame but don't add additional arguments. // Enter an internal frame.
__ EnterJSFrame(0); __ EnterInternalFrame();
// Preserve the function.
__ push(r1);
// Push the function on the stack and call the runtime function. // Push the function on the stack as the argument to the runtime function.
__ ldr(r0, MemOperand(pp, 0)); __ push(r1);
__ push(r0);
__ CallRuntime(Runtime::kLazyCompile, 1); __ CallRuntime(Runtime::kLazyCompile, 1);
// Move result to r1 and restore number of arguments. // Calculate the entry point.
__ mov(r1, Operand(r0)); __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kArgsLengthOffset));
// Restore saved function.
__ pop(r1);
__ ExitJSFrame(DO_NOT_RETURN); // Tear down temporary frame.
__ ExitInternalFrame();
// Do a tail-call of the compiled function. // Do a tail-call of the compiled function.
__ add(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); __ Jump(r2);
__ Jump(r1);
return GetCodeWithFlags(flags); return GetCodeWithFlags(flags);
} }
...@@ -202,30 +211,23 @@ Object* CallStubCompiler::CompileCallField(Object* object, ...@@ -202,30 +211,23 @@ Object* CallStubCompiler::CompileCallField(Object* object,
// Get the properties array of the holder and get the function from the field. // Get the properties array of the holder and get the function from the field.
int offset = index * kPointerSize + Array::kHeaderSize; int offset = index * kPointerSize + Array::kHeaderSize;
__ ldr(r3, FieldMemOperand(reg, JSObject::kPropertiesOffset)); __ ldr(r1, FieldMemOperand(reg, JSObject::kPropertiesOffset));
__ ldr(r3, FieldMemOperand(r3, offset)); __ ldr(r1, FieldMemOperand(r1, offset));
// Check that the function really is a function. // Check that the function really is a function.
__ tst(r3, Operand(kSmiTagMask)); __ tst(r1, Operand(kSmiTagMask));
__ b(eq, &miss); __ b(eq, &miss);
// Get the map. // Get the map.
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
__ cmp(r2, Operand(JS_FUNCTION_TYPE)); __ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(ne, &miss); __ 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. // 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). // Invoke the function.
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset)); __ InvokeFunction(r1, arguments(), JUMP_FUNCTION);
__ ldr(r2, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset));
__ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(r2);
// Handle call cache miss. // Handle call cache miss.
__ bind(&miss); __ bind(&miss);
...@@ -330,11 +332,11 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -330,11 +332,11 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
} }
// Get the function and setup the context. // Get the function and setup the context.
__ mov(r3, Operand(Handle<JSFunction>(function))); __ mov(r1, Operand(Handle<JSFunction>(function)));
__ ldr(cp, FieldMemOperand(r3, JSFunction::kContextOffset)); __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Patch the function on the stack; 1 ~ receiver. // 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). // Jump to the cached code (tail call).
Handle<Code> code(function->code()); Handle<Code> code(function->code());
......
...@@ -467,7 +467,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { ...@@ -467,7 +467,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
HandleScope scope; HandleScope scope;
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Push a copy of the function onto the stack. // Push a copy of the function onto the stack.
__ push(edi); __ push(edi);
...@@ -476,7 +476,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) { ...@@ -476,7 +476,7 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
__ CallRuntime(Runtime::kLazyCompile, 1); __ CallRuntime(Runtime::kLazyCompile, 1);
__ pop(edi); __ pop(edi);
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
// Do a tail-call of the compiled function. // Do a tail-call of the compiled function.
__ lea(ecx, FieldOperand(eax, Code::kHeaderSize)); __ lea(ecx, FieldOperand(eax, Code::kHeaderSize));
...@@ -666,7 +666,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -666,7 +666,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
__ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss); __ CheckMaps(JSObject::cast(object), edx, holder, ebx, ecx, &miss);
// Enter an internal frame. // Enter an internal frame.
__ EnterFrame(StackFrame::INTERNAL); __ EnterInternalFrame();
// Push arguments on the expression stack. // Push arguments on the expression stack.
__ push(edx); // receiver __ push(edx); // receiver
...@@ -687,7 +687,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, ...@@ -687,7 +687,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
__ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver
// Exit frame. // Exit frame.
__ ExitFrame(StackFrame::INTERNAL); __ ExitInternalFrame();
// Check that the function really is a function. // Check that the function really is a function.
__ test(edi, Immediate(kSmiTagMask)); __ 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