Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2934893002: [builtins] Properly optimize Object.prototype.isPrototypeOf. (Closed)
Patch Set: Address feedback. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/js-operator.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 } 267 }
268 268
269 return NoChange(); 269 return NoChange();
270 } 270 }
271 271
272 Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance( 272 Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
273 Node* node) { 273 Node* node) {
274 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode()); 274 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
275 Node* constructor = NodeProperties::GetValueInput(node, 0); 275 Node* constructor = NodeProperties::GetValueInput(node, 0);
276 Node* object = NodeProperties::GetValueInput(node, 1); 276 Node* object = NodeProperties::GetValueInput(node, 1);
277 Node* context = NodeProperties::GetContextInput(node);
278 Node* frame_state = NodeProperties::GetFrameStateInput(node);
279 Node* effect = NodeProperties::GetEffectInput(node);
280 Node* control = NodeProperties::GetControlInput(node);
281 277
282 // Check if the {constructor} is known at compile time. 278 // Check if the {constructor} is known at compile time.
283 HeapObjectMatcher m(constructor); 279 HeapObjectMatcher m(constructor);
284 if (!m.HasValue()) return NoChange(); 280 if (!m.HasValue()) return NoChange();
285 281
286 // Check if the {constructor} is a JSBoundFunction. 282 // Check if the {constructor} is a JSBoundFunction.
287 if (m.Value()->IsJSBoundFunction()) { 283 if (m.Value()->IsJSBoundFunction()) {
288 // OrdinaryHasInstance on bound functions turns into a recursive 284 // OrdinaryHasInstance on bound functions turns into a recursive
289 // invocation of the instanceof operator again. 285 // invocation of the instanceof operator again.
290 // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2. 286 // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
(...skipping 13 matching lines...) Expand all
304 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 300 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
305 if (function->IsConstructor() && function->has_instance_prototype() && 301 if (function->IsConstructor() && function->has_instance_prototype() &&
306 function->prototype()->IsJSReceiver()) { 302 function->prototype()->IsJSReceiver()) {
307 // Ensure that the {function} has a valid initial map, so we can 303 // Ensure that the {function} has a valid initial map, so we can
308 // depend on that for the prototype constant-folding below. 304 // depend on that for the prototype constant-folding below.
309 JSFunction::EnsureHasInitialMap(function); 305 JSFunction::EnsureHasInitialMap(function);
310 306
311 // Install a code dependency on the {function}s initial map. 307 // Install a code dependency on the {function}s initial map.
312 Handle<Map> initial_map(function->initial_map(), isolate()); 308 Handle<Map> initial_map(function->initial_map(), isolate());
313 dependencies()->AssumeInitialMapCantChange(initial_map); 309 dependencies()->AssumeInitialMapCantChange(initial_map);
314 Handle<JSReceiver> function_prototype = 310 Node* prototype =
315 handle(JSReceiver::cast(initial_map->prototype()), isolate()); 311 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
316 312
317 // Check if we can constant-fold the prototype chain walk 313 // Lower the {node} to JSHasInPrototypeChain.
318 // for the given {object} and the {function_prototype}. 314 NodeProperties::ReplaceValueInput(node, object, 0);
319 InferHasInPrototypeChainResult result = 315 NodeProperties::ReplaceValueInput(node, prototype, 1);
320 InferHasInPrototypeChain(object, effect, function_prototype); 316 NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
321 if (result != kMayBeInPrototypeChain) {
322 Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
323 ReplaceWithValue(node, value, effect, control);
324 return Replace(value);
325 }
326
327 Node* prototype = jsgraph()->Constant(function_prototype);
328
329 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
330 Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
331 check0, control);
332
333 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
334 Node* etrue0 = effect;
335 Node* vtrue0 = jsgraph()->FalseConstant();
336
337 control = graph()->NewNode(common()->IfFalse(), branch0);
338
339 // Loop through the {object}s prototype chain looking for the {prototype}.
340 Node* loop = control =
341 graph()->NewNode(common()->Loop(2), control, control);
342 Node* eloop = effect =
343 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
344 Node* vloop = object =
345 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
346 object, object, loop);
347
348 // Load the {object} map and instance type.
349 Node* object_map = effect =
350 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
351 object, effect, control);
352 Node* object_instance_type = effect = graph()->NewNode(
353 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
354 object_map, effect, control);
355
356 // Check if the {object} is a special receiver, because for special
357 // receivers, i.e. proxies or API objects that need access checks,
358 // we have to use the %HasInPrototypeChain runtime function instead.
359 Node* check1 = graph()->NewNode(
360 simplified()->NumberLessThanOrEqual(), object_instance_type,
361 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
362 Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
363 check1, control);
364
365 control = graph()->NewNode(common()->IfFalse(), branch1);
366
367 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
368 Node* etrue1 = effect;
369 Node* vtrue1;
370
371 // Check if the {object} is not a receiver at all.
372 Node* check10 =
373 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
374 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
375 Node* branch10 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
376 check10, if_true1);
377
378 // A primitive value cannot match the {prototype} we're looking for.
379 if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
380 vtrue1 = jsgraph()->FalseConstant();
381
382 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
383 Node* efalse1 = etrue1;
384 Node* vfalse1;
385 {
386 // Slow path, need to call the %HasInPrototypeChain runtime function.
387 vfalse1 = efalse1 = if_false1 = graph()->NewNode(
388 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
389 prototype, context, frame_state, efalse1, if_false1);
390
391 // Replace any potential {IfException} uses of {node} to catch
392 // exceptions from this %HasInPrototypeChain runtime call instead.
393 Node* on_exception = nullptr;
394 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
395 NodeProperties::ReplaceControlInput(on_exception, vfalse1);
396 NodeProperties::ReplaceEffectInput(on_exception, efalse1);
397 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
398 Revisit(on_exception);
399 }
400 }
401
402 // Load the {object} prototype.
403 Node* object_prototype = effect = graph()->NewNode(
404 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
405 effect, control);
406
407 // Check if we reached the end of {object}s prototype chain.
408 Node* check2 =
409 graph()->NewNode(simplified()->ReferenceEqual(), object_prototype,
410 jsgraph()->NullConstant());
411 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
412
413 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
414 Node* etrue2 = effect;
415 Node* vtrue2 = jsgraph()->FalseConstant();
416
417 control = graph()->NewNode(common()->IfFalse(), branch2);
418
419 // Check if we reached the {prototype}.
420 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
421 object_prototype, prototype);
422 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
423
424 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
425 Node* etrue3 = effect;
426 Node* vtrue3 = jsgraph()->TrueConstant();
427
428 control = graph()->NewNode(common()->IfFalse(), branch3);
429
430 // Close the loop.
431 vloop->ReplaceInput(1, object_prototype);
432 eloop->ReplaceInput(1, effect);
433 loop->ReplaceInput(1, control);
434
435 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1,
436 if_true2, if_true3, if_false1);
437 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
438 etrue3, efalse1, control);
439
440 // Morph the {node} into an appropriate Phi.
441 ReplaceWithValue(node, node, effect, control);
442 node->ReplaceInput(0, vtrue0);
443 node->ReplaceInput(1, vtrue1);
444 node->ReplaceInput(2, vtrue2);
445 node->ReplaceInput(3, vtrue3);
446 node->ReplaceInput(4, vfalse1);
447 node->ReplaceInput(5, control);
448 node->TrimInputCount(6);
449 NodeProperties::ChangeOp(
450 node, common()->Phi(MachineRepresentation::kTagged, 5));
451 return Changed(node); 317 return Changed(node);
452 } 318 }
453 } 319 }
454 320
455 return NoChange(); 321 return NoChange();
456 } 322 }
457 323
458 Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) { 324 Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
459 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode()); 325 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
460 ContextAccess const& access = ContextAccessOf(node->op()); 326 ContextAccess const& access = ContextAccessOf(node->op());
(...skipping 1977 matching lines...) Expand 10 before | Expand all | Expand 10 after
2438 // Install code dependencies on the prototype maps. 2304 // Install code dependencies on the prototype maps.
2439 for (Handle<Map> map : receiver_maps) { 2305 for (Handle<Map> map : receiver_maps) {
2440 dependencies()->AssumePrototypeMapsStable(map, initial_object_prototype); 2306 dependencies()->AssumePrototypeMapsStable(map, initial_object_prototype);
2441 } 2307 }
2442 2308
2443 // Install code dependency on the array protector cell. 2309 // Install code dependency on the array protector cell.
2444 dependencies()->AssumePropertyCell(factory()->array_protector()); 2310 dependencies()->AssumePropertyCell(factory()->array_protector());
2445 return true; 2311 return true;
2446 } 2312 }
2447 2313
2448 JSNativeContextSpecialization::InferHasInPrototypeChainResult
2449 JSNativeContextSpecialization::InferHasInPrototypeChain(
2450 Node* receiver, Node* effect, Handle<JSReceiver> prototype) {
2451 ZoneHandleSet<Map> receiver_maps;
2452 NodeProperties::InferReceiverMapsResult result =
2453 NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
2454 if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
2455
2456 // Check if either all or none of the {receiver_maps} have the given
2457 // {prototype} in their prototype chain.
2458 bool all = true;
2459 bool none = true;
2460 for (size_t i = 0; i < receiver_maps.size(); ++i) {
2461 Handle<Map> receiver_map = receiver_maps[i];
2462 if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
2463 return kMayBeInPrototypeChain;
2464 }
2465 if (result == NodeProperties::kUnreliableReceiverMaps) {
2466 // In case of an unreliable {result} we need to ensure that all
2467 // {receiver_maps} are stable, because otherwise we cannot trust
2468 // the {receiver_maps} information, since arbitrary side-effects
2469 // may have happened.
2470 if (!receiver_map->is_stable()) {
2471 return kMayBeInPrototypeChain;
2472 }
2473 }
2474 for (PrototypeIterator j(receiver_map);; j.Advance()) {
2475 if (j.IsAtEnd()) {
2476 all = false;
2477 break;
2478 }
2479 Handle<JSReceiver> const current =
2480 PrototypeIterator::GetCurrent<JSReceiver>(j);
2481 if (current.is_identical_to(prototype)) {
2482 none = false;
2483 break;
2484 }
2485 if (!current->map()->is_stable() ||
2486 current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
2487 return kMayBeInPrototypeChain;
2488 }
2489 }
2490 }
2491 DCHECK_IMPLIES(all, !none);
2492 DCHECK_IMPLIES(none, !all);
2493
2494 if (all) return kIsInPrototypeChain;
2495 if (none) return kIsNotInPrototypeChain;
2496 return kMayBeInPrototypeChain;
2497 }
2498
2499 bool JSNativeContextSpecialization::ExtractReceiverMaps( 2314 bool JSNativeContextSpecialization::ExtractReceiverMaps(
2500 Node* receiver, Node* effect, FeedbackNexus const& nexus, 2315 Node* receiver, Node* effect, FeedbackNexus const& nexus,
2501 MapHandles* receiver_maps) { 2316 MapHandles* receiver_maps) {
2502 DCHECK_EQ(0, receiver_maps->size()); 2317 DCHECK_EQ(0, receiver_maps->size());
2503 // See if we can infer a concrete type for the {receiver}. 2318 // See if we can infer a concrete type for the {receiver}.
2504 if (InferReceiverMaps(receiver, effect, receiver_maps)) { 2319 if (InferReceiverMaps(receiver, effect, receiver_maps)) {
2505 // We can assume that the {receiver} still has the infered {receiver_maps}. 2320 // We can assume that the {receiver} still has the infered {receiver_maps}.
2506 return true; 2321 return true;
2507 } 2322 }
2508 // Try to extract some maps from the {nexus}. 2323 // Try to extract some maps from the {nexus}.
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
2611 return jsgraph()->javascript(); 2426 return jsgraph()->javascript();
2612 } 2427 }
2613 2428
2614 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 2429 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
2615 return jsgraph()->simplified(); 2430 return jsgraph()->simplified();
2616 } 2431 }
2617 2432
2618 } // namespace compiler 2433 } // namespace compiler
2619 } // namespace internal 2434 } // namespace internal
2620 } // namespace v8 2435 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/js-operator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698