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

Side by Side Diff: src/compiler/js-inlining.cc

Issue 2626783003: [turbofan] Enable inlining based on SharedFunctionInfo. (Closed)
Patch Set: Rebased. Created 3 years, 10 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-inlining.h ('k') | src/compiler/js-inlining-heuristic.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 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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-inlining.h" 5 #include "src/compiler/js-inlining.h"
6 6
7 #include "src/ast/ast.h" 7 #include "src/ast/ast.h"
8 #include "src/compilation-info.h" 8 #include "src/compilation-info.h"
9 #include "src/compiler.h" 9 #include "src/compiler.h"
10 #include "src/compiler/all-nodes.h" 10 #include "src/compiler/all-nodes.h"
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 340
341 bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) { 341 bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
342 DisallowHeapAllocation no_gc; 342 DisallowHeapAllocation no_gc;
343 Isolate* const isolate = shared_info->GetIsolate(); 343 Isolate* const isolate = shared_info->GetIsolate();
344 Code* const construct_stub = shared_info->construct_stub(); 344 Code* const construct_stub = shared_info->construct_stub();
345 return construct_stub == *isolate->builtins()->ConstructedNonConstructable(); 345 return construct_stub == *isolate->builtins()->ConstructedNonConstructable();
346 } 346 }
347 347
348 } // namespace 348 } // namespace
349 349
350 350 // Determines whether the call target of the given call {node} is statically
351 Reduction JSInliner::Reduce(Node* node) { 351 // known and can be used as an inlining candidate. The {SharedFunctionInfo} of
352 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); 352 // the call target is provided (the exact closure might be unknown).
353 bool JSInliner::DetermineCallTarget(
354 Node* node, Handle<SharedFunctionInfo>& shared_info_out) {
355 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
356 HeapObjectMatcher match(node->InputAt(0));
353 357
354 // This reducer can handle both normal function calls as well a constructor 358 // This reducer can handle both normal function calls as well a constructor
355 // calls whenever the target is a constant function object, as follows: 359 // calls whenever the target is a constant function object, as follows:
356 // - JSCall(target:constant, receiver, args...) 360 // - JSCall(target:constant, receiver, args...)
357 // - JSConstruct(target:constant, args..., new.target) 361 // - JSConstruct(target:constant, args..., new.target)
358 HeapObjectMatcher match(node->InputAt(0)); 362 if (match.HasValue() && match.Value()->IsJSFunction()) {
359 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); 363 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
360 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
361 364
362 return ReduceJSCall(node, function); 365 // Disallow cross native-context inlining for now. This means that all parts
366 // of the resulting code will operate on the same global object. This also
367 // prevents cross context leaks, where we could inline functions from a
368 // different context and hold on to that context (and closure) from the code
369 // object.
370 // TODO(turbofan): We might want to revisit this restriction later when we
371 // have a need for this, and we know how to model different native contexts
372 // in the same graph in a compositional way.
373 if (function->context()->native_context() !=
374 info_->context()->native_context()) {
375 return false;
376 }
377
378 shared_info_out = handle(function->shared());
379 return true;
380 }
381
382 // This reducer can also handle calls where the target is statically known to
383 // be the result of a closure instantiation operation, as follows:
384 // - JSCall(JSCreateClosure[shared](context), receiver, args...)
385 // - JSConstruct(JSCreateClosure[shared](context), args..., new.target)
386 if (match.IsJSCreateClosure()) {
387 CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
388
389 // Disallow inlining in case the instantiation site was never run and hence
390 // the vector cell does not contain a valid feedback vector for the call
391 // target.
392 // TODO(turbofan): We might consider to eagerly create the feedback vector
393 // in such a case (in {DetermineCallContext} below) eventually.
394 FeedbackVectorSlot slot = p.feedback().slot();
395 Handle<Cell> cell(Cell::cast(p.feedback().vector()->Get(slot)));
396 if (!cell->value()->IsTypeFeedbackVector()) return false;
397
398 shared_info_out = p.shared_info();
399 return true;
400 }
401
402 return false;
363 } 403 }
364 404
365 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { 405 // Determines statically known information about the call target (assuming that
406 // the call target is known according to {DetermineCallTarget} above). The
407 // following static information is provided:
408 // - context : The context (as SSA value) bound by the call target.
409 // - feedback_vector : The target is guaranteed to use this feedback vector.
410 void JSInliner::DetermineCallContext(
411 Node* node, Node*& context_out,
412 Handle<TypeFeedbackVector>& feedback_vector_out) {
366 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); 413 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
414 HeapObjectMatcher match(node->InputAt(0));
415
416 if (match.HasValue() && match.Value()->IsJSFunction()) {
417 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
418
419 // If the target function was never invoked, its literals array might not
420 // contain a feedback vector. We ensure at this point that it is created.
421 JSFunction::EnsureLiterals(function);
422
423 // The inlinee specializes to the context from the JSFunction object.
424 context_out = jsgraph()->Constant(handle(function->context()));
425 feedback_vector_out = handle(function->feedback_vector());
426 return;
427 }
428
429 if (match.IsJSCreateClosure()) {
430 CreateClosureParameters const& p = CreateClosureParametersOf(match.op());
431
432 // Load the feedback vector of the target by looking up its vector cell at
433 // the instantiation site (we only decide to inline if it's populated).
434 FeedbackVectorSlot slot = p.feedback().slot();
435 Handle<Cell> cell(Cell::cast(p.feedback().vector()->Get(slot)));
436 DCHECK(cell->value()->IsTypeFeedbackVector());
437
438 // The inlinee uses the locally provided context at instantiation.
439 context_out = NodeProperties::GetContextInput(match.node());
440 feedback_vector_out = handle(TypeFeedbackVector::cast(cell->value()));
441 return;
442 }
443
444 // Must succeed.
445 UNREACHABLE();
446 }
447
448 Reduction JSInliner::Reduce(Node* node) {
449 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
450 return ReduceJSCall(node);
451 }
452
453 Reduction JSInliner::ReduceJSCall(Node* node) {
454 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
455 Handle<SharedFunctionInfo> shared_info;
367 JSCallAccessor call(node); 456 JSCallAccessor call(node);
368 Handle<SharedFunctionInfo> shared_info(function->shared()); 457
458 // Determine the call target.
459 if (!DetermineCallTarget(node, shared_info)) return NoChange();
369 460
370 // Inlining is only supported in the bytecode pipeline. 461 // Inlining is only supported in the bytecode pipeline.
371 if (!info_->is_optimizing_from_bytecode()) { 462 if (!info_->is_optimizing_from_bytecode()) {
372 TRACE("Inlining %s into %s is not supported in the deprecated pipeline\n", 463 TRACE("Not inlining %s into %s due to use of the deprecated pipeline\n",
373 shared_info->DebugName()->ToCString().get(), 464 shared_info->DebugName()->ToCString().get(),
374 info_->shared_info()->DebugName()->ToCString().get()); 465 info_->shared_info()->DebugName()->ToCString().get());
375 return NoChange(); 466 return NoChange();
376 } 467 }
377 468
378 // Function must be inlineable. 469 // Function must be inlineable.
379 if (!shared_info->IsInlineable()) { 470 if (!shared_info->IsInlineable()) {
380 TRACE("Not inlining %s into %s because callee is not inlineable\n", 471 TRACE("Not inlining %s into %s because callee is not inlineable\n",
381 shared_info->DebugName()->ToCString().get(), 472 shared_info->DebugName()->ToCString().get(),
382 info_->shared_info()->DebugName()->ToCString().get()); 473 info_->shared_info()->DebugName()->ToCString().get());
(...skipping 20 matching lines...) Expand all
403 } 494 }
404 495
405 // Function contains break points. 496 // Function contains break points.
406 if (shared_info->HasDebugInfo()) { 497 if (shared_info->HasDebugInfo()) {
407 TRACE("Not inlining %s into %s because callee may contain break points\n", 498 TRACE("Not inlining %s into %s because callee may contain break points\n",
408 shared_info->DebugName()->ToCString().get(), 499 shared_info->DebugName()->ToCString().get(),
409 info_->shared_info()->DebugName()->ToCString().get()); 500 info_->shared_info()->DebugName()->ToCString().get());
410 return NoChange(); 501 return NoChange();
411 } 502 }
412 503
413 // Disallow cross native-context inlining for now. This means that all parts
414 // of the resulting code will operate on the same global object.
415 // This also prevents cross context leaks for asm.js code, where we could
416 // inline functions from a different context and hold on to that context (and
417 // closure) from the code object.
418 // TODO(turbofan): We might want to revisit this restriction later when we
419 // have a need for this, and we know how to model different native contexts
420 // in the same graph in a compositional way.
421 if (function->context()->native_context() !=
422 info_->context()->native_context()) {
423 TRACE("Not inlining %s into %s because of different native contexts\n",
424 shared_info->DebugName()->ToCString().get(),
425 info_->shared_info()->DebugName()->ToCString().get());
426 return NoChange();
427 }
428
429 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on 504 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
430 // not inlining recursive functions. We might want to relax that at some 505 // not inlining recursive functions. We might want to relax that at some
431 // point. 506 // point.
432 for (Node* frame_state = call.frame_state(); 507 for (Node* frame_state = call.frame_state();
433 frame_state->opcode() == IrOpcode::kFrameState; 508 frame_state->opcode() == IrOpcode::kFrameState;
434 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) { 509 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
435 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); 510 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
436 Handle<SharedFunctionInfo> frame_shared_info; 511 Handle<SharedFunctionInfo> frame_shared_info;
437 if (frame_info.shared_info().ToHandle(&frame_shared_info) && 512 if (frame_info.shared_info().ToHandle(&frame_shared_info) &&
438 *frame_shared_info == *shared_info) { 513 *frame_shared_info == *shared_info) {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 shared_info, source_positions_->GetSourcePosition(node)); 572 shared_info, source_positions_->GetSourcePosition(node));
498 573
499 // ---------------------------------------------------------------- 574 // ----------------------------------------------------------------
500 // After this point, we've made a decision to inline this function. 575 // After this point, we've made a decision to inline this function.
501 // We shall not bailout from inlining if we got here. 576 // We shall not bailout from inlining if we got here.
502 577
503 TRACE("Inlining %s into %s\n", 578 TRACE("Inlining %s into %s\n",
504 shared_info->DebugName()->ToCString().get(), 579 shared_info->DebugName()->ToCString().get(),
505 info_->shared_info()->DebugName()->ToCString().get()); 580 info_->shared_info()->DebugName()->ToCString().get());
506 581
507 // If function was lazily compiled, its literals array may not yet be set up. 582 // Determine the targets feedback vector and its context.
508 JSFunction::EnsureLiterals(function); 583 Node* context;
584 Handle<TypeFeedbackVector> feedback_vector;
585 DetermineCallContext(node, context, feedback_vector);
509 586
510 // Create the subgraph for the inlinee. 587 // Create the subgraph for the inlinee.
511 Node* start; 588 Node* start;
512 Node* end; 589 Node* end;
513 { 590 {
514 // Run the BytecodeGraphBuilder to create the subgraph. 591 // Run the BytecodeGraphBuilder to create the subgraph.
515 Graph::SubgraphScope scope(graph()); 592 Graph::SubgraphScope scope(graph());
516 BytecodeGraphBuilder graph_builder( 593 BytecodeGraphBuilder graph_builder(
517 &zone, shared_info, handle(function->feedback_vector()), 594 &zone, shared_info, feedback_vector, BailoutId::None(), jsgraph(),
518 BailoutId::None(), jsgraph(), call.frequency(), source_positions_, 595 call.frequency(), source_positions_, inlining_id);
519 inlining_id);
520 graph_builder.CreateGraph(false); 596 graph_builder.CreateGraph(false);
521 597
522 // Extract the inlinee start/end nodes. 598 // Extract the inlinee start/end nodes.
523 start = graph()->start(); 599 start = graph()->start();
524 end = graph()->end(); 600 end = graph()->end();
525 } 601 }
526 602
527 if (exception_target != nullptr) { 603 if (exception_target != nullptr) {
528 // Find all uncaught 'calls' in the inlinee. 604 // Find all uncaught 'calls' in the inlinee.
529 AllNodes inlined_nodes(local_zone_, end, graph()); 605 AllNodes inlined_nodes(local_zone_, end, graph());
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 node->RemoveInput(call.formal_arguments() + 1); // Drop new target. 662 node->RemoveInput(call.formal_arguments() + 1); // Drop new target.
587 node->InsertInput(graph()->zone(), 1, receiver); 663 node->InsertInput(graph()->zone(), 1, receiver);
588 664
589 // Insert a construct stub frame into the chain of frame states. This will 665 // Insert a construct stub frame into the chain of frame states. This will
590 // reconstruct the proper frame when deoptimizing within the constructor. 666 // reconstruct the proper frame when deoptimizing within the constructor.
591 frame_state = CreateArtificialFrameState( 667 frame_state = CreateArtificialFrameState(
592 node, frame_state, call.formal_arguments(), 668 node, frame_state, call.formal_arguments(),
593 FrameStateType::kConstructStub, info.shared_info()); 669 FrameStateType::kConstructStub, info.shared_info());
594 } 670 }
595 671
596 // The inlinee specializes to the context from the JSFunction object.
597 // TODO(turbofan): We might want to load the context from the JSFunction at
598 // runtime in case we only know the SharedFunctionInfo once we have dynamic
599 // type feedback in the compiler.
600 Node* context = jsgraph()->Constant(handle(function->context()));
601
602 // Insert a JSConvertReceiver node for sloppy callees. Note that the context 672 // Insert a JSConvertReceiver node for sloppy callees. Note that the context
603 // passed into this node has to be the callees context (loaded above). 673 // passed into this node has to be the callees context (loaded above).
604 if (node->opcode() == IrOpcode::kJSCall && 674 if (node->opcode() == IrOpcode::kJSCall &&
605 is_sloppy(shared_info->language_mode()) && !shared_info->native()) { 675 is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
606 Node* effect = NodeProperties::GetEffectInput(node); 676 Node* effect = NodeProperties::GetEffectInput(node);
607 if (NeedsConvertReceiver(call.receiver(), effect)) { 677 if (NeedsConvertReceiver(call.receiver(), effect)) {
608 const CallParameters& p = CallParametersOf(node->op()); 678 const CallParameters& p = CallParametersOf(node->op());
609 Node* convert = effect = 679 Node* convert = effect =
610 graph()->NewNode(javascript()->ConvertReceiver(p.convert_mode()), 680 graph()->NewNode(javascript()->ConvertReceiver(p.convert_mode()),
611 call.receiver(), context, effect, start); 681 call.receiver(), context, effect, start);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 722
653 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); } 723 CommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
654 724
655 SimplifiedOperatorBuilder* JSInliner::simplified() const { 725 SimplifiedOperatorBuilder* JSInliner::simplified() const {
656 return jsgraph()->simplified(); 726 return jsgraph()->simplified();
657 } 727 }
658 728
659 } // namespace compiler 729 } // namespace compiler
660 } // namespace internal 730 } // namespace internal
661 } // namespace v8 731 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-inlining.h ('k') | src/compiler/js-inlining-heuristic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698