Commit 08377af9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[crankshaft] No need to rely on the @@hasInstance protector.

In Crankshaft we can actually do an abstract interpretation of the
@@hasInstance lookup when optimizing instanceof and then use the
normal machinery to protect the result instead of relying on the
global @@hasInstance protector cell for optimizations.

This recovers the 100x performance drop in Node.js v7 reported in
https://github.com/nodejs/node/issues/9634. This patch should be
easily back-mergable to Node.js v7.

BUG=v8:5640
R=yangguo@chromium.org,franzih@chromium.org

Review-Url: https://codereview.chromium.org/2504263004
Cr-Commit-Position: refs/heads/master@{#41059}
parent b8c2035f
...@@ -1257,6 +1257,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1257,6 +1257,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
JSObject::kHeaderSize, MaybeHandle<JSObject>(), JSObject::kHeaderSize, MaybeHandle<JSObject>(),
Builtins::kFunctionPrototypeHasInstance, Builtins::kFunctionPrototypeHasInstance,
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY)); static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY));
native_context()->set_function_has_instance(*has_instance);
// Set the expected parameters for @@hasInstance to 1; required by builtin. // Set the expected parameters for @@hasInstance to 1; required by builtin.
has_instance->shared()->set_internal_formal_parameter_count(1); has_instance->shared()->set_internal_formal_parameter_count(1);
......
...@@ -88,6 +88,7 @@ enum ContextLookupFlags { ...@@ -88,6 +88,7 @@ enum ContextLookupFlags {
V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \ V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \ V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \ V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \ V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
V(OBJECT_TO_STRING, JSFunction, object_to_string) \ V(OBJECT_TO_STRING, JSFunction, object_to_string) \
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \ V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \
......
...@@ -11207,24 +11207,37 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -11207,24 +11207,37 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HConstant::cast(right)->handle(isolate())->IsJSFunction()) { HConstant::cast(right)->handle(isolate())->IsJSFunction()) {
Handle<JSFunction> function = Handle<JSFunction> function =
Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate())); Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate()));
// Make sure the prototype of {function} is the %FunctionPrototype%, and // Make sure that the {function} already has a meaningful initial map
// it already has a meaningful initial map (i.e. we constructed at least // (i.e. we constructed at least one instance using the constructor
// one instance using the constructor {function}). // {function}).
// We can only use the fast case if @@hasInstance was not used so far. if (function->has_initial_map()) {
if (function->has_initial_map() && // Lookup @@hasInstance on the {function}.
function->map()->prototype() == Handle<Map> function_map(function->map(), isolate());
function->native_context()->closure() && PropertyAccessInfo has_instance(
!function->map()->has_non_instance_prototype() && this, LOAD, function_map,
isolate()->IsHasInstanceLookupChainIntact()) { isolate()->factory()->has_instance_symbol());
Handle<Map> initial_map(function->initial_map(), isolate()); // Check if we are using the Function.prototype[@@hasInstance].
top_info()->dependencies()->AssumeInitialMapCantChange(initial_map); if (has_instance.CanAccessMonomorphic() &&
top_info()->dependencies()->AssumePropertyCell( has_instance.IsDataConstant() &&
isolate()->factory()->has_instance_protector()); has_instance.constant().is_identical_to(
HInstruction* prototype = isolate()->function_has_instance())) {
Add<HConstant>(handle(initial_map->prototype(), isolate())); // Add appropriate receiver map check and prototype chain
HHasInPrototypeChainAndBranch* result = // checks to guard the @@hasInstance lookup chain.
New<HHasInPrototypeChainAndBranch>(left, prototype); AddCheckMap(right, function_map);
return ast_context()->ReturnControl(result, expr->id()); if (has_instance.has_holder()) {
Handle<JSObject> prototype(
JSObject::cast(has_instance.map()->prototype()), isolate());
BuildCheckPrototypeMaps(prototype, has_instance.holder());
}
// Perform the prototype chain walk.
Handle<Map> initial_map(function->initial_map(), isolate());
top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
HInstruction* prototype =
Add<HConstant>(handle(initial_map->prototype(), isolate()));
HHasInPrototypeChainAndBranch* result =
New<HHasInPrototypeChainAndBranch>(left, prototype);
return ast_context()->ReturnControl(result, expr->id());
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment