| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:collection'; | 5 import 'dart:collection'; |
| 6 | 6 |
| 7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
| 8 | 8 |
| 9 import '../closure.dart'; | 9 import '../closure.dart'; |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) | 61 SsaBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory) |
| 62 : emitter = backend.emitter, | 62 : emitter = backend.emitter, |
| 63 backend = backend, | 63 backend = backend, |
| 64 compiler = backend.compiler, | 64 compiler = backend.compiler, |
| 65 super(backend.compiler.measurer); | 65 super(backend.compiler.measurer); |
| 66 | 66 |
| 67 DiagnosticReporter get reporter => compiler.reporter; | 67 DiagnosticReporter get reporter => compiler.reporter; |
| 68 | 68 |
| 69 HGraph build(CodegenWorkItem work, ClosedWorld closedWorld) { | 69 HGraph build(CodegenWorkItem work, ClosedWorld closedWorld) { |
| 70 return measure(() { | 70 return measure(() { |
| 71 MemberElement element = work.element.implementation; | 71 Element element = work.element.implementation; |
| 72 return reporter.withCurrentElement(element, () { | 72 return reporter.withCurrentElement(element, () { |
| 73 SsaBuilder builder = new SsaBuilder( | 73 SsaBuilder builder = new SsaBuilder( |
| 74 work.element.implementation, | 74 work.element.implementation, |
| 75 work.resolvedAst, | 75 work.resolvedAst, |
| 76 work.registry, | 76 work.registry, |
| 77 backend, | 77 backend, |
| 78 closedWorld, | 78 closedWorld, |
| 79 emitter.nativeEmitter, | 79 emitter.nativeEmitter, |
| 80 sourceInformationFactory); | 80 sourceInformationFactory); |
| 81 HGraph graph = builder.build(); | 81 HGraph graph = builder.build(); |
| 82 | 82 |
| 83 // Default arguments are handled elsewhere, but we must ensure | 83 // Default arguments are handled elsewhere, but we must ensure |
| 84 // that the default values are computed during codegen. | 84 // that the default values are computed during codegen. |
| 85 if (!identical(element.kind, ElementKind.FIELD)) { | 85 if (!identical(element.kind, ElementKind.FIELD)) { |
| 86 MethodElement function = element; | 86 FunctionElement function = element; |
| 87 FunctionSignature signature = function.functionSignature; | 87 FunctionSignature signature = function.functionSignature; |
| 88 signature.forEachOptionalParameter((ParameterElement parameter) { | 88 signature.forEachOptionalParameter((ParameterElement parameter) { |
| 89 // This ensures the default value will be computed. | 89 // This ensures the default value will be computed. |
| 90 ConstantValue constant = | 90 ConstantValue constant = |
| 91 backend.constants.getConstantValue(parameter.constant); | 91 backend.constants.getConstantValue(parameter.constant); |
| 92 work.registry.registerCompileTimeConstant(constant); | 92 work.registry.registerCompileTimeConstant(constant); |
| 93 }); | 93 }); |
| 94 } | 94 } |
| 95 if (backend.tracer.isEnabled) { | 95 if (backend.tracer.isEnabled) { |
| 96 String name; | 96 String name; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 120 with | 120 with |
| 121 BaseImplementationOfCompoundsMixin, | 121 BaseImplementationOfCompoundsMixin, |
| 122 BaseImplementationOfSetIfNullsMixin, | 122 BaseImplementationOfSetIfNullsMixin, |
| 123 BaseImplementationOfSuperIndexSetIfNullMixin, | 123 BaseImplementationOfSuperIndexSetIfNullMixin, |
| 124 SemanticSendResolvedMixin, | 124 SemanticSendResolvedMixin, |
| 125 NewBulkMixin, | 125 NewBulkMixin, |
| 126 ErrorBulkMixin, | 126 ErrorBulkMixin, |
| 127 GraphBuilder | 127 GraphBuilder |
| 128 implements SemanticSendVisitor { | 128 implements SemanticSendVisitor { |
| 129 /// The element for which this SSA builder is being used. | 129 /// The element for which this SSA builder is being used. |
| 130 final MemberElement target; | 130 final Element target; |
| 131 final ClosedWorld closedWorld; | 131 final ClosedWorld closedWorld; |
| 132 | 132 |
| 133 ResolvedAst resolvedAst; | 133 ResolvedAst resolvedAst; |
| 134 | 134 |
| 135 /// Used to report information about inlining (which occurs while building the | 135 /// Used to report information about inlining (which occurs while building the |
| 136 /// SSA graph), when dump-info is enabled. | 136 /// SSA graph), when dump-info is enabled. |
| 137 final InfoReporter infoReporter; | 137 final InfoReporter infoReporter; |
| 138 | 138 |
| 139 /// Registry used to enqueue work during codegen, may be null to avoid | 139 /// Registry used to enqueue work during codegen, may be null to avoid |
| 140 /// enqueing any work. | 140 /// enqueing any work. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 170 /** | 170 /** |
| 171 * True if we are visiting the expression of a throw statement; we assume this | 171 * True if we are visiting the expression of a throw statement; we assume this |
| 172 * is a slow path. | 172 * is a slow path. |
| 173 */ | 173 */ |
| 174 bool inExpressionOfThrow = false; | 174 bool inExpressionOfThrow = false; |
| 175 | 175 |
| 176 /** | 176 /** |
| 177 * This stack contains declaration elements of the functions being built | 177 * This stack contains declaration elements of the functions being built |
| 178 * or inlined by this builder. | 178 * or inlined by this builder. |
| 179 */ | 179 */ |
| 180 final List<MemberElement> sourceElementStack = <MemberElement>[]; | 180 final List<Element> sourceElementStack = <Element>[]; |
| 181 | 181 |
| 182 HInstruction rethrowableException; | 182 HInstruction rethrowableException; |
| 183 | 183 |
| 184 /// Returns `true` if the current element is an `async` function. | 184 /// Returns `true` if the current element is an `async` function. |
| 185 bool get isBuildingAsyncFunction { | 185 bool get isBuildingAsyncFunction { |
| 186 Element element = sourceElement; | 186 Element element = sourceElement; |
| 187 return (element is FunctionElement && | 187 return (element is FunctionElement && |
| 188 element.asyncMarker == AsyncMarker.ASYNC); | 188 element.asyncMarker == AsyncMarker.ASYNC); |
| 189 } | 189 } |
| 190 | 190 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 void apply(ast.Node node, [_]) { | 248 void apply(ast.Node node, [_]) { |
| 249 node.accept(this); | 249 node.accept(this); |
| 250 } | 250 } |
| 251 | 251 |
| 252 /// Returns the current source element. | 252 /// Returns the current source element. |
| 253 /// | 253 /// |
| 254 /// The returned element is a declaration element. | 254 /// The returned element is a declaration element. |
| 255 // TODO(johnniwinther): Check that all usages of sourceElement agree on | 255 // TODO(johnniwinther): Check that all usages of sourceElement agree on |
| 256 // implementation/declaration distinction. | 256 // implementation/declaration distinction. |
| 257 @override | 257 @override |
| 258 MemberElement get sourceElement => sourceElementStack.last; | 258 Element get sourceElement => sourceElementStack.last; |
| 259 | 259 |
| 260 /// Helper to retrieve global inference results for [element] with special | 260 /// Helper to retrieve global inference results for [element] with special |
| 261 /// care for `ConstructorBodyElement`s which don't exist at the time the | 261 /// care for `ConstructorBodyElement`s which don't exist at the time the |
| 262 /// global analysis run. | 262 /// global analysis run. |
| 263 /// | 263 /// |
| 264 /// Note: this helper is used selectively. When we know that we are in a | 264 /// Note: this helper is used selectively. When we know that we are in a |
| 265 /// context were we don't expect to see a constructor body element, we | 265 /// context were we don't expect to see a constructor body element, we |
| 266 /// directly fetch the data from the global inference results. | 266 /// directly fetch the data from the global inference results. |
| 267 GlobalTypeInferenceElementResult _resultOf(AstElement element) => | 267 GlobalTypeInferenceElementResult _resultOf(AstElement element) => |
| 268 inferenceResults.resultOf( | 268 inferenceResults.resultOf( |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 // Bail out early if the inlining decision is in the cache and we can't | 430 // Bail out early if the inlining decision is in the cache and we can't |
| 431 // inline (no need to check the hard constraints). | 431 // inline (no need to check the hard constraints). |
| 432 bool cachedCanBeInlined = | 432 bool cachedCanBeInlined = |
| 433 backend.inlineCache.canInline(function, insideLoop: insideLoop); | 433 backend.inlineCache.canInline(function, insideLoop: insideLoop); |
| 434 if (cachedCanBeInlined == false) return false; | 434 if (cachedCanBeInlined == false) return false; |
| 435 | 435 |
| 436 bool meetsHardConstraints() { | 436 bool meetsHardConstraints() { |
| 437 if (compiler.options.disableInlining) return false; | 437 if (compiler.options.disableInlining) return false; |
| 438 | 438 |
| 439 assert(invariant( | 439 assert(invariant( |
| 440 currentNode != null ? currentNode : function, | 440 currentNode != null ? currentNode : element, |
| 441 selector != null || | 441 selector != null || |
| 442 Elements.isStaticOrTopLevel(function) || | 442 Elements.isStaticOrTopLevel(element) || |
| 443 function.isGenerativeConstructorBody, | 443 element.isGenerativeConstructorBody, |
| 444 message: "Missing selector for inlining of $function.")); | 444 message: "Missing selector for inlining of $element.")); |
| 445 if (selector != null) { | 445 if (selector != null) { |
| 446 if (!selector.applies(function)) return false; | 446 if (!selector.applies(function)) return false; |
| 447 if (mask != null && !mask.canHit(function, selector, closedWorld)) { | 447 if (mask != null && !mask.canHit(function, selector, closedWorld)) { |
| 448 return false; | 448 return false; |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 | 451 |
| 452 if (backend.isJsInterop(function)) return false; | 452 if (backend.isJsInterop(element)) return false; |
| 453 | 453 |
| 454 // Don't inline operator== methods if the parameter can be null. | 454 // Don't inline operator== methods if the parameter can be null. |
| 455 if (function.name == '==') { | 455 if (element.name == '==') { |
| 456 if (function.enclosingClass != commonElements.objectClass && | 456 if (element.enclosingClass != commonElements.objectClass && |
| 457 providedArguments[1].canBeNull()) { | 457 providedArguments[1].canBeNull()) { |
| 458 return false; | 458 return false; |
| 459 } | 459 } |
| 460 } | 460 } |
| 461 | 461 |
| 462 // Generative constructors of native classes should not be called directly | 462 // Generative constructors of native classes should not be called directly |
| 463 // and have an extra argument that causes problems with inlining. | 463 // and have an extra argument that causes problems with inlining. |
| 464 if (function.isGenerativeConstructor && | 464 if (element.isGenerativeConstructor && |
| 465 backend.isNativeOrExtendsNative(function.enclosingClass)) { | 465 backend.isNativeOrExtendsNative(element.enclosingClass)) { |
| 466 return false; | 466 return false; |
| 467 } | 467 } |
| 468 | 468 |
| 469 // A generative constructor body is not seen by global analysis, | 469 // A generative constructor body is not seen by global analysis, |
| 470 // so we should not query for its type. | 470 // so we should not query for its type. |
| 471 if (!function.isGenerativeConstructorBody) { | 471 if (!element.isGenerativeConstructorBody) { |
| 472 if (inferenceResults.resultOf(function).throwsAlways) { | 472 if (inferenceResults.resultOf(element).throwsAlways) { |
| 473 isReachable = false; | 473 isReachable = false; |
| 474 return false; | 474 return false; |
| 475 } | 475 } |
| 476 } | 476 } |
| 477 | 477 |
| 478 return true; | 478 return true; |
| 479 } | 479 } |
| 480 | 480 |
| 481 bool doesNotContainCode() { | 481 bool doesNotContainCode() { |
| 482 // A function with size 1 does not contain any code. | 482 // A function with size 1 does not contain any code. |
| 483 return InlineWeeder.canBeInlined(functionResolvedAst, 1, true, | 483 return InlineWeeder.canBeInlined(functionResolvedAst, 1, true, |
| 484 enableUserAssertions: compiler.options.enableUserAssertions); | 484 enableUserAssertions: compiler.options.enableUserAssertions); |
| 485 } | 485 } |
| 486 | 486 |
| 487 bool reductiveHeuristic() { | 487 bool reductiveHeuristic() { |
| 488 // The call is on a path which is executed rarely, so inline only if it | 488 // The call is on a path which is executed rarely, so inline only if it |
| 489 // does not make the program larger. | 489 // does not make the program larger. |
| 490 if (isCalledOnce(function)) { | 490 if (isCalledOnce(element)) { |
| 491 return InlineWeeder.canBeInlined(functionResolvedAst, -1, false, | 491 return InlineWeeder.canBeInlined(functionResolvedAst, -1, false, |
| 492 enableUserAssertions: compiler.options.enableUserAssertions); | 492 enableUserAssertions: compiler.options.enableUserAssertions); |
| 493 } | 493 } |
| 494 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable | 494 // TODO(sra): Measure if inlining would 'reduce' the size. One desirable |
| 495 // case we miss by doing nothing is inlining very simple constructors | 495 // case we miss by doing nothing is inlining very simple constructors |
| 496 // where all fields are initialized with values from the arguments at this | 496 // where all fields are initialized with values from the arguments at this |
| 497 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but | 497 // call site. The code is slightly larger (`new Foo(1)` vs `Foo$(1)`) but |
| 498 // that usually means the factory constructor is left unused and not | 498 // that usually means the factory constructor is left unused and not |
| 499 // emitted. | 499 // emitted. |
| 500 // We at least inline bodies that are empty (and thus have a size of 1). | 500 // We at least inline bodies that are empty (and thus have a size of 1). |
| 501 return doesNotContainCode(); | 501 return doesNotContainCode(); |
| 502 } | 502 } |
| 503 | 503 |
| 504 bool heuristicSayGoodToGo() { | 504 bool heuristicSayGoodToGo() { |
| 505 // Don't inline recursively | 505 // Don't inline recursively |
| 506 if (inliningStack.any((entry) => entry.function == function)) { | 506 if (inliningStack.any((entry) => entry.function == function)) { |
| 507 return false; | 507 return false; |
| 508 } | 508 } |
| 509 | 509 |
| 510 if (function.isSynthesized) return true; | 510 if (element.isSynthesized) return true; |
| 511 | 511 |
| 512 // Don't inline across deferred import to prevent leaking code. The only | 512 // Don't inline across deferred import to prevent leaking code. The only |
| 513 // exception is an empty function (which does not contain code). | 513 // exception is an empty function (which does not contain code). |
| 514 bool hasOnlyNonDeferredImportPaths = compiler.deferredLoadTask | 514 bool hasOnlyNonDeferredImportPaths = compiler.deferredLoadTask |
| 515 .hasOnlyNonDeferredImportPaths(compiler.currentElement, function); | 515 .hasOnlyNonDeferredImportPaths(compiler.currentElement, element); |
| 516 | 516 |
| 517 if (!hasOnlyNonDeferredImportPaths) { | 517 if (!hasOnlyNonDeferredImportPaths) { |
| 518 return doesNotContainCode(); | 518 return doesNotContainCode(); |
| 519 } | 519 } |
| 520 | 520 |
| 521 // Do not inline code that is rarely executed unless it reduces size. | 521 // Do not inline code that is rarely executed unless it reduces size. |
| 522 if (inExpressionOfThrow || inLazyInitializerExpression) { | 522 if (inExpressionOfThrow || inLazyInitializerExpression) { |
| 523 return reductiveHeuristic(); | 523 return reductiveHeuristic(); |
| 524 } | 524 } |
| 525 | 525 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 539 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + | 539 maxInliningNodes = InlineWeeder.INLINING_NODES_INSIDE_LOOP + |
| 540 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; | 540 InlineWeeder.INLINING_NODES_INSIDE_LOOP_ARG_FACTOR * numParameters; |
| 541 } else { | 541 } else { |
| 542 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + | 542 maxInliningNodes = InlineWeeder.INLINING_NODES_OUTSIDE_LOOP + |
| 543 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; | 543 InlineWeeder.INLINING_NODES_OUTSIDE_LOOP_ARG_FACTOR * numParameters; |
| 544 } | 544 } |
| 545 | 545 |
| 546 // If a method is called only once, and all the methods in the | 546 // If a method is called only once, and all the methods in the |
| 547 // inlining stack are called only once as well, we know we will | 547 // inlining stack are called only once as well, we know we will |
| 548 // save on output size by inlining this method. | 548 // save on output size by inlining this method. |
| 549 if (isCalledOnce(function)) { | 549 if (isCalledOnce(element)) { |
| 550 useMaxInliningNodes = false; | 550 useMaxInliningNodes = false; |
| 551 } | 551 } |
| 552 bool canInline; | 552 bool canInline; |
| 553 canInline = InlineWeeder.canBeInlined( | 553 canInline = InlineWeeder.canBeInlined( |
| 554 functionResolvedAst, maxInliningNodes, useMaxInliningNodes, | 554 functionResolvedAst, maxInliningNodes, useMaxInliningNodes, |
| 555 enableUserAssertions: compiler.options.enableUserAssertions); | 555 enableUserAssertions: compiler.options.enableUserAssertions); |
| 556 if (canInline) { | 556 if (canInline) { |
| 557 backend.inlineCache.markAsInlinable(function, insideLoop: insideLoop); | 557 backend.inlineCache.markAsInlinable(element, insideLoop: insideLoop); |
| 558 } else { | 558 } else { |
| 559 backend.inlineCache | 559 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); |
| 560 .markAsNonInlinable(function, insideLoop: insideLoop); | |
| 561 } | 560 } |
| 562 return canInline; | 561 return canInline; |
| 563 } | 562 } |
| 564 | 563 |
| 565 void doInlining() { | 564 void doInlining() { |
| 566 // Add an explicit null check on the receiver before doing the | 565 // Add an explicit null check on the receiver before doing the |
| 567 // inlining. We use [element] to get the same name in the | 566 // inlining. We use [element] to get the same name in the |
| 568 // NoSuchMethodError message as if we had called it. | 567 // NoSuchMethodError message as if we had called it. |
| 569 if (function.isInstanceMember && | 568 if (element.isInstanceMember && |
| 570 !function.isGenerativeConstructorBody && | 569 !element.isGenerativeConstructorBody && |
| 571 (mask == null || mask.isNullable)) { | 570 (mask == null || mask.isNullable)) { |
| 572 addWithPosition( | 571 addWithPosition( |
| 573 new HFieldGet(null, providedArguments[0], commonMasks.dynamicType, | 572 new HFieldGet(null, providedArguments[0], commonMasks.dynamicType, |
| 574 isAssignable: false), | 573 isAssignable: false), |
| 575 currentNode); | 574 currentNode); |
| 576 } | 575 } |
| 577 List<HInstruction> compiledArguments = completeSendArgumentsList( | 576 List<HInstruction> compiledArguments = completeSendArgumentsList( |
| 578 function, selector, providedArguments, currentNode); | 577 function, selector, providedArguments, currentNode); |
| 579 enterInlinedMethod(function, functionResolvedAst, compiledArguments, | 578 enterInlinedMethod(function, functionResolvedAst, compiledArguments, |
| 580 instanceType: instanceType); | 579 instanceType: instanceType); |
| 581 inlinedFrom(functionResolvedAst, () { | 580 inlinedFrom(functionResolvedAst, () { |
| 582 if (!isReachable) { | 581 if (!isReachable) { |
| 583 emitReturn(graph.addConstantNull(closedWorld), null); | 582 emitReturn(graph.addConstantNull(closedWorld), null); |
| 584 } else { | 583 } else { |
| 585 doInline(functionResolvedAst); | 584 doInline(functionResolvedAst); |
| 586 } | 585 } |
| 587 }); | 586 }); |
| 588 leaveInlinedMethod(); | 587 leaveInlinedMethod(); |
| 589 } | 588 } |
| 590 | 589 |
| 591 if (meetsHardConstraints() && heuristicSayGoodToGo()) { | 590 if (meetsHardConstraints() && heuristicSayGoodToGo()) { |
| 592 doInlining(); | 591 doInlining(); |
| 593 infoReporter?.reportInlined(function, | 592 infoReporter?.reportInlined(element, |
| 594 inliningStack.isEmpty ? target : inliningStack.last.function); | 593 inliningStack.isEmpty ? target : inliningStack.last.function); |
| 595 return true; | 594 return true; |
| 596 } | 595 } |
| 597 | 596 |
| 598 return false; | 597 return false; |
| 599 } | 598 } |
| 600 | 599 |
| 601 bool get allInlinedFunctionsCalledOnce { | 600 bool get allInlinedFunctionsCalledOnce { |
| 602 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; | 601 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; |
| 603 } | 602 } |
| 604 | 603 |
| 605 bool isFunctionCalledOnce(MethodElement element) { | 604 bool isFunctionCalledOnce(element) { |
| 606 // ConstructorBodyElements are not in the type inference graph. | 605 // ConstructorBodyElements are not in the type inference graph. |
| 607 if (element is ConstructorBodyElement) return false; | 606 if (element is ConstructorBodyElement) return false; |
| 608 return inferenceResults.resultOf(element).isCalledOnce; | 607 return inferenceResults.resultOf(element).isCalledOnce; |
| 609 } | 608 } |
| 610 | 609 |
| 611 bool isCalledOnce(MethodElement element) { | 610 bool isCalledOnce(Element element) { |
| 612 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); | 611 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); |
| 613 } | 612 } |
| 614 | 613 |
| 615 inlinedFrom(ResolvedAst resolvedAst, f()) { | 614 inlinedFrom(ResolvedAst resolvedAst, f()) { |
| 616 MemberElement element = resolvedAst.element; | 615 Element element = resolvedAst.element; |
| 617 assert(element is FunctionElement || element is VariableElement); | 616 assert(element is FunctionElement || element is VariableElement); |
| 618 return reporter.withCurrentElement(element.implementation, () { | 617 return reporter.withCurrentElement(element.implementation, () { |
| 619 // The [sourceElementStack] contains declaration elements. | 618 // The [sourceElementStack] contains declaration elements. |
| 620 SourceInformationBuilder oldSourceInformationBuilder = | 619 SourceInformationBuilder oldSourceInformationBuilder = |
| 621 sourceInformationBuilder; | 620 sourceInformationBuilder; |
| 622 sourceInformationBuilder = | 621 sourceInformationBuilder = |
| 623 sourceInformationBuilder.forContext(resolvedAst); | 622 sourceInformationBuilder.forContext(resolvedAst); |
| 624 sourceElementStack.add(element.declaration); | 623 sourceElementStack.add(element.declaration); |
| 625 var result = f(); | 624 var result = f(); |
| 626 sourceInformationBuilder = oldSourceInformationBuilder; | 625 sourceInformationBuilder = oldSourceInformationBuilder; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 | 678 |
| 680 HInstruction addConstant(ast.Node node) { | 679 HInstruction addConstant(ast.Node node) { |
| 681 return graph.addConstant(getConstantForNode(node), closedWorld); | 680 return graph.addConstant(getConstantForNode(node), closedWorld); |
| 682 } | 681 } |
| 683 | 682 |
| 684 /** | 683 /** |
| 685 * Documentation wanted -- johnniwinther | 684 * Documentation wanted -- johnniwinther |
| 686 * | 685 * |
| 687 * Invariant: [functionElement] must be an implementation element. | 686 * Invariant: [functionElement] must be an implementation element. |
| 688 */ | 687 */ |
| 689 HGraph buildMethod(MethodElement functionElement) { | 688 HGraph buildMethod(FunctionElement functionElement) { |
| 690 assert(invariant(functionElement, functionElement.isImplementation)); | 689 assert(invariant(functionElement, functionElement.isImplementation)); |
| 691 graph.calledInLoop = closedWorld.isCalledInLoop(functionElement); | 690 graph.calledInLoop = closedWorld.isCalledInLoop(functionElement); |
| 692 ast.FunctionExpression function = resolvedAst.node; | 691 ast.FunctionExpression function = resolvedAst.node; |
| 693 assert(function != null); | 692 assert(function != null); |
| 694 assert(elements.getFunctionDefinition(function) != null); | 693 assert(elements.getFunctionDefinition(function) != null); |
| 695 openFunction(functionElement, function); | 694 openFunction(functionElement, function); |
| 696 String name = functionElement.name; | 695 String name = functionElement.name; |
| 697 if (backend.isJsInterop(functionElement)) { | 696 if (backend.isJsInterop(functionElement)) { |
| 698 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), | 697 push(invokeJsInteropFunction(functionElement, parameters.values.toList(), |
| 699 sourceInformationBuilder.buildGeneric(function))); | 698 sourceInformationBuilder.buildGeneric(function))); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 // Add the parameter as the last instruction of the entry block. | 761 // Add the parameter as the last instruction of the entry block. |
| 763 // If the method is intercepted, we want the actual receiver | 762 // If the method is intercepted, we want the actual receiver |
| 764 // to be the first parameter. | 763 // to be the first parameter. |
| 765 graph.entry.addBefore(graph.entry.last, parameter); | 764 graph.entry.addBefore(graph.entry.last, parameter); |
| 766 HInstruction value = | 765 HInstruction value = |
| 767 typeBuilder.potentiallyCheckOrTrustType(parameter, field.type); | 766 typeBuilder.potentiallyCheckOrTrustType(parameter, field.type); |
| 768 add(new HFieldSet(field, thisInstruction, value)); | 767 add(new HFieldSet(field, thisInstruction, value)); |
| 769 return closeFunction(); | 768 return closeFunction(); |
| 770 } | 769 } |
| 771 | 770 |
| 772 HGraph buildLazyInitializer(FieldElement variable) { | 771 HGraph buildLazyInitializer(VariableElement variable) { |
| 773 assert(invariant(variable, resolvedAst.element == variable, | 772 assert(invariant(variable, resolvedAst.element == variable, |
| 774 message: "Unexpected variable $variable for $resolvedAst.")); | 773 message: "Unexpected variable $variable for $resolvedAst.")); |
| 775 inLazyInitializerExpression = true; | 774 inLazyInitializerExpression = true; |
| 776 ast.VariableDefinitions node = resolvedAst.node; | 775 ast.VariableDefinitions node = resolvedAst.node; |
| 777 ast.Node initializer = resolvedAst.body; | 776 ast.Node initializer = resolvedAst.body; |
| 778 assert(invariant(variable, initializer != null, | 777 assert(invariant(variable, initializer != null, |
| 779 message: "Non-constant variable $variable has no initializer.")); | 778 message: "Non-constant variable $variable has no initializer.")); |
| 780 openFunction(variable, node); | 779 openFunction(variable, node); |
| 781 visit(initializer); | 780 visit(initializer); |
| 782 HInstruction value = pop(); | 781 HInstruction value = pop(); |
| (...skipping 5623 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6406 } | 6405 } |
| 6407 | 6406 |
| 6408 visitTypeVariable(ast.TypeVariable node) { | 6407 visitTypeVariable(ast.TypeVariable node) { |
| 6409 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); | 6408 reporter.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); |
| 6410 } | 6409 } |
| 6411 | 6410 |
| 6412 /** | 6411 /** |
| 6413 * This method is invoked before inlining the body of [function] into this | 6412 * This method is invoked before inlining the body of [function] into this |
| 6414 * [SsaBuilder]. | 6413 * [SsaBuilder]. |
| 6415 */ | 6414 */ |
| 6416 void enterInlinedMethod(MethodElement function, | 6415 void enterInlinedMethod(FunctionElement function, |
| 6417 ResolvedAst functionResolvedAst, List<HInstruction> compiledArguments, | 6416 ResolvedAst functionResolvedAst, List<HInstruction> compiledArguments, |
| 6418 {InterfaceType instanceType}) { | 6417 {InterfaceType instanceType}) { |
| 6419 AstInliningState state = new AstInliningState( | 6418 AstInliningState state = new AstInliningState( |
| 6420 function, | 6419 function, |
| 6421 returnLocal, | 6420 returnLocal, |
| 6422 returnType, | 6421 returnType, |
| 6423 resolvedAst, | 6422 resolvedAst, |
| 6424 stack, | 6423 stack, |
| 6425 localsHandler, | 6424 localsHandler, |
| 6426 inTryStatement, | 6425 inTryStatement, |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6755 this.oldReturnLocal, | 6754 this.oldReturnLocal, |
| 6756 this.oldReturnType, | 6755 this.oldReturnType, |
| 6757 this.oldResolvedAst, | 6756 this.oldResolvedAst, |
| 6758 this.oldStack, | 6757 this.oldStack, |
| 6759 this.oldLocalsHandler, | 6758 this.oldLocalsHandler, |
| 6760 this.inTryStatement, | 6759 this.inTryStatement, |
| 6761 this.allFunctionsCalledOnce, | 6760 this.allFunctionsCalledOnce, |
| 6762 this.oldElementInferenceResults) | 6761 this.oldElementInferenceResults) |
| 6763 : super(function); | 6762 : super(function); |
| 6764 } | 6763 } |
| OLD | NEW |