| Index: src/arm/stub-cache-arm.cc
|
| ===================================================================
|
| --- src/arm/stub-cache-arm.cc (revision 6213)
|
| +++ src/arm/stub-cache-arm.cc (working copy)
|
| @@ -571,6 +571,7 @@
|
| __ CallStub(&stub);
|
| }
|
|
|
| +static const int kFastApiCallArguments = 3;
|
|
|
| // Reserves space for the extra arguments to FastHandleApiCall in the
|
| // caller's frame.
|
| @@ -579,64 +580,84 @@
|
| static void ReserveSpaceForFastApiCall(MacroAssembler* masm,
|
| Register scratch) {
|
| __ mov(scratch, Operand(Smi::FromInt(0)));
|
| - __ push(scratch);
|
| - __ push(scratch);
|
| - __ push(scratch);
|
| - __ push(scratch);
|
| + for (int i = 0; i < kFastApiCallArguments; i++) {
|
| + __ push(scratch);
|
| + }
|
| }
|
|
|
|
|
| // Undoes the effects of ReserveSpaceForFastApiCall.
|
| static void FreeSpaceForFastApiCall(MacroAssembler* masm) {
|
| - __ Drop(4);
|
| + __ Drop(kFastApiCallArguments);
|
| }
|
|
|
|
|
| -// Generates call to FastHandleApiCall builtin.
|
| -static void GenerateFastApiCall(MacroAssembler* masm,
|
| - const CallOptimization& optimization,
|
| - int argc) {
|
| +static bool GenerateFastApiDirectCall(MacroAssembler* masm,
|
| + const CallOptimization& optimization,
|
| + int argc,
|
| + Failure** failure) {
|
| + // ----------- 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.
|
| JSFunction* function = optimization.constant_function();
|
| __ mov(r5, Operand(Handle<JSFunction>(function)));
|
| __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset));
|
|
|
| // 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();
|
| + Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info());
|
| if (Heap::InNewSpace(call_data)) {
|
| - if (!info_loaded) {
|
| - __ Move(r0, Handle<CallHandlerInfo>(optimization.api_call_info()));
|
| - }
|
| + __ Move(r0, api_call_info_handle);
|
| __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset));
|
| } else {
|
| __ Move(r6, Handle<Object>(call_data));
|
| }
|
| + __ stm(ib, sp, r5.bit() | r6.bit());
|
|
|
| - __ add(sp, sp, Operand(1 * kPointerSize));
|
| - __ stm(ia, sp, r5.bit() | r6.bit() | r7.bit());
|
| - __ sub(sp, sp, Operand(1 * kPointerSize));
|
| + // r2 points to calldata as expected by Arguments class (refer layout above)
|
| + __ add(r2, sp, Operand(2 * kPointerSize));
|
|
|
| - // Set the number of arguments.
|
| - __ mov(r0, Operand(argc + 4));
|
| + Object* callback = optimization.api_call_info()->callback();
|
| + Address api_function_address = v8::ToCData<Address>(callback);
|
| + ApiFunction fun(api_function_address);
|
|
|
| - // Jump to the fast api call builtin (tail call).
|
| - Handle<Code> code = Handle<Code>(
|
| - Builtins::builtin(Builtins::FastHandleApiCall));
|
| - ParameterCount expected(0);
|
| - __ InvokeCode(code, expected, expected,
|
| - RelocInfo::CODE_TARGET, JUMP_FUNCTION);
|
| + const int kApiStackSpace = 4;
|
| + __ PrepareCallApiFunction(kApiStackSpace,
|
| + argc + kFastApiCallArguments + 1);
|
| + // v8::Arguments::implicit_args = data
|
| + __ str(r2, MemOperand(sp));
|
| + // v8::Arguments::values = last argument
|
| + __ add(ip, r2, Operand(argc * kPointerSize));
|
| + __ str(ip, MemOperand(sp, 1 * kPointerSize));
|
| + // v8::Arguments::length_ = argc
|
| + __ mov(ip, Operand(argc));
|
| + __ str(ip, MemOperand(sp, 2 * kPointerSize));
|
| + // v8::Arguments::is_construct_call = 0
|
| + __ mov(ip, Operand(0));
|
| + __ str(ip, MemOperand(sp, 3 * kPointerSize));
|
| + // r0 = v8::Arguments&
|
| + __ mov(r0, sp);
|
| +
|
| + // 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);
|
| + if (result->IsFailure()) {
|
| + *failure = Failure::cast(result);
|
| + return false;
|
| + }
|
| + return true;
|
| }
|
|
|
| -
|
| class CallInterceptorCompiler BASE_EMBEDDED {
|
| public:
|
| CallInterceptorCompiler(StubCompiler* stub_compiler,
|
| @@ -646,7 +667,7 @@
|
| arguments_(arguments),
|
| name_(name) {}
|
|
|
| - void Compile(MacroAssembler* masm,
|
| + bool Compile(MacroAssembler* masm,
|
| JSObject* object,
|
| JSObject* holder,
|
| String* name,
|
| @@ -655,7 +676,8 @@
|
| Register scratch1,
|
| Register scratch2,
|
| Register scratch3,
|
| - Label* miss) {
|
| + Label* miss,
|
| + Failure **failure) {
|
| ASSERT(holder->HasNamedInterceptor());
|
| ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
|
|
| @@ -665,7 +687,7 @@
|
| CallOptimization optimization(lookup);
|
|
|
| if (optimization.is_constant_call()) {
|
| - CompileCacheable(masm,
|
| + return CompileCacheable(masm,
|
| object,
|
| receiver,
|
| scratch1,
|
| @@ -675,7 +697,8 @@
|
| lookup,
|
| name,
|
| optimization,
|
| - miss);
|
| + miss,
|
| + failure);
|
| } else {
|
| CompileRegular(masm,
|
| object,
|
| @@ -686,11 +709,12 @@
|
| name,
|
| holder,
|
| miss);
|
| + return true;
|
| }
|
| }
|
|
|
| private:
|
| - void CompileCacheable(MacroAssembler* masm,
|
| + bool CompileCacheable(MacroAssembler* masm,
|
| JSObject* object,
|
| Register receiver,
|
| Register scratch1,
|
| @@ -700,7 +724,8 @@
|
| LookupResult* lookup,
|
| String* name,
|
| const CallOptimization& optimization,
|
| - Label* miss_label) {
|
| + Label* miss_label,
|
| + Failure **failure) {
|
| ASSERT(optimization.is_constant_call());
|
| ASSERT(!lookup->holder()->IsGlobalObject());
|
|
|
| @@ -764,7 +789,13 @@
|
|
|
| // Invoke function.
|
| if (can_do_fast_api_call) {
|
| - GenerateFastApiCall(masm, optimization, arguments_.immediate());
|
| + bool success = GenerateFastApiDirectCall(masm,
|
| + optimization,
|
| + arguments_.immediate(),
|
| + failure);
|
| + if (!success) {
|
| + return false;
|
| + }
|
| } else {
|
| __ InvokeFunction(optimization.constant_function(), arguments_,
|
| JUMP_FUNCTION);
|
| @@ -782,6 +813,8 @@
|
| if (can_do_fast_api_call) {
|
| FreeSpaceForFastApiCall(masm);
|
| }
|
| +
|
| + return true;
|
| }
|
|
|
| void CompileRegular(MacroAssembler* masm,
|
| @@ -2238,7 +2271,14 @@
|
| }
|
|
|
| if (depth != kInvalidProtoDepth) {
|
| - GenerateFastApiCall(masm(), optimization, argc);
|
| + Failure* failure;
|
| + bool success = GenerateFastApiDirectCall(masm(),
|
| + optimization,
|
| + argc,
|
| + &failure);
|
| + if (!success) {
|
| + return failure;
|
| + }
|
| } else {
|
| __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
| }
|
| @@ -2282,7 +2322,8 @@
|
| __ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
|
|
| CallInterceptorCompiler compiler(this, arguments(), r2);
|
| - compiler.Compile(masm(),
|
| + Failure *failure;
|
| + bool success = compiler.Compile(masm(),
|
| object,
|
| holder,
|
| name,
|
| @@ -2291,7 +2332,11 @@
|
| r3,
|
| r4,
|
| r0,
|
| - &miss);
|
| + &miss,
|
| + &failure);
|
| + if (!success) {
|
| + return false;
|
| + }
|
|
|
| // Move returned value, the function to call, to r1.
|
| __ mov(r1, r0);
|
|
|