Skip to content

Commit 08377af

Browse files
bmeurerCommit bot
authored andcommitted
[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 nodejs/node#9634. This patch should be easily back-mergable to Node.js v7. BUG=v8:5640 [email protected],[email protected] Review-Url: https://codereview.chromium.org/2504263004 Cr-Commit-Position: refs/heads/master@{#41059}
1 parent b8c2035 commit 08377af

3 files changed

Lines changed: 33 additions & 18 deletions

File tree

src/bootstrapper.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
12571257
JSObject::kHeaderSize, MaybeHandle<JSObject>(),
12581258
Builtins::kFunctionPrototypeHasInstance,
12591259
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY));
1260+
native_context()->set_function_has_instance(*has_instance);
12601261

12611262
// Set the expected parameters for @@hasInstance to 1; required by builtin.
12621263
has_instance->shared()->set_internal_formal_parameter_count(1);

src/contexts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ enum ContextLookupFlags {
8888
V(MAP_GET_METHOD_INDEX, JSFunction, map_get) \
8989
V(MAP_HAS_METHOD_INDEX, JSFunction, map_has) \
9090
V(MAP_SET_METHOD_INDEX, JSFunction, map_set) \
91+
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
9192
V(OBJECT_VALUE_OF, JSFunction, object_value_of) \
9293
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
9394
V(PROMISE_CATCH_INDEX, JSFunction, promise_catch) \

src/crankshaft/hydrogen.cc

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11207,24 +11207,37 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
1120711207
HConstant::cast(right)->handle(isolate())->IsJSFunction()) {
1120811208
Handle<JSFunction> function =
1120911209
Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate()));
11210-
// Make sure the prototype of {function} is the %FunctionPrototype%, and
11211-
// it already has a meaningful initial map (i.e. we constructed at least
11212-
// one instance using the constructor {function}).
11213-
// We can only use the fast case if @@hasInstance was not used so far.
11214-
if (function->has_initial_map() &&
11215-
function->map()->prototype() ==
11216-
function->native_context()->closure() &&
11217-
!function->map()->has_non_instance_prototype() &&
11218-
isolate()->IsHasInstanceLookupChainIntact()) {
11219-
Handle<Map> initial_map(function->initial_map(), isolate());
11220-
top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
11221-
top_info()->dependencies()->AssumePropertyCell(
11222-
isolate()->factory()->has_instance_protector());
11223-
HInstruction* prototype =
11224-
Add<HConstant>(handle(initial_map->prototype(), isolate()));
11225-
HHasInPrototypeChainAndBranch* result =
11226-
New<HHasInPrototypeChainAndBranch>(left, prototype);
11227-
return ast_context()->ReturnControl(result, expr->id());
11210+
// Make sure that the {function} already has a meaningful initial map
11211+
// (i.e. we constructed at least one instance using the constructor
11212+
// {function}).
11213+
if (function->has_initial_map()) {
11214+
// Lookup @@hasInstance on the {function}.
11215+
Handle<Map> function_map(function->map(), isolate());
11216+
PropertyAccessInfo has_instance(
11217+
this, LOAD, function_map,
11218+
isolate()->factory()->has_instance_symbol());
11219+
// Check if we are using the Function.prototype[@@hasInstance].
11220+
if (has_instance.CanAccessMonomorphic() &&
11221+
has_instance.IsDataConstant() &&
11222+
has_instance.constant().is_identical_to(
11223+
isolate()->function_has_instance())) {
11224+
// Add appropriate receiver map check and prototype chain
11225+
// checks to guard the @@hasInstance lookup chain.
11226+
AddCheckMap(right, function_map);
11227+
if (has_instance.has_holder()) {
11228+
Handle<JSObject> prototype(
11229+
JSObject::cast(has_instance.map()->prototype()), isolate());
11230+
BuildCheckPrototypeMaps(prototype, has_instance.holder());
11231+
}
11232+
// Perform the prototype chain walk.
11233+
Handle<Map> initial_map(function->initial_map(), isolate());
11234+
top_info()->dependencies()->AssumeInitialMapCantChange(initial_map);
11235+
HInstruction* prototype =
11236+
Add<HConstant>(handle(initial_map->prototype(), isolate()));
11237+
HHasInPrototypeChainAndBranch* result =
11238+
New<HHasInPrototypeChainAndBranch>(left, prototype);
11239+
return ast_context()->ReturnControl(result, expr->id());
11240+
}
1122811241
}
1122911242
}
1123011243

0 commit comments

Comments
 (0)