| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 4b4a158d4f5de65fbce4f8fa9781c2d4d757bf7b..8caeab7659ae2afa237329b83f780468de6acb75 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -5361,7 +5361,8 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible(
|
| if (info->has_holder()) return false;
|
|
|
| if (lookup_.IsPropertyCallbacks()) {
|
| - return accessor_.is_identical_to(info->accessor_);
|
| + return accessor_.is_identical_to(info->accessor_) &&
|
| + api_holder_.is_identical_to(info->api_holder_);
|
| }
|
|
|
| if (lookup_.IsConstant()) {
|
| @@ -5407,9 +5408,20 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
|
| : Handle<AccessorPair>::cast(callback)->setter();
|
| if (!raw_accessor->IsJSFunction()) return false;
|
| Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor));
|
| - CallOptimization call_optimization(accessor);
|
| - // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
|
| - if (call_optimization.is_simple_api_call()) return false;
|
| + if (accessor->shared()->IsApiFunction()) {
|
| + CallOptimization call_optimization(accessor);
|
| + if (!call_optimization.is_simple_api_call()) return false;
|
| + CallOptimization::HolderLookup holder_lookup;
|
| + api_holder_ = call_optimization.LookupHolderOfExpectedType(
|
| + map, &holder_lookup);
|
| + switch (holder_lookup) {
|
| + case CallOptimization::kHolderNotFound:
|
| + return false;
|
| + case CallOptimization::kHolderIsReceiver:
|
| + case CallOptimization::kHolderFound:
|
| + break;
|
| + }
|
| + }
|
| accessor_ = accessor;
|
| } else if (lookup_.IsConstant()) {
|
| constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
|
| @@ -5572,7 +5584,7 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
|
| return New<HCallFunction>(function, argument_count, WRAP_AND_CALL);
|
| } else if (FLAG_inline_accessors && can_inline_accessor) {
|
| bool success = info->IsLoad()
|
| - ? TryInlineGetter(info->accessor(), ast_id, return_id)
|
| + ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id)
|
| : TryInlineSetter(info->accessor(), ast_id, return_id, value);
|
| if (success) return NULL;
|
| }
|
| @@ -7394,8 +7406,10 @@ bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr,
|
|
|
|
|
| bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
|
| + Handle<Map> receiver_map,
|
| BailoutId ast_id,
|
| BailoutId return_id) {
|
| + if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true;
|
| return TryInline(getter,
|
| 0,
|
| NULL,
|
| @@ -7678,54 +7692,102 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
|
|
| bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr,
|
| HValue* receiver) {
|
| - return TryInlineApiCall(
|
| - expr, receiver, Handle<Map>::null(), true);
|
| + Handle<JSFunction> function = expr->target();
|
| + int argc = expr->arguments()->length();
|
| + SmallMapList receiver_maps;
|
| + return TryInlineApiCall(function,
|
| + receiver,
|
| + &receiver_maps,
|
| + argc,
|
| + expr->id(),
|
| + kCallApiFunction);
|
| }
|
|
|
|
|
| -bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr,
|
| - HValue* receiver,
|
| - Handle<Map> receiver_map) {
|
| - return TryInlineApiCall(expr, receiver, receiver_map, false);
|
| -}
|
| -
|
| -bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| - HValue* receiver,
|
| - Handle<Map> receiver_map,
|
| - bool is_function_call) {
|
| - if (!expr->IsMonomorphic()) return false;
|
| - CallOptimization optimization(expr->target());
|
| +bool HOptimizedGraphBuilder::TryInlineApiMethodCall(
|
| + Call* expr,
|
| + HValue* receiver,
|
| + SmallMapList* receiver_maps) {
|
| + Handle<JSFunction> function = expr->target();
|
| + int argc = expr->arguments()->length();
|
| + return TryInlineApiCall(function,
|
| + receiver,
|
| + receiver_maps,
|
| + argc,
|
| + expr->id(),
|
| + kCallApiMethod);
|
| +}
|
| +
|
| +
|
| +bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function,
|
| + Handle<Map> receiver_map,
|
| + BailoutId ast_id) {
|
| + SmallMapList receiver_maps(1, zone());
|
| + receiver_maps.Add(receiver_map, zone());
|
| + return TryInlineApiCall(function,
|
| + NULL, // Receiver is on expression stack.
|
| + &receiver_maps,
|
| + 0,
|
| + ast_id,
|
| + kCallApiGetter);
|
| +}
|
| +
|
| +
|
| +bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
|
| + HValue* receiver,
|
| + SmallMapList* receiver_maps,
|
| + int argc,
|
| + BailoutId ast_id,
|
| + ApiCallType call_type) {
|
| + CallOptimization optimization(function);
|
| if (!optimization.is_simple_api_call()) return false;
|
| Handle<Map> holder_map;
|
| - if (is_function_call) {
|
| + if (call_type == kCallApiFunction) {
|
| // 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());
|
| + ASSERT_EQ(0, receiver_maps->length());
|
| + receiver_maps->Add(handle(
|
| + function->context()->global_object()->global_receiver()->map()),
|
| + zone());
|
| }
|
| CallOptimization::HolderLookup holder_lookup =
|
| CallOptimization::kHolderNotFound;
|
| Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType(
|
| - receiver_map, &holder_lookup);
|
| + receiver_maps->first(), &holder_lookup);
|
| if (holder_lookup == CallOptimization::kHolderNotFound) return false;
|
|
|
| if (FLAG_trace_inlining) {
|
| PrintF("Inlining api function ");
|
| - expr->target()->ShortPrint();
|
| + function->ShortPrint();
|
| PrintF("\n");
|
| }
|
|
|
| - const int argc = expr->arguments()->length();
|
| - // Includes receiver.
|
| - PushArgumentsFromEnvironment(argc + 1);
|
| -
|
| - // 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);
|
| + bool drop_extra = false;
|
| + switch (call_type) {
|
| + case kCallApiFunction:
|
| + case kCallApiMethod:
|
| + // Need to check that none of the receiver maps could have changed.
|
| + Add<HCheckMaps>(receiver, receiver_maps);
|
| + // Need to ensure the chain between receiver and api_holder is intact.
|
| + if (holder_lookup == CallOptimization::kHolderFound) {
|
| + AddCheckPrototypeMaps(api_holder, receiver_maps->first());
|
| + } else {
|
| + ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver);
|
| + }
|
| + // Includes receiver.
|
| + PushArgumentsFromEnvironment(argc + 1);
|
| + // Drop function after call.
|
| + drop_extra = true;
|
| + break;
|
| + case kCallApiGetter:
|
| + // Receiver and prototype chain cannot have changed.
|
| + ASSERT_EQ(0, argc);
|
| + ASSERT_EQ(NULL, receiver);
|
| + // Receiver is on expression stack.
|
| + receiver = Pop();
|
| + Add<HPushArgument>(receiver);
|
| + break;
|
| }
|
|
|
| HValue* holder = NULL;
|
| @@ -7751,8 +7813,7 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| HValue* api_function_address = Add<HConstant>(ExternalReference(ref));
|
|
|
| HValue* op_vals[] = {
|
| - // callee
|
| - Add<HConstant>(expr->target()),
|
| + Add<HConstant>(function),
|
| call_data,
|
| holder,
|
| api_function_address,
|
| @@ -7773,8 +7834,8 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr,
|
| code_value, argc + 1, descriptor,
|
| Vector<HValue*>(op_vals, descriptor->environment_length()));
|
|
|
| - Drop(1); // Drop function.
|
| - ast_context()->ReturnInstruction(call, expr->id());
|
| + if (drop_extra) Drop(1); // Drop function.
|
| + ast_context()->ReturnInstruction(call, ast_id);
|
| return true;
|
| }
|
|
|
| @@ -7923,7 +7984,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| }
|
| return;
|
| }
|
| - if (TryInlineApiMethodCall(expr, receiver, map)) return;
|
| + if (TryInlineApiMethodCall(expr, receiver, types)) return;
|
|
|
| // Wrap the receiver if necessary.
|
| if (NeedsWrappingFor(ToType(types->first()), known_function)) {
|
|
|