| Index: src/arm/stub-cache-arm.cc
|
| diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
|
| index 1e99e606942b715942406a8307980e6470555815..2f29ecd13f7456ec32c4a85c96263fae2679ea2a 100644
|
| --- a/src/arm/stub-cache-arm.cc
|
| +++ b/src/arm/stub-cache-arm.cc
|
| @@ -575,72 +575,94 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
|
| __ CallStub(&stub);
|
| }
|
|
|
| +static const int kFastApiCallArguments = 3;
|
|
|
| // Reserves space for the extra arguments to FastHandleApiCall in the
|
| // caller's frame.
|
| //
|
| -// These arguments are set by CheckPrototypes and GenerateFastApiCall.
|
| +// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall.
|
| 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 MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm,
|
| + const CallOptimization& optimization,
|
| + 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.
|
| 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));
|
| }
|
| + // Store js function and 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));
|
| -
|
| - // Set the number of arguments.
|
| - __ mov(r0, Operand(argc + 4));
|
| + // r2 points to call data as expected by Arguments
|
| + // (refer to layout above).
|
| + __ add(r2, sp, Operand(2 * kPointerSize));
|
|
|
| - // 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);
|
| + Object* callback = optimization.api_call_info()->callback();
|
| + Address api_function_address = v8::ToCData<Address>(callback);
|
| + ApiFunction fun(api_function_address);
|
| +
|
| + const int kApiStackSpace = 4;
|
| + __ EnterExitFrame(false, kApiStackSpace);
|
| +
|
| + // r0 = v8::Arguments&
|
| + // Arguments is after the return address.
|
| + __ 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 {
|
| public:
|
| CallInterceptorCompiler(StubCompiler* stub_compiler,
|
| @@ -650,16 +672,16 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
| arguments_(arguments),
|
| name_(name) {}
|
|
|
| - void Compile(MacroAssembler* masm,
|
| - JSObject* object,
|
| - JSObject* holder,
|
| - String* name,
|
| - LookupResult* lookup,
|
| - Register receiver,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - Label* miss) {
|
| + MaybeObject* Compile(MacroAssembler* masm,
|
| + JSObject* object,
|
| + JSObject* holder,
|
| + String* name,
|
| + LookupResult* lookup,
|
| + Register receiver,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Register scratch3,
|
| + Label* miss) {
|
| ASSERT(holder->HasNamedInterceptor());
|
| ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
|
|
| @@ -669,17 +691,17 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
| CallOptimization optimization(lookup);
|
|
|
| if (optimization.is_constant_call()) {
|
| - CompileCacheable(masm,
|
| - object,
|
| - receiver,
|
| - scratch1,
|
| - scratch2,
|
| - scratch3,
|
| - holder,
|
| - lookup,
|
| - name,
|
| - optimization,
|
| - miss);
|
| + return CompileCacheable(masm,
|
| + object,
|
| + receiver,
|
| + scratch1,
|
| + scratch2,
|
| + scratch3,
|
| + holder,
|
| + lookup,
|
| + name,
|
| + optimization,
|
| + miss);
|
| } else {
|
| CompileRegular(masm,
|
| object,
|
| @@ -690,21 +712,22 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
| name,
|
| holder,
|
| miss);
|
| + return Heap::undefined_value();
|
| }
|
| }
|
|
|
| private:
|
| - void CompileCacheable(MacroAssembler* masm,
|
| - JSObject* object,
|
| - Register receiver,
|
| - Register scratch1,
|
| - Register scratch2,
|
| - Register scratch3,
|
| - JSObject* interceptor_holder,
|
| - LookupResult* lookup,
|
| - String* name,
|
| - const CallOptimization& optimization,
|
| - Label* miss_label) {
|
| + MaybeObject* CompileCacheable(MacroAssembler* masm,
|
| + JSObject* object,
|
| + Register receiver,
|
| + Register scratch1,
|
| + Register scratch2,
|
| + Register scratch3,
|
| + JSObject* interceptor_holder,
|
| + LookupResult* lookup,
|
| + String* name,
|
| + const CallOptimization& optimization,
|
| + Label* miss_label) {
|
| ASSERT(optimization.is_constant_call());
|
| ASSERT(!lookup->holder()->IsGlobalObject());
|
|
|
| @@ -768,7 +791,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|
|
| // Invoke function.
|
| if (can_do_fast_api_call) {
|
| - GenerateFastApiCall(masm, optimization, arguments_.immediate());
|
| + MaybeObject* result = GenerateFastApiDirectCall(masm,
|
| + optimization,
|
| + arguments_.immediate());
|
| + if (result->IsFailure()) return result;
|
| } else {
|
| __ InvokeFunction(optimization.constant_function(), arguments_,
|
| JUMP_FUNCTION);
|
| @@ -786,6 +812,8 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
| if (can_do_fast_api_call) {
|
| FreeSpaceForFastApiCall(masm);
|
| }
|
| +
|
| + return Heap::undefined_value();
|
| }
|
|
|
| void CompileRegular(MacroAssembler* masm,
|
| @@ -2368,7 +2396,8 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
|
| }
|
|
|
| if (depth != kInvalidProtoDepth) {
|
| - GenerateFastApiCall(masm(), optimization, argc);
|
| + MaybeObject* result = GenerateFastApiDirectCall(masm(), optimization, argc);
|
| + if (result->IsFailure()) return result;
|
| } else {
|
| __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
|
| }
|
| @@ -2412,16 +2441,19 @@ MaybeObject* CallStubCompiler::CompileCallInterceptor(JSObject* object,
|
| __ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
|
|
| CallInterceptorCompiler compiler(this, arguments(), r2);
|
| - compiler.Compile(masm(),
|
| - object,
|
| - holder,
|
| - name,
|
| - &lookup,
|
| - r1,
|
| - r3,
|
| - r4,
|
| - r0,
|
| - &miss);
|
| + MaybeObject* result = compiler.Compile(masm(),
|
| + object,
|
| + holder,
|
| + name,
|
| + &lookup,
|
| + r1,
|
| + r3,
|
| + r4,
|
| + r0,
|
| + &miss);
|
| + if (result->IsFailure()) {
|
| + return result;
|
| + }
|
|
|
| // Move returned value, the function to call, to r1.
|
| __ mov(r1, r0);
|
|
|