diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 87fa87df0c..fe963a24a7 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -5957,11 +5957,10 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) { void DirectCEntryStub::GenerateCall(MacroAssembler* masm, - ApiFunction *function) { + ExternalReference function) { __ mov(lr, Operand(reinterpret_cast(GetCode().location()), RelocInfo::CODE_TARGET)); - __ mov(r2, - Operand(ExternalReference(function, ExternalReference::DIRECT_CALL))); + __ mov(r2, Operand(function)); // Push return address (accessible to GC through exit frame pc). __ str(pc, MemOperand(sp, 0)); __ Jump(r2); // Call the api function. diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h index 475fbd70e8..0e707f41c8 100644 --- a/src/arm/code-stubs-arm.h +++ b/src/arm/code-stubs-arm.h @@ -592,7 +592,7 @@ class DirectCEntryStub: public CodeStub { public: DirectCEntryStub() {} void Generate(MacroAssembler* masm); - void GenerateCall(MacroAssembler* masm, ApiFunction *function); + void GenerateCall(MacroAssembler* masm, ExternalReference function); void GenerateCall(MacroAssembler* masm, Register target); private: diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 65c92f9e13..e0f2916449 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1618,7 +1618,7 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( - ApiFunction* function, int stack_space) { + ExternalReference function, int stack_space) { ExternalReference next_address = ExternalReference::handle_scope_next_address(); const int kNextOffset = 0; diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 83c59a6f65..3e13c783db 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -690,7 +690,7 @@ class MacroAssembler: public Assembler { // 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, + MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function, int stack_space); // Jump to a runtime routine. diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 8104747f14..20d51c6af0 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -1531,7 +1531,11 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, // This signature supports direct call in to API function native callback // (refer to InvocationCallback in v8.h). -typedef v8::Handle (*SimulatorRuntimeApiCall)(int32_t arg0); +typedef v8::Handle (*SimulatorRuntimeDirectApiCall)(int32_t arg0); + +// This signature supports direct call to accessor getter callback. +typedef v8::Handle (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, + int32_t arg1); // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. @@ -1572,14 +1576,12 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { CHECK(stack_aligned); double result = target(arg0, arg1, arg2, arg3); SetFpResult(result); - } else if (redirection->type() == ExternalReference::DIRECT_CALL) { - SimulatorRuntimeApiCall target = - reinterpret_cast(external); + } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) { + SimulatorRuntimeDirectApiCall target = + reinterpret_cast(external); if (::v8::internal::FLAG_trace_sim || !stack_aligned) { - PrintF( - "Call to host function at %p args %08x", - FUNCTION_ADDR(target), - arg0); + 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)); } @@ -1591,6 +1593,23 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintF("Returned %p\n", reinterpret_cast(*result)); } set_register(r0, (int32_t) *result); + } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) { + SimulatorRuntimeDirectGetterCall target = + reinterpret_cast(external); + if (::v8::internal::FLAG_trace_sim || !stack_aligned) { + PrintF("Call to host function at %p args %08x %08x", + FUNCTION_ADDR(target), arg0, arg1); + if (!stack_aligned) { + PrintF(" with unaligned stack %08x\n", get_register(sp)); + } + PrintF("\n"); + } + CHECK(stack_aligned); + v8::Handle result = target(arg0, arg1); + if (::v8::internal::FLAG_trace_sim) { + PrintF("Returned %p\n", reinterpret_cast(*result)); + } + set_register(r0, (int32_t) *result); } else { // builtin call. ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index e623ea1914..e2501125a0 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -655,12 +655,10 @@ static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm, // 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(); + const int kStackUnwindSpace = argc + kFastApiCallArguments + 1; + ExternalReference ref = + ExternalReference(&fun, ExternalReference::DIRECT_API_CALL); + return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); } class CallInterceptorCompiler BASE_EMBEDDED { @@ -1245,18 +1243,38 @@ MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, CheckPrototypes(object, receiver, holder, scratch1, scratch2, scratch3, name, miss); - // Push the arguments on the JS stack of the caller. - __ push(receiver); // Receiver. - __ mov(scratch3, Operand(Handle(callback))); // callback data - __ ldr(ip, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); - __ Push(reg, ip, scratch3, name_reg); + // Build AccessorInfo::args_ list on the stack and push property name below + // the exit frame to make GC aware of them and store pointers to them. + __ push(receiver); + __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_ + Handle callback_handle(callback); + if (Heap::InNewSpace(callback_handle->data())) { + __ Move(scratch3, callback_handle); + __ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); + } else { + __ Move(scratch3, Handle(callback_handle->data())); + } + __ Push(reg, scratch3, name_reg); + __ mov(r0, sp); // r0 = Handle - // Do tail-call to the runtime system. - ExternalReference load_callback_property = - ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); - __ TailCallExternalReference(load_callback_property, 5, 1); + Address getter_address = v8::ToCData
(callback->getter()); + ApiFunction fun(getter_address); - return Heap::undefined_value(); // Success. + const int kApiStackSpace = 1; + __ EnterExitFrame(false, kApiStackSpace); + // Create AccessorInfo instance on the stack above the exit frame with + // scratch2 (internal::Object **args_) as the data. + __ str(scratch2, MemOperand(sp, 1 * kPointerSize)); + __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& + + // 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. + const int kStackUnwindSpace = 4; + ExternalReference ref = + ExternalReference(&fun, ExternalReference::DIRECT_GETTER_CALL); + return masm()->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); } diff --git a/src/assembler.h b/src/assembler.h index abf34f2512..9e6aa087aa 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -481,21 +481,22 @@ class Debug_Address; class ExternalReference BASE_EMBEDDED { 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 f(v8::Arguments&) - // enum Type { + // Builtin call. + // MaybeObject* f(v8::internal::Arguments). BUILTIN_CALL, // default + + // Builtin call that returns floating point. + // double f(double, double). FP_RETURN_CALL, - DIRECT_CALL + + // Direct call to API function callback. + // Handle f(v8::Arguments&) + DIRECT_API_CALL, + + // Direct call to accessor getter callback. + // Handle f(Local property, AccessorInfo& info) + DIRECT_GETTER_CALL }; typedef void* ExternalReferenceRedirector(void* original, Type type); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 0da3f1cdc7..b3c52f1f1f 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -7627,10 +7627,11 @@ static void GenerateSomeGarbage() { "garbage = undefined;"); } + v8::Handle DirectApiCallback(const v8::Arguments& args) { static int count = 0; if (count++ % 3 == 0) { - v8::V8::LowMemoryNotification(); // This should move the stub + i::Heap::CollectAllGarbage(true); // This should move the stub GenerateSomeGarbage(); // This should ensure the old stub memory is flushed } return v8::Handle(); @@ -7682,6 +7683,54 @@ THREADED_TEST(CallICFastApi_DirectCall_Throw) { } +v8::Handle DirectGetterCallback(Local name, + const v8::AccessorInfo& info) { + if (++p_getter_count % 3 == 0) { + i::Heap::CollectAllGarbage(true); + GenerateSomeGarbage(); + } + return v8::Handle(); +} + + +THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { + v8::HandleScope scope; + LocalContext context; + v8::Handle obj = v8::ObjectTemplate::New(); + obj->SetAccessor(v8_str("p1"), DirectGetterCallback); + context->Global()->Set(v8_str("o1"), obj->NewInstance()); + p_getter_count = 0; + CompileRun( + "function f() {" + " for (var i = 0; i < 30; i++) o1.p1;" + "}" + "f();"); + CHECK_EQ(30, p_getter_count); +} + + +v8::Handle ThrowingDirectGetterCallback( + Local name, const v8::AccessorInfo& info) { + return v8::ThrowException(v8_str("g")); +} + + +THREADED_TEST(LoadICFastApi_DirectCall_Throw) { + v8::HandleScope scope; + LocalContext context; + v8::Handle obj = v8::ObjectTemplate::New(); + obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); + context->Global()->Set(v8_str("o1"), obj->NewInstance()); + v8::Handle result = CompileRun( + "var result = '';" + "for (var i = 0; i < 5; i++) {" + " try { o1.p1; } catch (e) { result += e; }" + "}" + "result;"); + CHECK_EQ(v8_str("ggggg"), result); +} + + THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) { int interceptor_call_count = 0; v8::HandleScope scope;