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

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

Issue 1714803002: [turbofan] Reduce JSInliner dependencies on JSFunction. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 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 | « no previous file | no next file » | 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/ast/ast-numbering.h" 8 #include "src/ast/ast-numbering.h"
9 #include "src/ast/scopes.h" 9 #include "src/ast/scopes.h"
10 #include "src/compiler.h" 10 #include "src/compiler.h"
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 op_param, static_cast<int>(params.size()), &params.front()); 261 op_param, static_cast<int>(params.size()), &params.front());
262 return jsgraph_->graph()->NewNode(op, params_node, node0, node0, 262 return jsgraph_->graph()->NewNode(op, params_node, node0, node0,
263 jsgraph_->UndefinedConstant(), 263 jsgraph_->UndefinedConstant(),
264 node->InputAt(0), outer_frame_state); 264 node->InputAt(0), outer_frame_state);
265 } 265 }
266 266
267 267
268 namespace { 268 namespace {
269 269
270 // TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo? 270 // TODO(mstarzinger,verwaest): Move this predicate onto SharedFunctionInfo?
271 bool NeedsImplicitReceiver(Handle<JSFunction> function, Isolate* isolate) { 271 bool NeedsImplicitReceiver(Handle<SharedFunctionInfo> shared_info) {
272 Code* construct_stub = function->shared()->construct_stub(); 272 DisallowHeapAllocation no_gc;
273 return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub() && 273 Isolate* const isolate = shared_info->GetIsolate();
274 construct_stub != *isolate->builtins()->ConstructedNonConstructable(); 274 Code* const construct_stub = shared_info->construct_stub();
275 return construct_stub != *isolate->builtins()->JSBuiltinsConstructStub();
276 }
277
278 bool IsNonConstructible(Handle<SharedFunctionInfo> shared_info) {
279 DisallowHeapAllocation no_gc;
280 Isolate* const isolate = shared_info->GetIsolate();
281 Code* const construct_stub = shared_info->construct_stub();
282 return construct_stub == *isolate->builtins()->ConstructedNonConstructable();
275 } 283 }
276 284
277 } // namespace 285 } // namespace
278 286
279 287
280 Reduction JSInliner::Reduce(Node* node) { 288 Reduction JSInliner::Reduce(Node* node) {
281 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange(); 289 if (!IrOpcode::IsInlineeOpcode(node->opcode())) return NoChange();
282 290
283 // This reducer can handle both normal function calls as well a constructor 291 // This reducer can handle both normal function calls as well a constructor
284 // calls whenever the target is a constant function object, as follows: 292 // calls whenever the target is a constant function object, as follows:
285 // - JSCallFunction(target:constant, receiver, args...) 293 // - JSCallFunction(target:constant, receiver, args...)
286 // - JSCallConstruct(target:constant, args..., new.target) 294 // - JSCallConstruct(target:constant, args..., new.target)
287 HeapObjectMatcher match(node->InputAt(0)); 295 HeapObjectMatcher match(node->InputAt(0));
288 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange(); 296 if (!match.HasValue() || !match.Value()->IsJSFunction()) return NoChange();
289 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value()); 297 Handle<JSFunction> function = Handle<JSFunction>::cast(match.Value());
290 298
291 return ReduceJSCall(node, function); 299 return ReduceJSCall(node, function);
292 } 300 }
293 301
294 302
295 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) { 303 Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
296 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode())); 304 DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
297 JSCallAccessor call(node); 305 JSCallAccessor call(node);
306 Handle<SharedFunctionInfo> shared_info(function->shared());
298 307
299 // Function must be inlineable. 308 // Function must be inlineable.
300 if (!function->shared()->IsInlineable()) { 309 if (!shared_info->IsInlineable()) {
301 TRACE("Not inlining %s into %s because callee is not inlineable\n", 310 TRACE("Not inlining %s into %s because callee is not inlineable\n",
302 function->shared()->DebugName()->ToCString().get(), 311 shared_info->DebugName()->ToCString().get(),
303 info_->shared_info()->DebugName()->ToCString().get()); 312 info_->shared_info()->DebugName()->ToCString().get());
304 return NoChange(); 313 return NoChange();
305 } 314 }
306 315
307 // Constructor must be constructable. 316 // Constructor must be constructable.
308 if (node->opcode() == IrOpcode::kJSCallConstruct && 317 if (node->opcode() == IrOpcode::kJSCallConstruct &&
309 !function->IsConstructor()) { 318 IsNonConstructible(shared_info)) {
310 TRACE("Not inlining %s into %s because constructor is not constructable.\n", 319 TRACE("Not inlining %s into %s because constructor is not constructable.\n",
311 function->shared()->DebugName()->ToCString().get(), 320 shared_info->DebugName()->ToCString().get(),
312 info_->shared_info()->DebugName()->ToCString().get()); 321 info_->shared_info()->DebugName()->ToCString().get());
313 return NoChange(); 322 return NoChange();
314 } 323 }
315 324
316 // Class constructors are callable, but [[Call]] will raise an exception. 325 // Class constructors are callable, but [[Call]] will raise an exception.
317 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 326 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
318 if (node->opcode() == IrOpcode::kJSCallFunction && 327 if (node->opcode() == IrOpcode::kJSCallFunction &&
319 IsClassConstructor(function->shared()->kind())) { 328 IsClassConstructor(shared_info->kind())) {
320 TRACE("Not inlining %s into %s because callee is a class constructor.\n", 329 TRACE("Not inlining %s into %s because callee is a class constructor.\n",
321 function->shared()->DebugName()->ToCString().get(), 330 shared_info->DebugName()->ToCString().get(),
322 info_->shared_info()->DebugName()->ToCString().get()); 331 info_->shared_info()->DebugName()->ToCString().get());
323 return NoChange(); 332 return NoChange();
324 } 333 }
325 334
326 // Function contains break points. 335 // Function contains break points.
327 if (function->shared()->HasDebugInfo()) { 336 if (shared_info->HasDebugInfo()) {
328 TRACE("Not inlining %s into %s because callee may contain break points\n", 337 TRACE("Not inlining %s into %s because callee may contain break points\n",
329 function->shared()->DebugName()->ToCString().get(), 338 shared_info->DebugName()->ToCString().get(),
330 info_->shared_info()->DebugName()->ToCString().get()); 339 info_->shared_info()->DebugName()->ToCString().get());
331 return NoChange(); 340 return NoChange();
332 } 341 }
333 342
334 // Disallow cross native-context inlining for now. This means that all parts 343 // Disallow cross native-context inlining for now. This means that all parts
335 // of the resulting code will operate on the same global object. 344 // of the resulting code will operate on the same global object.
336 // This also prevents cross context leaks for asm.js code, where we could 345 // This also prevents cross context leaks for asm.js code, where we could
337 // inline functions from a different context and hold on to that context (and 346 // inline functions from a different context and hold on to that context (and
338 // closure) from the code object. 347 // closure) from the code object.
339 // TODO(turbofan): We might want to revisit this restriction later when we 348 // TODO(turbofan): We might want to revisit this restriction later when we
340 // have a need for this, and we know how to model different native contexts 349 // have a need for this, and we know how to model different native contexts
341 // in the same graph in a compositional way. 350 // in the same graph in a compositional way.
342 if (function->context()->native_context() != 351 if (function->context()->native_context() !=
343 info_->context()->native_context()) { 352 info_->context()->native_context()) {
344 TRACE("Not inlining %s into %s because of different native contexts\n", 353 TRACE("Not inlining %s into %s because of different native contexts\n",
345 function->shared()->DebugName()->ToCString().get(), 354 shared_info->DebugName()->ToCString().get(),
346 info_->shared_info()->DebugName()->ToCString().get()); 355 info_->shared_info()->DebugName()->ToCString().get());
347 return NoChange(); 356 return NoChange();
348 } 357 }
349 358
350 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on 359 // TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on
351 // not inlining recursive functions. We might want to relax that at some 360 // not inlining recursive functions. We might want to relax that at some
352 // point. 361 // point.
353 for (Node* frame_state = call.frame_state_after(); 362 for (Node* frame_state = call.frame_state_after();
354 frame_state->opcode() == IrOpcode::kFrameState; 363 frame_state->opcode() == IrOpcode::kFrameState;
355 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) { 364 frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
356 FrameStateInfo const& info = OpParameter<FrameStateInfo>(frame_state); 365 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
357 Handle<SharedFunctionInfo> shared_info; 366 Handle<SharedFunctionInfo> frame_shared_info;
358 if (info.shared_info().ToHandle(&shared_info) && 367 if (frame_info.shared_info().ToHandle(&frame_shared_info) &&
359 *shared_info == function->shared()) { 368 *frame_shared_info == *shared_info) {
360 TRACE("Not inlining %s into %s because call is recursive\n", 369 TRACE("Not inlining %s into %s because call is recursive\n",
361 function->shared()->DebugName()->ToCString().get(), 370 shared_info->DebugName()->ToCString().get(),
362 info_->shared_info()->DebugName()->ToCString().get()); 371 info_->shared_info()->DebugName()->ToCString().get());
363 return NoChange(); 372 return NoChange();
364 } 373 }
365 } 374 }
366 375
367 // TODO(turbofan): Inlining into a try-block is not yet supported. 376 // TODO(turbofan): Inlining into a try-block is not yet supported.
368 if (NodeProperties::IsExceptionalCall(node)) { 377 if (NodeProperties::IsExceptionalCall(node)) {
369 TRACE("Not inlining %s into %s because of surrounding try-block\n", 378 TRACE("Not inlining %s into %s because of surrounding try-block\n",
370 function->shared()->DebugName()->ToCString().get(), 379 shared_info->DebugName()->ToCString().get(),
371 info_->shared_info()->DebugName()->ToCString().get()); 380 info_->shared_info()->DebugName()->ToCString().get());
372 return NoChange(); 381 return NoChange();
373 } 382 }
374 383
375 Zone zone; 384 Zone zone;
376 ParseInfo parse_info(&zone, function); 385 ParseInfo parse_info(&zone, function);
377 CompilationInfo info(&parse_info); 386 CompilationInfo info(&parse_info);
378 if (info_->is_deoptimization_enabled()) { 387 if (info_->is_deoptimization_enabled()) info.MarkAsDeoptimizationEnabled();
379 info.MarkAsDeoptimizationEnabled();
380 }
381 388
382 if (!Compiler::ParseAndAnalyze(info.parse_info())) { 389 if (!Compiler::ParseAndAnalyze(info.parse_info())) {
383 TRACE("Not inlining %s into %s because parsing failed\n", 390 TRACE("Not inlining %s into %s because parsing failed\n",
384 function->shared()->DebugName()->ToCString().get(), 391 shared_info->DebugName()->ToCString().get(),
385 info_->shared_info()->DebugName()->ToCString().get()); 392 info_->shared_info()->DebugName()->ToCString().get());
386 if (info_->isolate()->has_pending_exception()) { 393 if (info_->isolate()->has_pending_exception()) {
387 info_->isolate()->clear_pending_exception(); 394 info_->isolate()->clear_pending_exception();
388 } 395 }
389 return NoChange(); 396 return NoChange();
390 } 397 }
391 398
392 // In strong mode, in case of too few arguments we need to throw a TypeError 399 // In strong mode, in case of too few arguments we need to throw a TypeError
393 // so we must not inline this call. 400 // so we must not inline this call.
394 int parameter_count = info.literal()->parameter_count(); 401 int parameter_count = info.literal()->parameter_count();
395 if (is_strong(info.language_mode()) && 402 if (is_strong(info.language_mode()) &&
396 call.formal_arguments() < parameter_count) { 403 call.formal_arguments() < parameter_count) {
397 TRACE("Not inlining %s into %s because too few arguments for strong mode\n", 404 TRACE("Not inlining %s into %s because too few arguments for strong mode\n",
398 function->shared()->DebugName()->ToCString().get(), 405 shared_info->DebugName()->ToCString().get(),
399 info_->shared_info()->DebugName()->ToCString().get()); 406 info_->shared_info()->DebugName()->ToCString().get());
400 return NoChange(); 407 return NoChange();
401 } 408 }
402 409
403 if (!Compiler::EnsureDeoptimizationSupport(&info)) { 410 if (!Compiler::EnsureDeoptimizationSupport(&info)) {
404 TRACE("Not inlining %s into %s because deoptimization support failed\n", 411 TRACE("Not inlining %s into %s because deoptimization support failed\n",
405 function->shared()->DebugName()->ToCString().get(), 412 shared_info->DebugName()->ToCString().get(),
406 info_->shared_info()->DebugName()->ToCString().get()); 413 info_->shared_info()->DebugName()->ToCString().get());
407 return NoChange(); 414 return NoChange();
408 } 415 }
409 // Remember that we inlined this function. This needs to be called right 416 // Remember that we inlined this function. This needs to be called right
410 // after we ensure deoptimization support so that the code flusher 417 // after we ensure deoptimization support so that the code flusher
411 // does not remove the code with the deoptimization support. 418 // does not remove the code with the deoptimization support.
412 info_->AddInlinedFunction(info.shared_info()); 419 info_->AddInlinedFunction(shared_info);
413 420
414 // ---------------------------------------------------------------- 421 // ----------------------------------------------------------------
415 // After this point, we've made a decision to inline this function. 422 // After this point, we've made a decision to inline this function.
416 // We shall not bailout from inlining if we got here. 423 // We shall not bailout from inlining if we got here.
417 424
418 TRACE("Inlining %s into %s\n", 425 TRACE("Inlining %s into %s\n",
419 function->shared()->DebugName()->ToCString().get(), 426 shared_info->DebugName()->ToCString().get(),
420 info_->shared_info()->DebugName()->ToCString().get()); 427 info_->shared_info()->DebugName()->ToCString().get());
421 428
422 // TODO(mstarzinger): We could use the temporary zone for the graph because 429 // TODO(mstarzinger): We could use the temporary zone for the graph because
423 // nodes are copied. This however leads to Zone-Types being allocated in the 430 // nodes are copied. This however leads to Zone-Types being allocated in the
424 // wrong zone and makes the engine explode at high speeds. Explosion bad! 431 // wrong zone and makes the engine explode at high speeds. Explosion bad!
425 Graph graph(jsgraph_->zone()); 432 Graph graph(jsgraph_->zone());
426 JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(), 433 JSGraph jsgraph(info.isolate(), &graph, jsgraph_->common(),
427 jsgraph_->javascript(), jsgraph_->simplified(), 434 jsgraph_->javascript(), jsgraph_->simplified(),
428 jsgraph_->machine()); 435 jsgraph_->machine());
429 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph); 436 AstGraphBuilder graph_builder(local_zone_, &info, &jsgraph);
430 graph_builder.CreateGraph(false); 437 graph_builder.CreateGraph(false);
431 438
432 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone); 439 CopyVisitor visitor(&graph, jsgraph_->graph(), &zone);
433 visitor.CopyGraph(); 440 visitor.CopyGraph();
434 441
435 Node* start = visitor.GetCopy(graph.start()); 442 Node* start = visitor.GetCopy(graph.start());
436 Node* end = visitor.GetCopy(graph.end()); 443 Node* end = visitor.GetCopy(graph.end());
437 Node* frame_state = call.frame_state_after(); 444 Node* frame_state = call.frame_state_after();
438 Node* new_target = jsgraph_->UndefinedConstant(); 445 Node* new_target = jsgraph_->UndefinedConstant();
439 446
440 // Insert nodes around the call that model the behavior required for a 447 // Insert nodes around the call that model the behavior required for a
441 // constructor dispatch (allocate implicit receiver and check return value). 448 // constructor dispatch (allocate implicit receiver and check return value).
442 // This models the behavior usually accomplished by our {JSConstructStub}. 449 // This models the behavior usually accomplished by our {JSConstructStub}.
443 // Note that the context has to be the callers context (input to call node). 450 // Note that the context has to be the callers context (input to call node).
444 Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver. 451 Node* receiver = jsgraph_->UndefinedConstant(); // Implicit receiver.
445 if (node->opcode() == IrOpcode::kJSCallConstruct && 452 if (node->opcode() == IrOpcode::kJSCallConstruct &&
446 NeedsImplicitReceiver(function, info_->isolate())) { 453 NeedsImplicitReceiver(shared_info)) {
447 Node* effect = NodeProperties::GetEffectInput(node); 454 Node* effect = NodeProperties::GetEffectInput(node);
448 Node* context = NodeProperties::GetContextInput(node); 455 Node* context = NodeProperties::GetContextInput(node);
449 Node* create = jsgraph_->graph()->NewNode( 456 Node* create = jsgraph_->graph()->NewNode(
450 jsgraph_->javascript()->Create(), call.target(), call.new_target(), 457 jsgraph_->javascript()->Create(), call.target(), call.new_target(),
451 context, call.frame_state_before(), effect); 458 context, call.frame_state_before(), effect);
452 NodeProperties::ReplaceEffectInput(node, create); 459 NodeProperties::ReplaceEffectInput(node, create);
453 // Insert a check of the return value to determine whether the return value 460 // Insert a check of the return value to determine whether the return value
454 // or the implicit receiver should be selected as a result of the call. 461 // or the implicit receiver should be selected as a result of the call.
455 Node* check = jsgraph_->graph()->NewNode( 462 Node* check = jsgraph_->graph()->NewNode(
456 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), 463 jsgraph_->javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1),
(...skipping 28 matching lines...) Expand all
485 // type feedback in the compiler. 492 // type feedback in the compiler.
486 Node* context = jsgraph_->Constant(handle(function->context())); 493 Node* context = jsgraph_->Constant(handle(function->context()));
487 494
488 // Insert a JSConvertReceiver node for sloppy callees. Note that the context 495 // Insert a JSConvertReceiver node for sloppy callees. Note that the context
489 // passed into this node has to be the callees context (loaded above). Note 496 // passed into this node has to be the callees context (loaded above). Note
490 // that the frame state passed to the JSConvertReceiver must be the frame 497 // that the frame state passed to the JSConvertReceiver must be the frame
491 // state _before_ the call; it is not necessary to fiddle with the receiver 498 // state _before_ the call; it is not necessary to fiddle with the receiver
492 // in that frame state tho, as the conversion of the receiver can be repeated 499 // in that frame state tho, as the conversion of the receiver can be repeated
493 // any number of times, it's not observable. 500 // any number of times, it's not observable.
494 if (node->opcode() == IrOpcode::kJSCallFunction && 501 if (node->opcode() == IrOpcode::kJSCallFunction &&
495 is_sloppy(info.language_mode()) && !function->shared()->native()) { 502 is_sloppy(info.language_mode()) && !shared_info->native()) {
496 const CallFunctionParameters& p = CallFunctionParametersOf(node->op()); 503 const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
497 Node* effect = NodeProperties::GetEffectInput(node); 504 Node* effect = NodeProperties::GetEffectInput(node);
498 Node* convert = jsgraph_->graph()->NewNode( 505 Node* convert = jsgraph_->graph()->NewNode(
499 jsgraph_->javascript()->ConvertReceiver(p.convert_mode()), 506 jsgraph_->javascript()->ConvertReceiver(p.convert_mode()),
500 call.receiver(), context, call.frame_state_before(), effect, start); 507 call.receiver(), context, call.frame_state_before(), effect, start);
501 NodeProperties::ReplaceValueInput(node, convert, 1); 508 NodeProperties::ReplaceValueInput(node, convert, 1);
502 NodeProperties::ReplaceEffectInput(node, convert); 509 NodeProperties::ReplaceEffectInput(node, convert);
503 } 510 }
504 511
505 // Insert argument adaptor frame if required. The callees formal parameter 512 // Insert argument adaptor frame if required. The callees formal parameter
506 // count (i.e. value outputs of start node minus target, receiver, new target, 513 // count (i.e. value outputs of start node minus target, receiver, new target,
507 // arguments count and context) have to match the number of arguments passed 514 // arguments count and context) have to match the number of arguments passed
508 // to the call. 515 // to the call.
509 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5); 516 DCHECK_EQ(parameter_count, start->op()->ValueOutputCount() - 5);
510 if (call.formal_arguments() != parameter_count) { 517 if (call.formal_arguments() != parameter_count) {
511 frame_state = CreateArtificialFrameState( 518 frame_state = CreateArtificialFrameState(
512 node, frame_state, call.formal_arguments(), 519 node, frame_state, call.formal_arguments(),
513 FrameStateType::kArgumentsAdaptor, info.shared_info()); 520 FrameStateType::kArgumentsAdaptor, shared_info);
514 } 521 }
515 522
516 return InlineCall(node, new_target, context, frame_state, start, end); 523 return InlineCall(node, new_target, context, frame_state, start, end);
517 } 524 }
518 525
519 } // namespace compiler 526 } // namespace compiler
520 } // namespace internal 527 } // namespace internal
521 } // namespace v8 528 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698