Revision: 18946
Author: [email protected]
Date: Thu Jan 30 13:18:41 2014 UTC
Log: crankshaft support for api method calls
[email protected]
BUG=
Review URL: https://codereview.chromium.org/148333003
http://code.google.com/p/v8/source/detail?r=18946
Modified:
/branches/bleeding_edge/src/arm/code-stubs-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.cc
/branches/bleeding_edge/src/arm/macro-assembler-arm.h
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/isolate.h
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Jan 30 13:18:41
2014 UTC
@@ -453,6 +453,27 @@
descriptor->param_representations_ = representations;
descriptor->platform_specific_descriptor_ = &default_descriptor;
}
+ {
+ CallInterfaceDescriptor* descriptor =
+ isolate->call_descriptor(Isolate::ApiFunctionCall);
+ static Register registers[] = { r0, // callee
+ r4, // call_data
+ r2, // holder
+ r1, // api_function_address
+ cp, // context
+ };
+ static Representation representations[] = {
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Tagged(), // context
+ };
+ descriptor->register_param_count_ = 5;
+ descriptor->register_params_ = registers;
+ descriptor->param_representations_ = representations;
+ descriptor->platform_specific_descriptor_ = &default_descriptor;
+ }
}
@@ -5379,8 +5400,7 @@
// -- r0 : callee
// -- r4 : call_data
// -- r2 : holder
- // -- r3 : api_function_address
- // -- r1 : thunk_arg
+ // -- r1 : api_function_address
// -- cp : context
// --
// -- sp[0] : last argument
@@ -5392,8 +5412,7 @@
Register callee = r0;
Register call_data = r4;
Register holder = r2;
- Register api_function_address = r3;
- Register thunk_arg = r1;
+ Register api_function_address = r1;
Register context = cp;
int argc = ArgumentBits::decode(bit_field_);
@@ -5449,7 +5468,7 @@
FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
- ASSERT(!thunk_arg.is(r0) && !api_function_address.is(r0)
&& !scratch.is(r0));
+ ASSERT(!api_function_address.is(r0) && !scratch.is(r0));
// r0 = FunctionCallbackInfo&
// Arguments is after the return address.
__ add(r0, sp, Operand(1 * kPointerSize));
@@ -5480,7 +5499,6 @@
__ CallApiFunctionAndReturn(api_function_address,
thunk_ref,
- thunk_arg,
kStackUnwindSpace,
return_value_operand,
restore_context ?
@@ -5493,12 +5511,10 @@
// -- sp[0] : name
// -- sp[4 - kArgsLength*4] : PropertyCallbackArguments object
// -- ...
- // -- r3 : api_function_address
- // -- r2 : thunk_last_arg
+ // -- r2 : api_function_address
// -----------------------------------
- Register api_function_address = r3;
- Register thunk_last_arg = r2;
+ Register api_function_address = r2;
__ mov(r0, sp); // r0 = Handle<Name>
__ add(r1, r0, Operand(1 * kPointerSize)); // r1 = PCA
@@ -5522,7 +5538,6 @@
masm->isolate());
__ CallApiFunctionAndReturn(api_function_address,
thunk_ref,
- thunk_last_arg,
kStackUnwindSpace,
MemOperand(fp, 6 * kPointerSize),
NULL);
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jan 28
11:53:11 2014 UTC
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jan 30
13:18:41 2014 UTC
@@ -2300,7 +2300,6 @@
void MacroAssembler::CallApiFunctionAndReturn(
Register function_address,
ExternalReference thunk_ref,
- Register thunk_last_arg,
int stack_space,
MemOperand return_value_operand,
MemOperand* context_restore_operand) {
@@ -2314,8 +2313,7 @@
ExternalReference::handle_scope_level_address(isolate()),
next_address);
- ASSERT(function_address.is(r3));
- ASSERT(thunk_last_arg.is(r1) || thunk_last_arg.is(r2));
+ ASSERT(function_address.is(r1) || function_address.is(r2));
Label profiler_disabled;
Label end_profiler_check;
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jan 27
09:57:54 2014 UTC
+++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Thu Jan 30
13:18:41 2014 UTC
@@ -1136,7 +1136,6 @@
// the additional space allocated for the fast call).
void CallApiFunctionAndReturn(Register function_address,
ExternalReference thunk_ref,
- Register thunk_last_arg,
int stack_space,
MemOperand return_value_operand,
MemOperand* context_restore_operand);
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Tue Jan 14 09:57:05
2014 UTC
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jan 30 13:18:41
2014 UTC
@@ -845,6 +845,12 @@
addr_of_swi - OFFSET_OF(Redirection, swi_instruction_);
return reinterpret_cast<Redirection*>(addr_of_redirection);
}
+
+ static void* ReverseRedirection(int32_t reg) {
+ Redirection* redirection = FromSwiInstruction(
+ reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
+ return redirection->external_function();
+ }
private:
void* external_function_;
@@ -1689,12 +1695,12 @@
// This signature supports direct call in to API function native callback
// (refer to InvocationCallback in v8.h).
typedef void (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
-typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, int32_t
arg1);
+typedef void (*SimulatorRuntimeProfilingApiCall)(int32_t arg0, void* arg1);
// This signature supports direct call to accessor getter callback.
typedef void (*SimulatorRuntimeDirectGetterCall)(int32_t arg0, int32_t
arg1);
typedef void (*SimulatorRuntimeProfilingGetterCall)(
- int32_t arg0, int32_t arg1, int32_t arg2);
+ int32_t arg0, int32_t arg1, void* arg2);
// Software interrupt instructions are used by the simulator to call into
the
// C-based V8 runtime.
@@ -1833,7 +1839,7 @@
CHECK(stack_aligned);
SimulatorRuntimeProfilingApiCall target =
reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
- target(arg0, arg1);
+ target(arg0, Redirection::ReverseRedirection(arg1));
} else if (
redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
@@ -1862,7 +1868,7 @@
SimulatorRuntimeProfilingGetterCall target =
reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
external);
- target(arg0, arg1, arg2);
+ target(arg0, arg1, Redirection::ReverseRedirection(arg2));
} else {
// builtin call.
ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Jan 30 13:18:41
2014 UTC
@@ -788,8 +788,7 @@
Register callee = r0;
Register call_data = r4;
Register holder = r2;
- Register api_function_address = r3;
- Register thunk_arg = r1;
+ Register api_function_address = r1;
// Put holder in place.
__ Move(holder, holder_in);
@@ -822,53 +821,11 @@
type,
masm->isolate());
__ mov(api_function_address, Operand(ref));
- __ mov(thunk_arg, Operand(reinterpret_cast<int32_t>(function_address)));
// Jump to stub.
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
- const CallOptimization& optimization,
- int argc,
- Handle<Map> map_to_holder,
- CallOptimization::HolderLookup
holder_lookup) {
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1);
-
- // Move holder to a register
- Register holder_reg = r2;
- switch (holder_lookup) {
- case CallOptimization::kHolderIsReceiver:
- {
- ASSERT(map_to_holder.is_null());
- __ ldr(holder_reg, MemOperand(sp, argc * kPointerSize));
- }
- break;
- case CallOptimization::kHolderIsPrototypeOfMap:
- {
- Handle<JSObject>
holder(JSObject::cast(map_to_holder->prototype()));
- if (!masm->isolate()->heap()->InNewSpace(*holder)) {
- __ Move(holder_reg, holder);
- } else {
- __ Move(holder_reg, map_to_holder);
- __ ldr(holder_reg,
- FieldMemOperand(holder_reg, Map::kPrototypeOffset));
- }
- }
- break;
- case CallOptimization::kHolderNotFound:
- UNREACHABLE();
- }
- GenerateFastApiCallBody(masm,
- optimization,
- argc,
- holder_reg,
- false);
-}
// Generate call to api function.
@@ -975,36 +932,9 @@
name, miss_label);
}
- Handle<Map> lookup_map;
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- if (optimization.is_simple_api_call() &&
- !lookup->holder()->IsGlobalObject()) {
- lookup_map = optimization.LookupHolderOfExpectedType(
- object, object, interceptor_holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- lookup_map =
- optimization.LookupHolderOfExpectedType(
- object,
- interceptor_holder,
- Handle<JSObject>(lookup->holder()),
- &holder_lookup);
- }
- }
-
- // Invoke function.
- if (holder_lookup != CallOptimization::kHolderNotFound) {
- int argc = arguments_.immediate();
- GenerateFastApiCall(masm,
- optimization,
- argc,
- lookup_map,
- holder_lookup);
- } else {
- Handle<JSFunction> function = optimization.constant_function();
- __ Move(r0, receiver);
- stub_compiler_->GenerateJumpFunction(object, function);
- }
+ Handle<JSFunction> function = optimization.constant_function();
+ __ Move(r0, receiver);
+ stub_compiler_->GenerateJumpFunction(object, function);
// Invoke a regular function.
__ bind(®ular_invoke);
@@ -1324,15 +1254,13 @@
__ push(name());
// Abi for CallApiGetter
- Register getter_address_reg = r3;
- Register thunk_last_arg = r2;
+ Register getter_address_reg = r2;
Address getter_address = v8::ToCData<Address>(callback->getter());
ApiFunction fun(getter_address);
ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL;
ExternalReference ref = ExternalReference(&fun, type, isolate());
__ mov(getter_address_reg, Operand(ref));
- __ mov(thunk_last_arg,
Operand(reinterpret_cast<int32_t>(getter_address)));
CallApiGetterStub stub;
__ TailCallStub(&stub);
@@ -1500,57 +1428,6 @@
}
-Handle<Code> CallStubCompiler::CompileFastApiCall(
- const CallOptimization& optimization,
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> name) {
- Counters* counters = isolate()->counters();
-
- ASSERT(optimization.is_simple_api_call());
- // Bail out if object is a global object as we don't want to
- // repatch it to global receiver.
- if (object->IsGlobalObject()) return Handle<Code>::null();
- if (!cell.is_null()) return Handle<Code>::null();
- if (!object->IsJSObject()) return Handle<Code>::null();
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
- receiver, receiver, holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- return Handle<Code>::null();
- }
-
- Label miss;
- GenerateNameCheck(name, &miss);
-
- // Get the receiver from the stack.
- const int argc = arguments().immediate();
- __ ldr(r1, MemOperand(sp, argc * kPointerSize));
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(r1, &miss);
-
- __ IncrementCounter(counters->call_const(), 1, r0, r3);
-
- // Check that the maps haven't changed and find a Holder as a side
effect.
- CheckPrototypes(
- IC::CurrentTypeOf(object, isolate()),
- r1, holder, r0, r3, r4, name, &miss);
-
- GenerateFastApiCall(
- masm(), optimization, argc, lookup_map, holder_lookup);
-
- HandlerFrontendFooter(&miss);
-
- // Return the generated code.
- return GetCode(function);
-}
-
-
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
// Check that the object is a boolean.
@@ -1712,14 +1589,6 @@
Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(
- object, holder, cell, function, Handle<String>::cast(name),
- Code::NORMAL);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of
the
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Thu Jan 30 12:52:49 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Thu Jan 30 13:18:41 2014 UTC
@@ -7950,6 +7950,118 @@
}
return false;
}
+
+
+bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
+ HValue* receiver,
+ bool drop_extra) {
+ return TryInlineApiCall(
+ expr, receiver, Handle<Map>::null(), drop_extra, true);
+}
+
+
+bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr,
+ HValue* receiver,
+ Handle<Map>
receiver_map) {
+ return TryInlineApiCall(expr, receiver, receiver_map, false, false);
+}
+
+bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
+ HValue* receiver,
+ Handle<Map> receiver_map,
+ bool drop_extra,
+ bool is_function_call) {
+ if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) {
+ return false;
+ }
+ CallOptimization optimization(expr->target());
+ if (!optimization.is_simple_api_call()) return false;
+ Handle<Map> holder_map;
+ if (is_function_call) {
+ // Cannot embed a direct reference to the global proxy map
+ // as it maybe dropped on deserialization.
+ CHECK(!Serializer::enabled());
+ receiver_map = Handle<Map>(
+
expr->target()->context()->global_object()->global_receiver()->map());
+ }
+ CallOptimization::HolderLookup holder_lookup =
+ CallOptimization::kHolderNotFound;
+ Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
+ receiver_map, &holder_lookup);
+ if (holder_lookup == CallOptimization::kHolderNotFound) return false;
+
+ if (FLAG_trace_inlining) {
+ PrintF("Inlining api function ");
+ expr->target()->ShortPrint();
+ PrintF("\n");
+ }
+
+ // Need to ensure the chain between receiver and api_holder is intact
+ AddCheckMap(receiver, receiver_map);
+ if (holder_lookup == CallOptimization::kHolderFound) {
+ AddCheckPrototypeMaps(api_holder, receiver_map);
+ } else {
+ ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
+ }
+
+ // TODO(verwaest): remove.
+ if (!is_function_call) {
+ AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
+ }
+
+ HValue* holder = NULL;
+ switch (holder_lookup) {
+ case CallOptimization::kHolderFound:
+ holder = Add<HConstant>(api_holder);
+ break;
+ case CallOptimization::kHolderIsReceiver:
+ holder =
environment()->ExpressionStackAt(expr->arguments()->length());
+ break;
+ case CallOptimization::kHolderNotFound:
+ UNREACHABLE();
+ break;
+ }
+ Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
+ Handle<Object> call_data_obj(api_call_info->data(), isolate());
+ bool call_data_is_undefined = call_data_obj->IsUndefined();
+ HValue* call_data = Add<HConstant>(call_data_obj);
+ ApiFunction fun(v8::ToCData<Address>(api_call_info->callback()));
+ ExternalReference ref = ExternalReference(&fun,
+
ExternalReference::DIRECT_API_CALL,
+ isolate());
+ HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
+
+ HValue* op_vals[] = {
+ // callee
+ Add<HConstant>(expr->target()),
+ call_data,
+ holder,
+ api_function_address,
+ context()
+ };
+
+ const int argc = expr->arguments()->length();
+ // Includes receiver.
+ PushArgumentsFromEnvironment(argc + 1);
+
+ CallInterfaceDescriptor* descriptor =
+ isolate()->call_descriptor(Isolate::ApiFunctionCall);
+
+ CallApiFunctionStub stub(true, call_data_is_undefined, argc);
+ Handle<Code> code = stub.GetCode(isolate());
+ HConstant* code_value = Add<HConstant>(code);
+
+ ASSERT((sizeof(op_vals) / kPointerSize) ==
+ descriptor->environment_length());
+
+ HInstruction* call = New<HCallWithDescriptor>(
+ code_value, argc + 1, descriptor,
+ Vector<HValue*>(op_vals, descriptor->environment_length()));
+
+ if (drop_extra) Drop(1); // Drop function.
+ ast_context()->ReturnInstruction(call, expr->id());
+ return true;
+}
bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
@@ -8040,16 +8152,12 @@
Handle<JSFunction>
target) {
SharedFunctionInfo* shared = target->shared();
if (shared->is_classic_mode() && !shared->native()) {
- HValue* context = Add<HLoadNamedField>(
- function, static_cast<HValue*>(NULL),
- HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset));
- HValue* global_object = Add<HLoadNamedField>(
- context, static_cast<HValue*>(NULL),
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
- return Add<HLoadNamedField>(
- global_object, static_cast<HValue*>(NULL),
- HObjectAccess::ForJSObjectOffset(
- GlobalObject::kGlobalReceiverOffset));
+ // Cannot embed a direct reference to the global proxy
+ // as is it dropped on deserialization.
+ CHECK(!Serializer::enabled());
+ Handle<JSObject> global_receiver(
+ target->context()->global_object()->global_receiver());
+ return Add<HConstant>(global_receiver);
}
return graph()->GetConstantUndefined();
}
@@ -8122,12 +8230,9 @@
}
return;
}
+ if (TryInlineApiMethodCall(expr, receiver, map)) return;
- if (CallStubCompiler::HasCustomCallGenerator(expr->target()) ||
- expr->check_type() != RECEIVER_MAP_CHECK) {
- // When the target has a custom call IC generator, use the IC,
- // because it is likely to generate better code. Also use the IC
- // when a primitive receiver check is required.
+ if (expr->check_type() != RECEIVER_MAP_CHECK) {
call = NewCallNamed(name, argument_count);
PushArgumentsFromEnvironment(argument_count);
} else {
@@ -8193,28 +8298,15 @@
}
return;
}
+ if (TryInlineApiFunctionCall(expr, receiver, false)) return;
if (TryInlineCall(expr)) return;
if (expr->target().is_identical_to(current_info()->closure())) {
graph()->MarkRecursive();
}
- if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
- // We're about to install a contextual IC, which expects the
global
- // object as receiver rather than the global proxy.
- HValue* global_object = Add<HLoadNamedField>(
- context(), static_cast<HValue*>(NULL),
- HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX));
- const int receiver_index = argument_count - 1;
- environment()->SetExpressionStackAt(receiver_index,
global_object);
- // When the target has a custom call IC generator, use the IC,
- // because it is likely to generate better code.
- call = NewCallNamed(var->name(), argument_count);
- PushArgumentsFromEnvironment(argument_count);
- } else {
- call = BuildCallConstantFunction(expr->target(), argument_count);
- PushArgumentsFromEnvironment(argument_count);
- }
+ call = BuildCallConstantFunction(expr->target(), argument_count);
+ PushArgumentsFromEnvironment(argument_count);
} else {
HValue* receiver = Add<HLoadNamedField>(
context(), static_cast<HValue*>(NULL),
@@ -8247,6 +8339,7 @@
}
return;
}
+ if (TryInlineApiFunctionCall(expr, receiver, true)) return;
if (TryInlineCall(expr, true)) { // Drop function from environment.
return;
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Thu Jan 30 11:30:38 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.h Thu Jan 30 13:18:41 2014 UTC
@@ -2227,6 +2227,14 @@
Handle<Map> receiver_map,
CheckType check_type);
bool TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra);
+ bool TryInlineApiMethodCall(
+ Call* expr, HValue* receiver, Handle<Map> receiver_map);
+ bool TryInlineApiFunctionCall(Call* expr, HValue* receiver, bool
drop_extra);
+ bool TryInlineApiCall(Call* expr,
+ HValue* receiver,
+ Handle<Map> receiver_map,
+ bool drop_extra,
+ bool is_function_call);
// If --trace-inlining, print a line of the inlining trace. Inlining
// succeeded if the reason string is NULL and failed if there is a
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Jan 30 13:18:41
2014 UTC
@@ -446,6 +446,26 @@
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
+ {
+ CallInterfaceDescriptor* descriptor =
+ isolate->call_descriptor(Isolate::ApiFunctionCall);
+ static Register registers[] = { eax, // callee
+ ebx, // call_data
+ ecx, // holder
+ edx, // api_function_address
+ esi, // context
+ };
+ static Representation representations[] = {
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Tagged(), // context
+ };
+ descriptor->register_param_count_ = 5;
+ descriptor->register_params_ = registers;
+ descriptor->param_representations_ = representations;
+ }
}
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Jan 30 13:18:41
2014 UTC
@@ -460,46 +460,6 @@
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
- const CallOptimization& optimization,
- int argc,
- Handle<Map> map_to_holder,
- CallOptimization::HolderLookup
holder_lookup) {
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->call_const_fast_api(), 1);
-
- // Move holder to a register
- Register holder_reg = ecx;
- switch (holder_lookup) {
- case CallOptimization::kHolderIsReceiver:
- {
- ASSERT(map_to_holder.is_null());
- __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize));
- }
- break;
- case CallOptimization::kHolderIsPrototypeOfMap:
- {
- Handle<JSObject>
holder(JSObject::cast(map_to_holder->prototype()));
- if (!masm->isolate()->heap()->InNewSpace(*holder)) {
- __ mov(holder_reg, holder);
- } else {
- __ mov(holder_reg, map_to_holder);
- __ mov(holder_reg, FieldOperand(holder_reg,
Map::kPrototypeOffset));
- }
- }
- break;
- case CallOptimization::kHolderNotFound:
- UNREACHABLE();
- }
- GenerateFastApiCallBody(masm,
- optimization,
- argc,
- holder_reg,
- false);
-}
// Generate call to api function.
@@ -612,35 +572,8 @@
name, miss_label);
}
- Handle<Map> lookup_map;
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- if (optimization.is_simple_api_call() &&
- !lookup->holder()->IsGlobalObject()) {
- lookup_map = optimization.LookupHolderOfExpectedType(
- object, object, interceptor_holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- lookup_map =
- optimization.LookupHolderOfExpectedType(
- object,
- interceptor_holder,
- Handle<JSObject>(lookup->holder()),
- &holder_lookup);
- }
- }
-
- // Invoke function.
- if (holder_lookup != CallOptimization::kHolderNotFound) {
- int argc = arguments_.immediate();
- GenerateFastApiCall(masm,
- optimization,
- argc,
- lookup_map,
- holder_lookup);
- } else {
- Handle<JSFunction> fun = optimization.constant_function();
- stub_compiler_->GenerateJumpFunction(object, fun);
- }
+ Handle<JSFunction> fun = optimization.constant_function();
+ stub_compiler_->GenerateJumpFunction(object, fun);
// Invoke a regular function.
__ bind(®ular_invoke);
@@ -1509,54 +1442,6 @@
return GetCode(Code::FAST, name);
}
-
-Handle<Code> CallStubCompiler::CompileFastApiCall(
- const CallOptimization& optimization,
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> name) {
- ASSERT(optimization.is_simple_api_call());
- // Bail out if object is a global object as we don't want to
- // repatch it to global receiver.
- if (object->IsGlobalObject()) return Handle<Code>::null();
- if (!cell.is_null()) return Handle<Code>::null();
- if (!object->IsJSObject()) return Handle<Code>::null();
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
- receiver, receiver, holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- return Handle<Code>::null();
- }
-
- Label miss;
- GenerateNameCheck(name, &miss);
-
- // Get the receiver from the stack.
- const int argc = arguments().immediate();
- __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(edx, &miss);
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->call_const(), 1);
-
- // Check that the maps haven't changed and find a Holder as a side
effect.
- CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
- ebx, eax, edi, name, &miss);
-
- GenerateFastApiCall(masm(), optimization, argc, lookup_map,
holder_lookup);
-
- HandlerFrontendFooter(&miss);
-
- // Return the generated code.
- return GetCode(function);
-}
-
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
@@ -1712,14 +1597,6 @@
Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(
- object, holder, cell, function, Handle<String>::cast(name),
- Code::NORMAL);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of
the
=======================================
--- /branches/bleeding_edge/src/isolate.h Thu Jan 30 10:33:53 2014 UTC
+++ /branches/bleeding_edge/src/isolate.h Thu Jan 30 13:18:41 2014 UTC
@@ -1082,6 +1082,7 @@
NamedCall,
CallHandler,
ArgumentAdaptorCall,
+ ApiFunctionCall,
NUMBER_OF_CALL_DESCRIPTORS
};
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Fri Jan 24 11:47:53 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc Thu Jan 30 13:18:41 2014 UTC
@@ -1288,15 +1288,6 @@
Handle<Name> name,
CheckType check,
Handle<JSFunction> function) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(object, holder,
- Handle<Cell>::null(),
- function,
Handle<String>::cast(name),
- Code::FAST);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
Label miss;
HandlerFrontendHeader(object, holder, name, check, &miss);
GenerateJumpFunction(object, function);
@@ -1875,31 +1866,6 @@
kind_(kind),
cache_holder_(cache_holder) {
}
-
-
-bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function)
{
- CallOptimization optimization(function);
- return optimization.is_simple_api_call();
-}
-
-
-Handle<Code> CallStubCompiler::CompileCustomCall(
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> fname,
- Code::StubType type) {
- ASSERT(HasCustomCallGenerator(function));
- CallOptimization optimization(function);
- ASSERT(optimization.is_simple_api_call());
- return CompileFastApiCall(optimization,
- object,
- holder,
- cell,
- function,
- fname);
-}
Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
@@ -1937,44 +1903,32 @@
}
-Handle<Map> CallOptimization::LookupHolderOfExpectedType(
- Handle<JSObject> receiver,
- Handle<JSObject> object,
- Handle<JSObject> holder,
+Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
+ Handle<Map> object_map,
HolderLookup* holder_lookup) const {
ASSERT(is_simple_api_call());
ASSERT_EQ(kHolderNotFound, *holder_lookup);
- *holder_lookup = kHolderIsReceiver;
- Handle<Map> map_to_holder;
- if (expected_receiver_type_.is_null()) {
- // no expected type, load from receiver.
- return map_to_holder;
+ if (!object_map->IsJSObjectMap()) {
+ *holder_lookup = kHolderNotFound;
+ return Handle<JSObject>::null();
}
- // walk down the prototype chain to the object
- while (!receiver.is_identical_to(object)) {
- *holder_lookup = kHolderIsPrototypeOfMap;
- map_to_holder = Handle<Map>(receiver->map());
- receiver =
Handle<JSObject>(JSObject::cast(map_to_holder->prototype()));
+ if (expected_receiver_type_.is_null() ||
+ expected_receiver_type_->IsTemplateFor(*object_map)) {
+ *holder_lookup = kHolderIsReceiver;
+ return Handle<JSObject>::null();
}
- // start looking for the holder
- while (!object.is_identical_to(holder)) {
- Handle<Map> object_map(object->map());
+ while (true) {
+ if (!object_map->prototype()->IsJSObject()) break;
+ Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
+ if (!prototype->map()->is_hidden_prototype()) break;
+ object_map = handle(prototype->map());
if (expected_receiver_type_->IsTemplateFor(*object_map)) {
- return map_to_holder;
+ *holder_lookup = kHolderFound;
+ return prototype;
}
- if (!object_map->is_hidden_prototype()) {
- *holder_lookup = kHolderNotFound;
- return Handle<Map>::null();
- }
- *holder_lookup = kHolderIsPrototypeOfMap;
- map_to_holder = object_map;
- object = Handle<JSObject>(JSObject::cast(object_map->prototype()));
- }
- if (expected_receiver_type_->IsTemplateFor(holder->map())) {
- return map_to_holder;
}
*holder_lookup = kHolderNotFound;
- return Handle<Map>::null();
+ return Handle<JSObject>::null();
}
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Fri Jan 24 11:47:53 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Thu Jan 30 13:18:41 2014 UTC
@@ -921,26 +921,7 @@
Handle<JSFunction> function,
Handle<Name> name);
- static bool HasCustomCallGenerator(Handle<JSFunction> function);
-
private:
- // Compiles a custom call constant/global IC. For constant calls cell is
- // NULL. Returns an empty handle if there is no custom call code for the
- // given function.
- Handle<Code> CompileCustomCall(Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> name,
- Code::StubType type);
-
- Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> name);
-
Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
Handle<Code> GetCode(Handle<JSFunction> function);
@@ -998,16 +979,11 @@
enum HolderLookup {
kHolderNotFound,
kHolderIsReceiver,
- kHolderIsPrototypeOfMap
+ kHolderFound
};
- // Returns a map whose prototype has the expected type in the
- // prototype chain between the two arguments
- // null will be returned if the first argument has that property
- // lookup will be set accordingly
- Handle<Map> LookupHolderOfExpectedType(Handle<JSObject> receiver,
- Handle<JSObject> object,
- Handle<JSObject> holder,
- HolderLookup* holder_lookup)
const;
+ Handle<JSObject> LookupHolderOfExpectedType(
+ Handle<Map> receiver_map,
+ HolderLookup* holder_lookup) const;
bool IsCompatibleReceiver(Object* receiver) {
ASSERT(is_simple_api_call());
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Thu Jan 30 13:18:41
2014 UTC
@@ -443,6 +443,26 @@
descriptor->register_params_ = registers;
descriptor->param_representations_ = representations;
}
+ {
+ CallInterfaceDescriptor* descriptor =
+ isolate->call_descriptor(Isolate::ApiFunctionCall);
+ static Register registers[] = { rax, // callee
+ rbx, // call_data
+ rcx, // holder
+ rdx, // api_function_address
+ rsi, // context
+ };
+ static Representation representations[] = {
+ Representation::Tagged(), // callee
+ Representation::Tagged(), // call_data
+ Representation::Tagged(), // holder
+ Representation::External(), // api_function_address
+ Representation::Tagged(), // context
+ };
+ descriptor->register_param_count_ = 5;
+ descriptor->register_params_ = registers;
+ descriptor->param_representations_ = representations;
+ }
}
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Jan 30 12:15:51
2014 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Jan 30 13:18:41
2014 UTC
@@ -435,47 +435,6 @@
CallApiFunctionStub stub(restore_context, call_data_undefined, argc);
__ TailCallStub(&stub);
}
-
-
-// Generates call to API function.
-static void GenerateFastApiCall(MacroAssembler* masm,
- const CallOptimization& optimization,
- int argc,
- Handle<Map> map_to_holder,
- CallOptimization::HolderLookup
holder_lookup) {
- Counters* counters = masm->isolate()->counters();
- __ IncrementCounter(counters->call_const_fast_api(), 1);
-
- // Move holder to a register
- Register holder_reg = rax;
- switch (holder_lookup) {
- case CallOptimization::kHolderIsReceiver:
- {
- ASSERT(map_to_holder.is_null());
- StackArgumentsAccessor args(rsp, argc);
- __ movp(holder_reg, args.GetReceiverOperand());
- }
- break;
- case CallOptimization::kHolderIsPrototypeOfMap:
- {
- Handle<JSObject>
holder(JSObject::cast(map_to_holder->prototype()));
- if (!masm->isolate()->heap()->InNewSpace(*holder)) {
- __ Move(holder_reg, holder);
- } else {
- __ Move(holder_reg, map_to_holder);
- __ movp(holder_reg, FieldOperand(holder_reg,
Map::kPrototypeOffset));
- }
- }
- break;
- case CallOptimization::kHolderNotFound:
- UNREACHABLE();
- }
- GenerateFastApiCallBody(masm,
- optimization,
- argc,
- holder_reg,
- false);
-}
// Generate call to api function.
@@ -585,35 +544,8 @@
name, miss_label);
}
- Handle<Map> lookup_map;
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- if (optimization.is_simple_api_call() &&
- !lookup->holder()->IsGlobalObject()) {
- lookup_map = optimization.LookupHolderOfExpectedType(
- object, object, interceptor_holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- lookup_map =
- optimization.LookupHolderOfExpectedType(
- object,
- interceptor_holder,
- Handle<JSObject>(lookup->holder()),
- &holder_lookup);
- }
- }
-
- // Invoke function.
- if (holder_lookup != CallOptimization::kHolderNotFound) {
- int argc = arguments_.immediate();
- GenerateFastApiCall(masm,
- optimization,
- argc,
- lookup_map,
- holder_lookup);
- } else {
- Handle<JSFunction> fun = optimization.constant_function();
- stub_compiler_->GenerateJumpFunction(object, fun);
- }
+ Handle<JSFunction> fun = optimization.constant_function();
+ stub_compiler_->GenerateJumpFunction(object, fun);
// Invoke a regular function.
__ bind(®ular_invoke);
@@ -1399,54 +1331,6 @@
// Return the generated code.
return GetCode(Code::FAST, name);
}
-
-
-Handle<Code> CallStubCompiler::CompileFastApiCall(
- const CallOptimization& optimization,
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Cell> cell,
- Handle<JSFunction> function,
- Handle<String> name) {
- ASSERT(optimization.is_simple_api_call());
- // Bail out if object is a global object as we don't want to
- // repatch it to global receiver.
- if (object->IsGlobalObject()) return Handle<Code>::null();
- if (!cell.is_null()) return Handle<Code>::null();
- if (!object->IsJSObject()) return Handle<Code>::null();
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- CallOptimization::HolderLookup holder_lookup =
- CallOptimization::kHolderNotFound;
- Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType(
- receiver, receiver, holder, &holder_lookup);
- if (holder_lookup == CallOptimization::kHolderNotFound) {
- return Handle<Code>::null();
- }
-
- Label miss;
- GenerateNameCheck(name, &miss);
-
- const int argc = arguments().immediate();
- StackArgumentsAccessor args(rsp, argc);
- __ movp(rdx, args.GetReceiverOperand());
-
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(rdx, &miss);
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->call_const(), 1);
-
- // Check that the maps haven't changed and find a Holder as a side
effect.
- CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
- rbx, rax, rdi, name, &miss);
-
- GenerateFastApiCall(masm(), optimization, argc, lookup_map,
holder_lookup);
-
- HandlerFrontendFooter(&miss);
-
- // Return the generated code.
- return GetCode(function);
-}
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
@@ -1599,14 +1483,6 @@
Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(
- object, holder, cell, function, Handle<String>::cast(name),
- Code::NORMAL);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of
the
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Thu Jan 30 10:53:20
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-api.cc Thu Jan 30 13:18:41
2014 UTC
@@ -21845,3 +21845,132 @@
" new C1();"
"}");
}
+
+
+class ApiCallOptimizationChecker {
+ private:
+ static Local<Object> data;
+ static Local<Object> receiver;
+ static Local<Object> holder;
+ static Local<Object> callee;
+ static int count;
+
+ static void OptimizationCallback(
+ const v8::FunctionCallbackInfo<v8::Value>& info) {
+ CHECK(callee == info.Callee());
+ CHECK(data == info.Data());
+ CHECK(receiver == info.This());
+ CHECK(holder == info.Holder());
+ count++;
+ }
+
+ public:
+ void Run(bool use_signature, bool global) {
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ // Build a template for signature checks.
+ Local<v8::ObjectTemplate> signature_template;
+ Local<v8::Signature> signature;
+ {
+ Local<v8::FunctionTemplate> parent_template =
+ FunctionTemplate::New(isolate);
+ parent_template->SetHiddenPrototype(true);
+ Local<v8::FunctionTemplate> function_template
+ = FunctionTemplate::New(isolate);
+ function_template->Inherit(parent_template);
+ if (use_signature) {
+ signature = v8::Signature::New(isolate, parent_template);
+ }
+ signature_template = function_template->InstanceTemplate();
+ }
+ // Global object must pass checks.
+ Local<v8::Context> context =
+ v8::Context::New(isolate, NULL, signature_template);
+ v8::Context::Scope context_scope(context);
+ // Install regular object that can pass signature checks.
+ Local<Object> function_receiver = signature_template->NewInstance();
+ context->Global()->Set(v8_str("function_receiver"),
function_receiver);
+ // Get the holder objects.
+ Local<Object> inner_global =
+ Local<Object>::Cast(context->Global()->GetPrototype());
+ Local<Object> function_holder =
+ Local<Object>::Cast(function_receiver->GetPrototype());
+ // Install function on hidden prototype object.
+ data = Object::New(isolate);
+ Local<FunctionTemplate> function_template = FunctionTemplate::New(
+ isolate, OptimizationCallback, data, signature);
+ Local<Function> function = function_template->GetFunction();
+ Local<Object>::Cast(
+ inner_global->GetPrototype())->Set(v8_str("global_f"), function);
+ function_holder->Set(v8_str("f"), function);
+ // Initialize expected values.
+ callee = function;
+ count = 0;
+ if (global) {
+ receiver = context->Global();
+ holder = inner_global;
+ } else {
+ holder = function_receiver;
+ // If not using a signature, add something else to the prototype
chain
+ // to test the case that holder != receiver
+ if (!use_signature) {
+ receiver = Local<Object>::Cast(CompileRun(
+ "var receiver_subclass = {};\n"
+ "receiver_subclass.__proto__ = function_receiver;\n"
+ "receiver_subclass"));
+ } else {
+ receiver = Local<Object>::Cast(CompileRun(
+ "var receiver_subclass = function_receiver;\n"
+ "receiver_subclass"));
+ }
+ }
+ // With no signature, the holder is not set.
+ if (!use_signature) holder = receiver;
+ // build wrap_function
+ int key = (use_signature ? 1 : 0) + 2 * (global ? 1 : 0);
+ i::ScopedVector<char> wrap_function(100);
+ if (global) {
+ i::OS::SNPrintF(
+ wrap_function,
+ "function wrap_%d() { var f = global_f; return f(); }\n",
+ key);
+ } else {
+ i::OS::SNPrintF(
+ wrap_function,
+ "function wrap_%d() { return receiver_subclass.f(); }\n",
+ key);
+ }
+ // build source string
+ i::ScopedVector<char> source(500);
+ i::OS::SNPrintF(
+ source,
+ "%s\n" // wrap_function
+ "function wrap2() { wrap_%d(); }\n"
+ "wrap2();\n"
+ "wrap2();\n"
+ "%%OptimizeFunctionOnNextCall(wrap_%d);\n"
+ "wrap2();\n",
+ wrap_function.start(), key, key);
+ v8::TryCatch try_catch;
+ CompileRun(source.start());
+ ASSERT(!try_catch.HasCaught());
+ CHECK_EQ(3, count);
+ }
+};
+
+
+Local<Object> ApiCallOptimizationChecker::data;
+Local<Object> ApiCallOptimizationChecker::receiver;
+Local<Object> ApiCallOptimizationChecker::holder;
+Local<Object> ApiCallOptimizationChecker::callee;
+int ApiCallOptimizationChecker::count = 0;
+
+
+TEST(TestFunctionCallOptimization) {
+ i::FLAG_allow_natives_syntax = true;
+ ApiCallOptimizationChecker checker;
+ checker.Run(true, true);
+ checker.Run(false, true);
+ checker.Run(true, false);
+ checker.Run(false, false);
+}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.