Landing for Zaheer Ahmad.
Direct call api functions (arm implementation) See: http://codereview.chromium.org/6170001/ Review URL: http://codereview.chromium.org/6286078 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6639 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
17da434b29
commit
aecb05354b
3
AUTHORS
3
AUTHORS
@ -26,6 +26,7 @@ Kun Zhang <zhangk@codeaurora.org>
|
|||||||
Matt Hanselman <mjhanselman@gmail.com>
|
Matt Hanselman <mjhanselman@gmail.com>
|
||||||
Martyn Capewell <martyn.capewell@arm.com>
|
Martyn Capewell <martyn.capewell@arm.com>
|
||||||
Michael Smith <mike@w3.org>
|
Michael Smith <mike@w3.org>
|
||||||
|
Mike Gilbert <floppymaster@gmail.com>
|
||||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||||
Patrick Gansterer <paroga@paroga.com>
|
Patrick Gansterer <paroga@paroga.com>
|
||||||
Rafal Krypa <rafal@krypa.net>
|
Rafal Krypa <rafal@krypa.net>
|
||||||
@ -35,4 +36,4 @@ Ryan Dahl <coldredlemur@gmail.com>
|
|||||||
Sanjoy Das <sanjoy@playingwithpointers.com>
|
Sanjoy Das <sanjoy@playingwithpointers.com>
|
||||||
Subrato K De <subratokde@codeaurora.org>
|
Subrato K De <subratokde@codeaurora.org>
|
||||||
Vlad Burlik <vladbph@gmail.com>
|
Vlad Burlik <vladbph@gmail.com>
|
||||||
Mike Gilbert <floppymaster@gmail.com>
|
Zaheer Ahmad <zahmad@codeaurora.org>
|
||||||
|
@ -3501,9 +3501,17 @@ void CEntryStub::Generate(MacroAssembler* masm) {
|
|||||||
// this by performing a garbage collection and retrying the
|
// this by performing a garbage collection and retrying the
|
||||||
// builtin once.
|
// builtin once.
|
||||||
|
|
||||||
|
// Compute the argv pointer in a callee-saved register.
|
||||||
|
__ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||||
|
__ sub(r6, r6, Operand(kPointerSize));
|
||||||
|
|
||||||
// Enter the exit frame that transitions from JavaScript to C++.
|
// Enter the exit frame that transitions from JavaScript to C++.
|
||||||
__ EnterExitFrame(save_doubles_);
|
__ EnterExitFrame(save_doubles_);
|
||||||
|
|
||||||
|
// Setup argc and the builtin function in callee-saved registers.
|
||||||
|
__ mov(r4, Operand(r0));
|
||||||
|
__ mov(r5, Operand(r1));
|
||||||
|
|
||||||
// r4: number of arguments (C callee-saved)
|
// r4: number of arguments (C callee-saved)
|
||||||
// r5: pointer to builtin function (C callee-saved)
|
// r5: pointer to builtin function (C callee-saved)
|
||||||
// r6: pointer to first argument (C callee-saved)
|
// r6: pointer to first argument (C callee-saved)
|
||||||
@ -5906,6 +5914,23 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DirectCEntryStub::Generate(MacroAssembler* masm) {
|
||||||
|
__ ldr(pc, MemOperand(sp, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
|
||||||
|
ApiFunction *function) {
|
||||||
|
__ mov(lr, Operand(reinterpret_cast<intptr_t>(GetCode().location()),
|
||||||
|
RelocInfo::CODE_TARGET));
|
||||||
|
// Push return address (accessible to GC through exit frame pc).
|
||||||
|
__ mov(r2,
|
||||||
|
Operand(ExternalReference(function, ExternalReference::DIRECT_CALL)));
|
||||||
|
__ str(pc, MemOperand(sp, 0));
|
||||||
|
__ Jump(r2); // Call the api function.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
void GenerateFastPixelArrayLoad(MacroAssembler* masm,
|
||||||
Register receiver,
|
Register receiver,
|
||||||
Register key,
|
Register key,
|
||||||
|
@ -571,6 +571,24 @@ class RegExpCEntryStub: public CodeStub {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Trampoline stub to call into native code. To call safely into native code
|
||||||
|
// in the presence of compacting GC (which can move code objects) we need to
|
||||||
|
// keep the code which called into native pinned in the memory. Currently the
|
||||||
|
// simplest approach is to generate such stub early enough so it can never be
|
||||||
|
// moved by GC
|
||||||
|
class DirectCEntryStub: public CodeStub {
|
||||||
|
public:
|
||||||
|
DirectCEntryStub() {}
|
||||||
|
void Generate(MacroAssembler* masm);
|
||||||
|
void GenerateCall(MacroAssembler* masm, ApiFunction *function);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Major MajorKey() { return DirectCEntry; }
|
||||||
|
int MinorKey() { return 0; }
|
||||||
|
const char* GetName() { return "DirectCEntryStub"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Generate code the to load an element from a pixel array. The receiver is
|
// Generate code the to load an element from a pixel array. The receiver is
|
||||||
// assumed to not be a smi and to have elements, the caller must guarantee this
|
// assumed to not be a smi and to have elements, the caller must guarantee this
|
||||||
// precondition. If the receiver does not have elements that are pixel arrays,
|
// precondition. If the receiver does not have elements that are pixel arrays,
|
||||||
|
@ -632,11 +632,7 @@ void MacroAssembler::LeaveFrame(StackFrame::Type type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::EnterExitFrame(bool save_doubles) {
|
void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
|
||||||
// Compute the argv pointer in a callee-saved register.
|
|
||||||
add(r6, sp, Operand(r0, LSL, kPointerSizeLog2));
|
|
||||||
sub(r6, r6, Operand(kPointerSize));
|
|
||||||
|
|
||||||
// Setup the frame structure on the stack.
|
// Setup the frame structure on the stack.
|
||||||
ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
|
ASSERT_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
|
||||||
ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
|
ASSERT_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
|
||||||
@ -658,10 +654,6 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) {
|
|||||||
mov(ip, Operand(ExternalReference(Top::k_context_address)));
|
mov(ip, Operand(ExternalReference(Top::k_context_address)));
|
||||||
str(cp, MemOperand(ip));
|
str(cp, MemOperand(ip));
|
||||||
|
|
||||||
// Setup argc and the builtin function in callee-saved registers.
|
|
||||||
mov(r4, Operand(r0));
|
|
||||||
mov(r5, Operand(r1));
|
|
||||||
|
|
||||||
// Optionally save all double registers.
|
// Optionally save all double registers.
|
||||||
if (save_doubles) {
|
if (save_doubles) {
|
||||||
sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize));
|
sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize));
|
||||||
@ -675,10 +667,10 @@ void MacroAssembler::EnterExitFrame(bool save_doubles) {
|
|||||||
// since the sp slot and code slot were pushed after the fp.
|
// since the sp slot and code slot were pushed after the fp.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve place for the return address and align the frame preparing for
|
// Reserve place for the return address and stack space and align the frame
|
||||||
// calling the runtime function.
|
// preparing for calling the runtime function.
|
||||||
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
|
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
|
||||||
sub(sp, sp, Operand(kPointerSize));
|
sub(sp, sp, Operand((stack_space + 1) * kPointerSize));
|
||||||
if (frame_alignment > 0) {
|
if (frame_alignment > 0) {
|
||||||
ASSERT(IsPowerOf2(frame_alignment));
|
ASSERT(IsPowerOf2(frame_alignment));
|
||||||
and_(sp, sp, Operand(-frame_alignment));
|
and_(sp, sp, Operand(-frame_alignment));
|
||||||
@ -1475,17 +1467,115 @@ void MacroAssembler::TryGetFunctionPrototype(Register function,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
|
void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
|
||||||
ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs
|
ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs.
|
||||||
Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
|
Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
|
void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
|
||||||
ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs
|
ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs.
|
||||||
Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
|
Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub, Condition cond) {
|
||||||
|
ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs.
|
||||||
|
Object* result;
|
||||||
|
{ MaybeObject* maybe_result = stub->TryGetCode();
|
||||||
|
if (!maybe_result->ToObject(&result)) return maybe_result;
|
||||||
|
}
|
||||||
|
Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
|
||||||
|
return ref0.address() - ref1.address();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(
|
||||||
|
ApiFunction* function, int stack_space) {
|
||||||
|
ExternalReference next_address =
|
||||||
|
ExternalReference::handle_scope_next_address();
|
||||||
|
const int kNextOffset = 0;
|
||||||
|
const int kLimitOffset = AddressOffset(
|
||||||
|
ExternalReference::handle_scope_limit_address(),
|
||||||
|
next_address);
|
||||||
|
const int kLevelOffset = AddressOffset(
|
||||||
|
ExternalReference::handle_scope_level_address(),
|
||||||
|
next_address);
|
||||||
|
|
||||||
|
// Allocate HandleScope in callee-save registers.
|
||||||
|
mov(r7, Operand(next_address));
|
||||||
|
ldr(r4, MemOperand(r7, kNextOffset));
|
||||||
|
ldr(r5, MemOperand(r7, kLimitOffset));
|
||||||
|
ldr(r6, MemOperand(r7, kLevelOffset));
|
||||||
|
add(r6, r6, Operand(1));
|
||||||
|
str(r6, MemOperand(r7, kLevelOffset));
|
||||||
|
|
||||||
|
// Native call returns to the DirectCEntry stub which redirects to the
|
||||||
|
// return address pushed on stack (could have moved after GC).
|
||||||
|
// DirectCEntry stub itself is generated early and never moves.
|
||||||
|
DirectCEntryStub stub;
|
||||||
|
stub.GenerateCall(this, function);
|
||||||
|
|
||||||
|
Label promote_scheduled_exception;
|
||||||
|
Label delete_allocated_handles;
|
||||||
|
Label leave_exit_frame;
|
||||||
|
|
||||||
|
// If result is non-zero, dereference to get the result value
|
||||||
|
// otherwise set it to undefined.
|
||||||
|
cmp(r0, Operand(0));
|
||||||
|
LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
|
||||||
|
ldr(r0, MemOperand(r0), ne);
|
||||||
|
|
||||||
|
// No more valid handles (the result handle was the last one). Restore
|
||||||
|
// previous handle scope.
|
||||||
|
str(r4, MemOperand(r7, kNextOffset));
|
||||||
|
if (FLAG_debug_code) {
|
||||||
|
ldr(r1, MemOperand(r7, kLevelOffset));
|
||||||
|
cmp(r1, r6);
|
||||||
|
Check(eq, "Unexpected level after return from api call");
|
||||||
|
}
|
||||||
|
sub(r6, r6, Operand(1));
|
||||||
|
str(r6, MemOperand(r7, kLevelOffset));
|
||||||
|
ldr(ip, MemOperand(r7, kLimitOffset));
|
||||||
|
cmp(r5, ip);
|
||||||
|
b(ne, &delete_allocated_handles);
|
||||||
|
|
||||||
|
// Check if the function scheduled an exception.
|
||||||
|
bind(&leave_exit_frame);
|
||||||
|
LoadRoot(r4, Heap::kTheHoleValueRootIndex);
|
||||||
|
mov(ip, Operand(ExternalReference::scheduled_exception_address()));
|
||||||
|
ldr(r5, MemOperand(ip));
|
||||||
|
cmp(r4, r5);
|
||||||
|
b(ne, &promote_scheduled_exception);
|
||||||
|
|
||||||
|
// LeaveExitFrame expects unwind space to be in r4.
|
||||||
|
mov(r4, Operand(stack_space));
|
||||||
|
LeaveExitFrame(false);
|
||||||
|
|
||||||
|
bind(&promote_scheduled_exception);
|
||||||
|
MaybeObject* result = TryTailCallExternalReference(
|
||||||
|
ExternalReference(Runtime::kPromoteScheduledException), 0, 1);
|
||||||
|
if (result->IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleScope limit has changed. Delete allocated extensions.
|
||||||
|
bind(&delete_allocated_handles);
|
||||||
|
str(r5, MemOperand(r7, kLimitOffset));
|
||||||
|
mov(r4, r0);
|
||||||
|
PrepareCallCFunction(0, r5);
|
||||||
|
CallCFunction(ExternalReference::delete_handle_scope_extensions(), 0);
|
||||||
|
mov(r0, r4);
|
||||||
|
jmp(&leave_exit_frame);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::IllegalOperation(int num_arguments) {
|
void MacroAssembler::IllegalOperation(int num_arguments) {
|
||||||
if (num_arguments > 0) {
|
if (num_arguments > 0) {
|
||||||
add(sp, sp, Operand(num_arguments * kPointerSize));
|
add(sp, sp, Operand(num_arguments * kPointerSize));
|
||||||
@ -1740,6 +1830,17 @@ void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MaybeObject* MacroAssembler::TryTailCallExternalReference(
|
||||||
|
const ExternalReference& ext, int num_arguments, int result_size) {
|
||||||
|
// TODO(1236192): Most runtime routines don't need the number of
|
||||||
|
// arguments passed in because it is constant. At some point we
|
||||||
|
// should remove this need and make the runtime routine entry code
|
||||||
|
// smarter.
|
||||||
|
mov(r0, Operand(num_arguments));
|
||||||
|
return TryJumpToExternalReference(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
|
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
|
||||||
int num_arguments,
|
int num_arguments,
|
||||||
int result_size) {
|
int result_size) {
|
||||||
@ -1758,6 +1859,18 @@ void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MaybeObject* MacroAssembler::TryJumpToExternalReference(
|
||||||
|
const ExternalReference& builtin) {
|
||||||
|
#if defined(__thumb__)
|
||||||
|
// Thumb mode builtin.
|
||||||
|
ASSERT((reinterpret_cast<intptr_t>(builtin.address()) & 1) == 1);
|
||||||
|
#endif
|
||||||
|
mov(r1, Operand(builtin));
|
||||||
|
CEntryStub stub(1);
|
||||||
|
return TryTailCallStub(&stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
|
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
|
||||||
InvokeJSFlags flags,
|
InvokeJSFlags flags,
|
||||||
PostCallGenerator* post_call_generator) {
|
PostCallGenerator* post_call_generator) {
|
||||||
|
@ -287,10 +287,8 @@ class MacroAssembler: public Assembler {
|
|||||||
void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
|
void LeaveConstructFrame() { LeaveFrame(StackFrame::CONSTRUCT); }
|
||||||
|
|
||||||
// Enter exit frame.
|
// Enter exit frame.
|
||||||
// Expects the number of arguments in register r0 and
|
// stack_space - extra stack space, used for alignment before call to C.
|
||||||
// the builtin function to call in register r1. Exits with argc in
|
void EnterExitFrame(bool save_doubles, int stack_space = 0);
|
||||||
// r4, argv in r6, and and the builtin function to call in r5.
|
|
||||||
void EnterExitFrame(bool save_doubles);
|
|
||||||
|
|
||||||
// Leave the current exit frame. Expects the return value in r0.
|
// Leave the current exit frame. Expects the return value in r0.
|
||||||
void LeaveExitFrame(bool save_doubles);
|
void LeaveExitFrame(bool save_doubles);
|
||||||
@ -616,6 +614,12 @@ class MacroAssembler: public Assembler {
|
|||||||
// Call a code stub.
|
// Call a code stub.
|
||||||
void TailCallStub(CodeStub* stub, Condition cond = al);
|
void TailCallStub(CodeStub* stub, Condition cond = al);
|
||||||
|
|
||||||
|
// Tail call a code stub (jump) and return the code object called. Try to
|
||||||
|
// generate the code if necessary. Do not perform a GC but instead return
|
||||||
|
// a retry after GC failure.
|
||||||
|
MUST_USE_RESULT MaybeObject* TryTailCallStub(CodeStub* stub,
|
||||||
|
Condition cond = al);
|
||||||
|
|
||||||
// Call a runtime routine.
|
// Call a runtime routine.
|
||||||
void CallRuntime(Runtime::Function* f, int num_arguments);
|
void CallRuntime(Runtime::Function* f, int num_arguments);
|
||||||
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
|
void CallRuntimeSaveDoubles(Runtime::FunctionId id);
|
||||||
@ -634,6 +638,12 @@ class MacroAssembler: public Assembler {
|
|||||||
int num_arguments,
|
int num_arguments,
|
||||||
int result_size);
|
int result_size);
|
||||||
|
|
||||||
|
// Tail call of a runtime routine (jump). Try to generate the code if
|
||||||
|
// necessary. Do not perform a GC but instead return a retry after GC
|
||||||
|
// failure.
|
||||||
|
MUST_USE_RESULT MaybeObject* TryTailCallExternalReference(
|
||||||
|
const ExternalReference& ext, int num_arguments, int result_size);
|
||||||
|
|
||||||
// Convenience function: tail call a runtime routine (jump).
|
// Convenience function: tail call a runtime routine (jump).
|
||||||
void TailCallRuntime(Runtime::FunctionId fid,
|
void TailCallRuntime(Runtime::FunctionId fid,
|
||||||
int num_arguments,
|
int num_arguments,
|
||||||
@ -657,9 +667,18 @@ class MacroAssembler: public Assembler {
|
|||||||
void CallCFunction(ExternalReference function, int num_arguments);
|
void CallCFunction(ExternalReference function, int num_arguments);
|
||||||
void CallCFunction(Register function, int num_arguments);
|
void CallCFunction(Register function, int num_arguments);
|
||||||
|
|
||||||
|
// Calls an API function. Allocates HandleScope, extracts returned value
|
||||||
|
// from handle and propagates exceptions. Restores context.
|
||||||
|
// stack_space - space to be unwound on exit (includes the call js
|
||||||
|
// arguments space and the additional space allocated for the fast call).
|
||||||
|
MaybeObject* TryCallApiFunctionAndReturn(ApiFunction* function,
|
||||||
|
int stack_space);
|
||||||
|
|
||||||
// Jump to a runtime routine.
|
// Jump to a runtime routine.
|
||||||
void JumpToExternalReference(const ExternalReference& builtin);
|
void JumpToExternalReference(const ExternalReference& builtin);
|
||||||
|
|
||||||
|
MaybeObject* TryJumpToExternalReference(const ExternalReference& ext);
|
||||||
|
|
||||||
// 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(Builtins::JavaScript id,
|
void InvokeBuiltin(Builtins::JavaScript id,
|
||||||
|
@ -744,10 +744,10 @@ Simulator::Simulator() {
|
|||||||
// offset from the svc instruction so the simulator knows what to call.
|
// offset from the svc instruction so the simulator knows what to call.
|
||||||
class Redirection {
|
class Redirection {
|
||||||
public:
|
public:
|
||||||
Redirection(void* external_function, bool fp_return)
|
Redirection(void* external_function, ExternalReference::Type type)
|
||||||
: external_function_(external_function),
|
: external_function_(external_function),
|
||||||
swi_instruction_(al | (0xf*B24) | kCallRtRedirected),
|
swi_instruction_(al | (0xf*B24) | kCallRtRedirected),
|
||||||
fp_return_(fp_return),
|
type_(type),
|
||||||
next_(list_) {
|
next_(list_) {
|
||||||
Simulator::current()->
|
Simulator::current()->
|
||||||
FlushICache(reinterpret_cast<void*>(&swi_instruction_),
|
FlushICache(reinterpret_cast<void*>(&swi_instruction_),
|
||||||
@ -760,14 +760,15 @@ class Redirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* external_function() { return external_function_; }
|
void* external_function() { return external_function_; }
|
||||||
bool fp_return() { return fp_return_; }
|
ExternalReference::Type type() { return type_; }
|
||||||
|
|
||||||
static Redirection* Get(void* external_function, bool fp_return) {
|
static Redirection* Get(void* external_function,
|
||||||
|
ExternalReference::Type type) {
|
||||||
Redirection* current;
|
Redirection* current;
|
||||||
for (current = list_; current != NULL; current = current->next_) {
|
for (current = list_; current != NULL; current = current->next_) {
|
||||||
if (current->external_function_ == external_function) return current;
|
if (current->external_function_ == external_function) return current;
|
||||||
}
|
}
|
||||||
return new Redirection(external_function, fp_return);
|
return new Redirection(external_function, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
|
static Redirection* FromSwiInstruction(Instruction* swi_instruction) {
|
||||||
@ -780,7 +781,7 @@ class Redirection {
|
|||||||
private:
|
private:
|
||||||
void* external_function_;
|
void* external_function_;
|
||||||
uint32_t swi_instruction_;
|
uint32_t swi_instruction_;
|
||||||
bool fp_return_;
|
ExternalReference::Type type_;
|
||||||
Redirection* next_;
|
Redirection* next_;
|
||||||
static Redirection* list_;
|
static Redirection* list_;
|
||||||
};
|
};
|
||||||
@ -790,8 +791,8 @@ Redirection* Redirection::list_ = NULL;
|
|||||||
|
|
||||||
|
|
||||||
void* Simulator::RedirectExternalReference(void* external_function,
|
void* Simulator::RedirectExternalReference(void* external_function,
|
||||||
bool fp_return) {
|
ExternalReference::Type type) {
|
||||||
Redirection* redirection = Redirection::Get(external_function, fp_return);
|
Redirection* redirection = Redirection::Get(external_function, type);
|
||||||
return redirection->address_of_swi_instruction();
|
return redirection->address_of_swi_instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1528,6 +1529,9 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
|
|||||||
int32_t arg2,
|
int32_t arg2,
|
||||||
int32_t arg3);
|
int32_t arg3);
|
||||||
|
|
||||||
|
// This signature supports direct call in to API function native callback
|
||||||
|
// (refer to InvocationCallback in v8.h).
|
||||||
|
typedef v8::Handle<v8::Value> (*SimulatorRuntimeApiCall)(int32_t arg0);
|
||||||
|
|
||||||
// Software interrupt instructions are used by the simulator to call into the
|
// Software interrupt instructions are used by the simulator to call into the
|
||||||
// C-based V8 runtime.
|
// C-based V8 runtime.
|
||||||
@ -1550,9 +1554,9 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
|||||||
// This is dodgy but it works because the C entry stubs are never moved.
|
// This is dodgy but it works because the C entry stubs are never moved.
|
||||||
// See comment in codegen-arm.cc and bug 1242173.
|
// See comment in codegen-arm.cc and bug 1242173.
|
||||||
int32_t saved_lr = get_register(lr);
|
int32_t saved_lr = get_register(lr);
|
||||||
if (redirection->fp_return()) {
|
intptr_t external =
|
||||||
intptr_t external =
|
reinterpret_cast<intptr_t>(redirection->external_function());
|
||||||
reinterpret_cast<intptr_t>(redirection->external_function());
|
if (redirection->type() == ExternalReference::FP_RETURN_CALL) {
|
||||||
SimulatorRuntimeFPCall target =
|
SimulatorRuntimeFPCall target =
|
||||||
reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
reinterpret_cast<SimulatorRuntimeFPCall>(external);
|
||||||
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||||
@ -1568,9 +1572,28 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
|
|||||||
CHECK(stack_aligned);
|
CHECK(stack_aligned);
|
||||||
double result = target(arg0, arg1, arg2, arg3);
|
double result = target(arg0, arg1, arg2, arg3);
|
||||||
SetFpResult(result);
|
SetFpResult(result);
|
||||||
|
} else if (redirection->type() == ExternalReference::DIRECT_CALL) {
|
||||||
|
SimulatorRuntimeApiCall target =
|
||||||
|
reinterpret_cast<SimulatorRuntimeApiCall>(external);
|
||||||
|
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||||
|
PrintF(
|
||||||
|
"Call to host function at %p args %08x",
|
||||||
|
FUNCTION_ADDR(target),
|
||||||
|
arg0);
|
||||||
|
if (!stack_aligned) {
|
||||||
|
PrintF(" with unaligned stack %08x\n", get_register(sp));
|
||||||
|
}
|
||||||
|
PrintF("\n");
|
||||||
|
}
|
||||||
|
CHECK(stack_aligned);
|
||||||
|
v8::Handle<v8::Value> result = target(arg0);
|
||||||
|
if (::v8::internal::FLAG_trace_sim) {
|
||||||
|
PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
|
||||||
|
}
|
||||||
|
set_register(r0, (int32_t) *result);
|
||||||
} else {
|
} else {
|
||||||
intptr_t external =
|
// builtin call.
|
||||||
reinterpret_cast<int32_t>(redirection->external_function());
|
ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
|
||||||
SimulatorRuntimeCall target =
|
SimulatorRuntimeCall target =
|
||||||
reinterpret_cast<SimulatorRuntimeCall>(external);
|
reinterpret_cast<SimulatorRuntimeCall>(external);
|
||||||
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
|
||||||
|
@ -79,6 +79,7 @@ class SimulatorStack : public v8::internal::AllStatic {
|
|||||||
|
|
||||||
#include "constants-arm.h"
|
#include "constants-arm.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
#include "assembler.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -285,8 +286,9 @@ class Simulator {
|
|||||||
static CachePage* GetCachePage(void* page);
|
static CachePage* GetCachePage(void* page);
|
||||||
|
|
||||||
// Runtime call support.
|
// Runtime call support.
|
||||||
static void* RedirectExternalReference(void* external_function,
|
static void* RedirectExternalReference(
|
||||||
bool fp_return);
|
void* external_function,
|
||||||
|
v8::internal::ExternalReference::Type type);
|
||||||
|
|
||||||
// For use in calls that take two double values, constructed from r0, r1, r2
|
// For use in calls that take two double values, constructed from r0, r1, r2
|
||||||
// and r3.
|
// and r3.
|
||||||
|
@ -575,72 +575,94 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
|
|||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int kFastApiCallArguments = 3;
|
||||||
|
|
||||||
// Reserves space for the extra arguments to FastHandleApiCall in the
|
// Reserves space for the extra arguments to FastHandleApiCall in the
|
||||||
// caller's frame.
|
// caller's frame.
|
||||||
//
|
//
|
||||||
// These arguments are set by CheckPrototypes and GenerateFastApiCall.
|
// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
|
||||||
static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
|
static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
|
||||||
Register scratch) {
|
Register scratch) {
|
||||||
__ mov(scratch, Operand(Smi::FromInt(0)));
|
__ mov(scratch, Operand(Smi::FromInt(0)));
|
||||||
__ push(scratch);
|
for (int i = 0; i < kFastApiCallArguments; i++) {
|
||||||
__ push(scratch);
|
__ push(scratch);
|
||||||
__ push(scratch);
|
}
|
||||||
__ push(scratch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Undoes the effects of ReserveSpaceForFastApiCall.
|
// Undoes the effects of ReserveSpaceForFastApiCall.
|
||||||
static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
|
static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
|
||||||
__ Drop(4);
|
__ Drop(kFastApiCallArguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generates call to FastHandleApiCall builtin.
|
static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
|
||||||
static void GenerateFastApiCall(MacroAssembler* masm,
|
const CallOptimization& optimization,
|
||||||
const CallOptimization& optimization,
|
int argc) {
|
||||||
int argc) {
|
// ----------- S t a t e -------------
|
||||||
|
// -- sp[0] : holder (set by CheckPrototypes)
|
||||||
|
// -- sp[4] : callee js function
|
||||||
|
// -- sp[8] : call data
|
||||||
|
// -- sp[12] : last js argument
|
||||||
|
// -- ...
|
||||||
|
// -- sp[(argc + 3) * 4] : first js argument
|
||||||
|
// -- sp[(argc + 4) * 4] : receiver
|
||||||
|
// -----------------------------------
|
||||||
// Get the function and setup the context.
|
// Get the function and setup the context.
|
||||||
JSFunction* function = optimization.constant_function();
|
JSFunction* function = optimization.constant_function();
|
||||||
__ mov(r5, Operand(Handle<JSFunction>(function)));
|
__ mov(r5, Operand(Handle<JSFunction>(function)));
|
||||||
__ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
|
__ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
|
||||||
|
|
||||||
// Pass the additional arguments FastHandleApiCall expects.
|
// Pass the additional arguments FastHandleApiCall expects.
|
||||||
bool info_loaded = false;
|
|
||||||
Object* callback = optimization.api_call_info()->callback();
|
|
||||||
if (Heap::InNewSpace(callback)) {
|
|
||||||
info_loaded = true;
|
|
||||||
__ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
|
|
||||||
__ ldr(r7, FieldMemOperand(r0, CallHandlerInfo::kCallbackOffset));
|
|
||||||
} else {
|
|
||||||
__ Move(r7, Handle<Object>(callback));
|
|
||||||
}
|
|
||||||
Object* call_data = optimization.api_call_info()->data();
|
Object* call_data = optimization.api_call_info()->data();
|
||||||
|
Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
|
||||||
if (Heap::InNewSpace(call_data)) {
|
if (Heap::InNewSpace(call_data)) {
|
||||||
if (!info_loaded) {
|
__ Move(r0, api_call_info_handle);
|
||||||
__ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
|
|
||||||
}
|
|
||||||
__ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
|
__ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
|
||||||
} else {
|
} else {
|
||||||
__ Move(r6, Handle<Object>(call_data));
|
__ Move(r6, Handle<Object>(call_data));
|
||||||
}
|
}
|
||||||
|
// Store js function and call data.
|
||||||
|
__ stm(ib, sp, r5.bit() | r6.bit());
|
||||||
|
|
||||||
__ add(sp, sp, Operand(1 * kPointerSize));
|
// r2 points to call data as expected by Arguments
|
||||||
__ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
|
// (refer to layout above).
|
||||||
__ sub(sp, sp, Operand(1 * kPointerSize));
|
__ add(r2, sp, Operand(2 * kPointerSize));
|
||||||
|
|
||||||
// Set the number of arguments.
|
Object* callback = optimization.api_call_info()->callback();
|
||||||
__ mov(r0, Operand(argc + 4));
|
Address api_function_address = v8::ToCData<Address>(callback);
|
||||||
|
ApiFunction fun(api_function_address);
|
||||||
|
|
||||||
// Jump to the fast api call builtin (tail call).
|
const int kApiStackSpace = 4;
|
||||||
Handle<Code> code = Handle<Code>(
|
__ EnterExitFrame(false, kApiStackSpace);
|
||||||
Builtins::builtin(Builtins::FastHandleApiCall));
|
|
||||||
ParameterCount expected(0);
|
// r0 = v8::Arguments&
|
||||||
__ InvokeCode(code, expected, expected,
|
// Arguments is after the return address.
|
||||||
RelocInfo::CODE_TARGET, JUMP_FUNCTION);
|
__ add(r0, sp, Operand(1 * kPointerSize));
|
||||||
|
// v8::Arguments::implicit_args = data
|
||||||
|
__ str(r2, MemOperand(r0, 0 * kPointerSize));
|
||||||
|
// v8::Arguments::values = last argument
|
||||||
|
__ add(ip, r2, Operand(argc * kPointerSize));
|
||||||
|
__ str(ip, MemOperand(r0, 1 * kPointerSize));
|
||||||
|
// v8::Arguments::length_ = argc
|
||||||
|
__ mov(ip, Operand(argc));
|
||||||
|
__ str(ip, MemOperand(r0, 2 * kPointerSize));
|
||||||
|
// v8::Arguments::is_construct_call = 0
|
||||||
|
__ mov(ip, Operand(0));
|
||||||
|
__ str(ip, MemOperand(r0, 3 * kPointerSize));
|
||||||
|
|
||||||
|
// Emitting a stub call may try to allocate (if the code is not
|
||||||
|
// already generated). Do not allow the assembler to perform a
|
||||||
|
// garbage collection but instead return the allocation failure
|
||||||
|
// object.
|
||||||
|
MaybeObject* result = masm->TryCallApiFunctionAndReturn(
|
||||||
|
&fun, argc + kFastApiCallArguments + 1);
|
||||||
|
if (result->IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return Heap::undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CallInterceptorCompiler BASE_EMBEDDED {
|
class CallInterceptorCompiler BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
CallInterceptorCompiler(StubCompiler* stub_compiler,
|
CallInterceptorCompiler(StubCompiler* stub_compiler,
|
||||||
@ -650,16 +672,16 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|||||||
arguments_(arguments),
|
arguments_(arguments),
|
||||||
name_(name) {}
|
name_(name) {}
|
||||||
|
|
||||||
void Compile(MacroAssembler* masm,
|
MaybeObject* Compile(MacroAssembler* masm,
|
||||||
JSObject* object,
|
JSObject* object,
|
||||||
JSObject* holder,
|
JSObject* holder,
|
||||||
String* name,
|
String* name,
|
||||||
LookupResult* lookup,
|
LookupResult* lookup,
|
||||||
Register receiver,
|
Register receiver,
|
||||||
Register scratch1,
|
Register scratch1,
|
||||||
Register scratch2,
|
Register scratch2,
|
||||||
Register scratch3,
|
Register scratch3,
|
||||||
Label* miss) {
|
Label* miss) {
|
||||||
ASSERT(holder->HasNamedInterceptor());
|
ASSERT(holder->HasNamedInterceptor());
|
||||||
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||||
|
|
||||||
@ -669,17 +691,17 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|||||||
CallOptimization optimization(lookup);
|
CallOptimization optimization(lookup);
|
||||||
|
|
||||||
if (optimization.is_constant_call()) {
|
if (optimization.is_constant_call()) {
|
||||||
CompileCacheable(masm,
|
return CompileCacheable(masm,
|
||||||
object,
|
object,
|
||||||
receiver,
|
receiver,
|
||||||
scratch1,
|
scratch1,
|
||||||
scratch2,
|
scratch2,
|
||||||
scratch3,
|
scratch3,
|
||||||
holder,
|
holder,
|
||||||
lookup,
|
lookup,
|
||||||
name,
|
name,
|
||||||
optimization,
|
optimization,
|
||||||
miss);
|
miss);
|
||||||
} else {
|
} else {
|
||||||
CompileRegular(masm,
|
CompileRegular(masm,
|
||||||
object,
|
object,
|
||||||
@ -690,21 +712,22 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|||||||
name,
|
name,
|
||||||
holder,
|
holder,
|
||||||
miss);
|
miss);
|
||||||
|
return Heap::undefined_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CompileCacheable(MacroAssembler* masm,
|
MaybeObject* CompileCacheable(MacroAssembler* masm,
|
||||||
JSObject* object,
|
JSObject* object,
|
||||||
Register receiver,
|
Register receiver,
|
||||||
Register scratch1,
|
Register scratch1,
|
||||||
Register scratch2,
|
Register scratch2,
|
||||||
Register scratch3,
|
Register scratch3,
|
||||||
JSObject* interceptor_holder,
|
JSObject* interceptor_holder,
|
||||||
LookupResult* lookup,
|
LookupResult* lookup,
|
||||||
String* name,
|
String* name,
|
||||||
const CallOptimization& optimization,
|
const CallOptimization& optimization,
|
||||||
Label* miss_label) {
|
Label* miss_label) {
|
||||||
ASSERT(optimization.is_constant_call());
|
ASSERT(optimization.is_constant_call());
|
||||||
ASSERT(!lookup->holder()->IsGlobalObject());
|
ASSERT(!lookup->holder()->IsGlobalObject());
|
||||||
|
|
||||||
@ -768,7 +791,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|||||||
|
|
||||||
// Invoke function.
|
// Invoke function.
|
||||||
if (can_do_fast_api_call) {
|
if (can_do_fast_api_call) {
|
||||||
GenerateFastApiCall(masm, optimization, arguments_.immediate());
|
MaybeObject* result = GenerateFastApiDirectCall(masm,
|
||||||
|
optimization,
|
||||||
|
arguments_.immediate());
|
||||||
|
if (result->IsFailure()) return result;
|
||||||
} else {
|
} else {
|
||||||
__ InvokeFunction(optimization.constant_function(), arguments_,
|
__ InvokeFunction(optimization.constant_function(), arguments_,
|
||||||
JUMP_FUNCTION);
|
JUMP_FUNCTION);
|
||||||
@ -786,6 +812,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|||||||
if (can_do_fast_api_call) {
|
if (can_do_fast_api_call) {
|
||||||
FreeSpaceForFastApiCall(masm);
|
FreeSpaceForFastApiCall(masm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Heap::undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompileRegular(MacroAssembler* masm,
|
void CompileRegular(MacroAssembler* masm,
|
||||||
@ -2368,7 +2396,8 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (depth != kInvalidProtoDepth) {
|
if (depth != kInvalidProtoDepth) {
|
||||||
GenerateFastApiCall(masm(), optimization, argc);
|
MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
|
||||||
|
if (result->IsFailure()) return result;
|
||||||
} else {
|
} else {
|
||||||
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
__ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
||||||
}
|
}
|
||||||
@ -2412,16 +2441,19 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
|
|||||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||||
|
|
||||||
CallInterceptorCompiler compiler(this, arguments(), r2);
|
CallInterceptorCompiler compiler(this, arguments(), r2);
|
||||||
compiler.Compile(masm(),
|
MaybeObject* result = compiler.Compile(masm(),
|
||||||
object,
|
object,
|
||||||
holder,
|
holder,
|
||||||
name,
|
name,
|
||||||
&lookup,
|
&lookup,
|
||||||
r1,
|
r1,
|
||||||
r3,
|
r3,
|
||||||
r4,
|
r4,
|
||||||
r0,
|
r0,
|
||||||
&miss);
|
&miss);
|
||||||
|
if (result->IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Move returned value, the function to call, to r1.
|
// Move returned value, the function to call, to r1.
|
||||||
__ mov(r1, r0);
|
__ mov(r1, r0);
|
||||||
|
@ -553,8 +553,9 @@ ExternalReference::ExternalReference(Builtins::CFunctionId id)
|
|||||||
: address_(Redirect(Builtins::c_function_address(id))) {}
|
: address_(Redirect(Builtins::c_function_address(id))) {}
|
||||||
|
|
||||||
|
|
||||||
ExternalReference::ExternalReference(ApiFunction* fun)
|
ExternalReference::ExternalReference(
|
||||||
: address_(Redirect(fun->address())) {}
|
ApiFunction* fun, Type type = ExternalReference::BUILTIN_CALL)
|
||||||
|
: address_(Redirect(fun->address(), type)) {}
|
||||||
|
|
||||||
|
|
||||||
ExternalReference::ExternalReference(Builtins::Name name)
|
ExternalReference::ExternalReference(Builtins::Name name)
|
||||||
@ -888,17 +889,18 @@ ExternalReference ExternalReference::double_fp_operation(
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
// Passing true as 2nd parameter indicates that they return an fp value.
|
// Passing true as 2nd parameter indicates that they return an fp value.
|
||||||
return ExternalReference(Redirect(FUNCTION_ADDR(function), true));
|
return ExternalReference(Redirect(FUNCTION_ADDR(function), FP_RETURN_CALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExternalReference ExternalReference::compare_doubles() {
|
ExternalReference ExternalReference::compare_doubles() {
|
||||||
return ExternalReference(Redirect(FUNCTION_ADDR(native_compare_doubles),
|
return ExternalReference(Redirect(FUNCTION_ADDR(native_compare_doubles),
|
||||||
false));
|
BUILTIN_CALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExternalReferenceRedirector* ExternalReference::redirector_ = NULL;
|
ExternalReference::ExternalReferenceRedirector*
|
||||||
|
ExternalReference::redirector_ = NULL;
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
|
@ -459,9 +459,6 @@ class Debug_Address;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef void* ExternalReferenceRedirector(void* original, bool fp_return);
|
|
||||||
|
|
||||||
|
|
||||||
// An ExternalReference represents a C++ address used in the generated
|
// An ExternalReference represents a C++ address used in the generated
|
||||||
// code. All references to C++ functions and variables must be encapsulated in
|
// code. All references to C++ functions and variables must be encapsulated in
|
||||||
// an ExternalReference instance. This is done in order to track the origin of
|
// an ExternalReference instance. This is done in order to track the origin of
|
||||||
@ -469,9 +466,29 @@ typedef void* ExternalReferenceRedirector(void* original, bool fp_return);
|
|||||||
// addresses when deserializing a heap.
|
// addresses when deserializing a heap.
|
||||||
class ExternalReference BASE_EMBEDDED {
|
class ExternalReference BASE_EMBEDDED {
|
||||||
public:
|
public:
|
||||||
|
// Used in the simulator to support different native api calls.
|
||||||
|
//
|
||||||
|
// BUILTIN_CALL - builtin call.
|
||||||
|
// MaybeObject* f(v8::internal::Arguments).
|
||||||
|
//
|
||||||
|
// FP_RETURN_CALL - builtin call that returns floating point.
|
||||||
|
// double f(double, double).
|
||||||
|
//
|
||||||
|
// DIRECT_CALL - direct call to API function native callback
|
||||||
|
// from generated code.
|
||||||
|
// Handle<Value> f(v8::Arguments&)
|
||||||
|
//
|
||||||
|
enum Type {
|
||||||
|
BUILTIN_CALL, // default
|
||||||
|
FP_RETURN_CALL,
|
||||||
|
DIRECT_CALL
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void* ExternalReferenceRedirector(void* original, Type type);
|
||||||
|
|
||||||
explicit ExternalReference(Builtins::CFunctionId id);
|
explicit ExternalReference(Builtins::CFunctionId id);
|
||||||
|
|
||||||
explicit ExternalReference(ApiFunction* ptr);
|
explicit ExternalReference(ApiFunction* ptr, Type type);
|
||||||
|
|
||||||
explicit ExternalReference(Builtins::Name name);
|
explicit ExternalReference(Builtins::Name name);
|
||||||
|
|
||||||
@ -599,17 +616,19 @@ class ExternalReference BASE_EMBEDDED {
|
|||||||
|
|
||||||
static ExternalReferenceRedirector* redirector_;
|
static ExternalReferenceRedirector* redirector_;
|
||||||
|
|
||||||
static void* Redirect(void* address, bool fp_return = false) {
|
static void* Redirect(void* address,
|
||||||
|
Type type = ExternalReference::BUILTIN_CALL) {
|
||||||
if (redirector_ == NULL) return address;
|
if (redirector_ == NULL) return address;
|
||||||
void* answer = (*redirector_)(address, fp_return);
|
void* answer = (*redirector_)(address, type);
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* Redirect(Address address_arg, bool fp_return = false) {
|
static void* Redirect(Address address_arg,
|
||||||
|
Type type = ExternalReference::BUILTIN_CALL) {
|
||||||
void* address = reinterpret_cast<void*>(address_arg);
|
void* address = reinterpret_cast<void*>(address_arg);
|
||||||
void* answer = (redirector_ == NULL) ?
|
void* answer = (redirector_ == NULL) ?
|
||||||
address :
|
address :
|
||||||
(*redirector_)(address, fp_return);
|
(*redirector_)(address, type);
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,8 @@ namespace internal {
|
|||||||
V(GetProperty) \
|
V(GetProperty) \
|
||||||
V(SetProperty) \
|
V(SetProperty) \
|
||||||
V(InvokeBuiltin) \
|
V(InvokeBuiltin) \
|
||||||
V(RegExpCEntry)
|
V(RegExpCEntry) \
|
||||||
|
V(DirectCEntry)
|
||||||
#else
|
#else
|
||||||
#define CODE_STUB_LIST_ARM(V)
|
#define CODE_STUB_LIST_ARM(V)
|
||||||
#endif
|
#endif
|
||||||
|
11
src/heap.cc
11
src/heap.cc
@ -1943,6 +1943,14 @@ void Heap::CreateJSConstructEntryStub() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if V8_TARGET_ARCH_ARM
|
||||||
|
void Heap::CreateDirectCEntryStub() {
|
||||||
|
DirectCEntryStub stub;
|
||||||
|
set_direct_c_entry_code(*stub.GetCode());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void Heap::CreateFixedStubs() {
|
void Heap::CreateFixedStubs() {
|
||||||
// Here we create roots for fixed stubs. They are needed at GC
|
// Here we create roots for fixed stubs. They are needed at GC
|
||||||
// for cooking and uncooking (check out frames.cc).
|
// for cooking and uncooking (check out frames.cc).
|
||||||
@ -1963,6 +1971,9 @@ void Heap::CreateFixedStubs() {
|
|||||||
#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
|
#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
|
||||||
Heap::CreateRegExpCEntryStub();
|
Heap::CreateRegExpCEntryStub();
|
||||||
#endif
|
#endif
|
||||||
|
#if V8_TARGET_ARCH_ARM
|
||||||
|
Heap::CreateDirectCEntryStub();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10
src/heap.h
10
src/heap.h
@ -122,7 +122,12 @@ namespace internal {
|
|||||||
#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
|
#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
|
||||||
#define STRONG_ROOT_LIST(V) \
|
#define STRONG_ROOT_LIST(V) \
|
||||||
UNCONDITIONAL_STRONG_ROOT_LIST(V) \
|
UNCONDITIONAL_STRONG_ROOT_LIST(V) \
|
||||||
V(Code, re_c_entry_code, RegExpCEntryCode)
|
V(Code, re_c_entry_code, RegExpCEntryCode) \
|
||||||
|
V(Code, direct_c_entry_code, DirectCEntryCode)
|
||||||
|
#elif V8_TARGET_ARCH_ARM
|
||||||
|
#define STRONG_ROOT_LIST(V) \
|
||||||
|
UNCONDITIONAL_STRONG_ROOT_LIST(V) \
|
||||||
|
V(Code, direct_c_entry_code, DirectCEntryCode)
|
||||||
#else
|
#else
|
||||||
#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V)
|
#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V)
|
||||||
#endif
|
#endif
|
||||||
@ -1320,12 +1325,13 @@ class Heap : public AllStatic {
|
|||||||
static bool CreateInitialMaps();
|
static bool CreateInitialMaps();
|
||||||
static bool CreateInitialObjects();
|
static bool CreateInitialObjects();
|
||||||
|
|
||||||
// These four Create*EntryStub functions are here and forced to not be inlined
|
// These five Create*EntryStub functions are here and forced to not be inlined
|
||||||
// because of a gcc-4.4 bug that assigns wrong vtable entries.
|
// because of a gcc-4.4 bug that assigns wrong vtable entries.
|
||||||
NO_INLINE(static void CreateCEntryStub());
|
NO_INLINE(static void CreateCEntryStub());
|
||||||
NO_INLINE(static void CreateJSEntryStub());
|
NO_INLINE(static void CreateJSEntryStub());
|
||||||
NO_INLINE(static void CreateJSConstructEntryStub());
|
NO_INLINE(static void CreateJSConstructEntryStub());
|
||||||
NO_INLINE(static void CreateRegExpCEntryStub());
|
NO_INLINE(static void CreateRegExpCEntryStub());
|
||||||
|
NO_INLINE(static void CreateDirectCEntryStub());
|
||||||
|
|
||||||
static void CreateFixedStubs();
|
static void CreateFixedStubs();
|
||||||
|
|
||||||
|
@ -32,11 +32,11 @@
|
|||||||
#include "compilation-cache.h"
|
#include "compilation-cache.h"
|
||||||
#include "frames-inl.h"
|
#include "frames-inl.h"
|
||||||
#include "runtime-profiler.h"
|
#include "runtime-profiler.h"
|
||||||
#include "simulator.h"
|
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
class Simulator;
|
||||||
|
|
||||||
#define RETURN_IF_SCHEDULED_EXCEPTION() \
|
#define RETURN_IF_SCHEDULED_EXCEPTION() \
|
||||||
if (Top::has_scheduled_exception()) return Top::PromoteScheduledException()
|
if (Top::has_scheduled_exception()) return Top::PromoteScheduledException()
|
||||||
|
@ -7525,6 +7525,61 @@ static void GenerateSomeGarbage() {
|
|||||||
"garbage = undefined;");
|
"garbage = undefined;");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
|
||||||
|
static int count = 0;
|
||||||
|
if (count++ % 3 == 0) {
|
||||||
|
v8::V8::LowMemoryNotification(); // This should move the stub
|
||||||
|
GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
|
||||||
|
}
|
||||||
|
return v8::Handle<v8::Value>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
LocalContext context;
|
||||||
|
v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
|
||||||
|
nativeobject_templ->Set("callback",
|
||||||
|
v8::FunctionTemplate::New(DirectApiCallback));
|
||||||
|
v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
|
||||||
|
context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
|
||||||
|
// call the api function multiple times to ensure direct call stub creation.
|
||||||
|
CompileRun(
|
||||||
|
"function f() {"
|
||||||
|
" for (var i = 1; i <= 30; i++) {"
|
||||||
|
" nativeobject.callback();"
|
||||||
|
" }"
|
||||||
|
"}"
|
||||||
|
"f();");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
|
||||||
|
return v8::ThrowException(v8_str("g"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
THREADED_TEST(CallICFastApi_DirectCall_Throw) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
LocalContext context;
|
||||||
|
v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
|
||||||
|
nativeobject_templ->Set("callback",
|
||||||
|
v8::FunctionTemplate::New(ThrowingDirectApiCallback));
|
||||||
|
v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
|
||||||
|
context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
|
||||||
|
// call the api function multiple times to ensure direct call stub creation.
|
||||||
|
v8::Handle<Value> result = CompileRun(
|
||||||
|
"var result = '';"
|
||||||
|
"function f() {"
|
||||||
|
" for (var i = 1; i <= 5; i++) {"
|
||||||
|
" try { nativeobject.callback(); } catch (e) { result += e; }"
|
||||||
|
" }"
|
||||||
|
"}"
|
||||||
|
"f(); result;");
|
||||||
|
CHECK_EQ(v8_str("ggggg"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
|
THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
|
||||||
int interceptor_call_count = 0;
|
int interceptor_call_count = 0;
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
Loading…
Reference in New Issue
Block a user