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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
11 | 11 |
12 SsaFunctionCompiler(JavaScriptBackend backend, bool generateSourceMap) | 12 SsaFunctionCompiler(JavaScriptBackend backend, bool generateSourceMap) |
13 : generator = new SsaCodeGeneratorTask(backend), | 13 : generator = new SsaCodeGeneratorTask(backend), |
14 builder = new SsaBuilderTask(backend, generateSourceMap), | 14 builder = new SsaBuilderTask(backend, generateSourceMap), |
15 optimizer = new SsaOptimizerTask(backend); | 15 optimizer = new SsaOptimizerTask(backend); |
16 | 16 |
17 /// Generates JavaScript code for `work.element`. | 17 /// Generates JavaScript code for `work.element`. |
18 /// Using the ssa builder, optimizer and codegenerator. | 18 /// Using the ssa builder, optimizer and codegenerator. |
19 js.Fun compile(CodegenWorkItem work) { | 19 js.Fun compile(CodegenWorkItem work) { |
20 HGraph graph = builder.build(work); | 20 HGraph graph = builder.build(work); |
21 optimizer.optimize(work, graph); | 21 optimizer.optimize(work, graph); |
22 return generator.generateCode(work, graph); | 22 Element element = work.element; |
| 23 js.Expression result = generator.generateCode(work, graph); |
| 24 if (element is FunctionElement) { |
| 25 JavaScriptBackend backend = builder.backend; |
| 26 |
| 27 AsyncRewriter rewriter = null; |
| 28 if (element.asyncMarker == AsyncMarker.ASYNC) { |
| 29 rewriter = new AsyncRewriter( |
| 30 backend.compiler, |
| 31 backend.compiler.currentElement, |
| 32 thenHelper: |
| 33 backend.emitter.staticFunctionAccess(backend.getThenHelper()), |
| 34 newCompleter: backend.emitter.staticFunctionAccess( |
| 35 backend.getCompleterConstructor()), |
| 36 safeVariableName: backend.namer.safeVariableName); |
| 37 } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) { |
| 38 rewriter = new AsyncRewriter( |
| 39 backend.compiler, |
| 40 backend.compiler.currentElement, |
| 41 endOfIteration: backend.emitter.staticFunctionAccess( |
| 42 backend.getEndOfIteration()), |
| 43 newIterable: backend.emitter.staticFunctionAccess( |
| 44 backend.getSyncStarIterableConstructor()), |
| 45 yieldStarExpression: backend.emitter.staticFunctionAccess( |
| 46 backend.getYieldStar()), |
| 47 safeVariableName: backend.namer.safeVariableName); |
| 48 } |
| 49 else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) { |
| 50 rewriter = new AsyncRewriter( |
| 51 backend.compiler, |
| 52 backend.compiler.currentElement, |
| 53 streamHelper: backend.emitter.staticFunctionAccess( |
| 54 backend.getStreamHelper()), |
| 55 newController: backend.emitter.staticFunctionAccess( |
| 56 backend.getASyncStarControllerConstructor()), |
| 57 safeVariableName: backend.namer.safeVariableName, |
| 58 yieldExpression: backend.emitter.staticFunctionAccess( |
| 59 backend.getYieldSingle()), |
| 60 yieldStarExpression: backend.emitter.staticFunctionAccess( |
| 61 backend.getYieldStar())); |
| 62 } |
| 63 if (rewriter != null) { |
| 64 result = rewriter.rewrite(result); |
| 65 } |
| 66 } |
| 67 return result; |
23 } | 68 } |
24 | 69 |
25 Iterable<CompilerTask> get tasks { | 70 Iterable<CompilerTask> get tasks { |
26 return <CompilerTask>[builder, optimizer, generator]; | 71 return <CompilerTask>[builder, optimizer, generator]; |
27 } | 72 } |
28 } | 73 } |
29 | 74 |
30 /// A synthetic local variable only used with the SSA graph. | 75 /// A synthetic local variable only used with the SSA graph. |
31 /// | 76 /// |
32 /// For instance used for holding return value of function or the exception of a | 77 /// For instance used for holding return value of function or the exception of a |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 } | 400 } |
356 } | 401 } |
357 | 402 |
358 /** | 403 /** |
359 * Returns true if the local can be accessed directly. Boxed variables or | 404 * Returns true if the local can be accessed directly. Boxed variables or |
360 * captured variables that are stored in the closure-field return [:false:]. | 405 * captured variables that are stored in the closure-field return [:false:]. |
361 */ | 406 */ |
362 bool isAccessedDirectly(Local local) { | 407 bool isAccessedDirectly(Local local) { |
363 assert(local != null); | 408 assert(local != null); |
364 return !redirectionMapping.containsKey(local) | 409 return !redirectionMapping.containsKey(local) |
365 && !closureData.usedVariablesInTry.contains(local); | 410 && !closureData.variablesUsedInTryOrGenerator.contains(local); |
366 } | 411 } |
367 | 412 |
368 bool isStoredInClosureField(Local local) { | 413 bool isStoredInClosureField(Local local) { |
369 assert(local != null); | 414 assert(local != null); |
370 if (isAccessedDirectly(local)) return false; | 415 if (isAccessedDirectly(local)) return false; |
371 CapturedVariable redirectTarget = redirectionMapping[local]; | 416 CapturedVariable redirectTarget = redirectionMapping[local]; |
372 if (redirectTarget == null) return false; | 417 if (redirectTarget == null) return false; |
373 return redirectTarget is ClosureFieldElement; | 418 return redirectTarget is ClosureFieldElement; |
374 } | 419 } |
375 | 420 |
376 bool isBoxed(Local local) { | 421 bool isBoxed(Local local) { |
377 if (isAccessedDirectly(local)) return false; | 422 if (isAccessedDirectly(local)) return false; |
378 if (isStoredInClosureField(local)) return false; | 423 if (isStoredInClosureField(local)) return false; |
379 return redirectionMapping.containsKey(local); | 424 return redirectionMapping.containsKey(local); |
380 } | 425 } |
381 | 426 |
382 bool isUsedInTry(Local local) { | 427 bool isUsedInTryOrGenerator(Local local) { |
383 return closureData.usedVariablesInTry.contains(local); | 428 return closureData.variablesUsedInTryOrGenerator.contains(local); |
384 } | 429 } |
385 | 430 |
386 /** | 431 /** |
387 * Returns an [HInstruction] for the given element. If the element is | 432 * Returns an [HInstruction] for the given element. If the element is |
388 * boxed or stored in a closure then the method generates code to retrieve | 433 * boxed or stored in a closure then the method generates code to retrieve |
389 * the value. | 434 * the value. |
390 */ | 435 */ |
391 HInstruction readLocal(Local local) { | 436 HInstruction readLocal(Local local) { |
392 if (isAccessedDirectly(local)) { | 437 if (isAccessedDirectly(local)) { |
393 if (directLocals[local] == null) { | 438 if (directLocals[local] == null) { |
(...skipping 21 matching lines...) Expand all Loading... |
415 // accessed as direct local. Inside the nested closure the box is | 460 // accessed as direct local. Inside the nested closure the box is |
416 // accessed through a closure-field. | 461 // accessed through a closure-field. |
417 // Calling [readLocal] makes sure we generate the correct code to get | 462 // Calling [readLocal] makes sure we generate the correct code to get |
418 // the box. | 463 // the box. |
419 HInstruction box = readLocal(redirect.box); | 464 HInstruction box = readLocal(redirect.box); |
420 HInstruction lookup = new HFieldGet( | 465 HInstruction lookup = new HFieldGet( |
421 redirect, box, builder.getTypeOfCapturedVariable(redirect)); | 466 redirect, box, builder.getTypeOfCapturedVariable(redirect)); |
422 builder.add(lookup); | 467 builder.add(lookup); |
423 return lookup; | 468 return lookup; |
424 } else { | 469 } else { |
425 assert(isUsedInTry(local)); | 470 assert(isUsedInTryOrGenerator(local)); |
426 HLocalValue localValue = getLocal(local); | 471 HLocalValue localValue = getLocal(local); |
427 HInstruction instruction = new HLocalGet( | 472 HInstruction instruction = new HLocalGet( |
428 local, localValue, builder.backend.dynamicType); | 473 local, localValue, builder.backend.dynamicType); |
429 builder.add(instruction); | 474 builder.add(instruction); |
430 return instruction; | 475 return instruction; |
431 } | 476 } |
432 } | 477 } |
433 | 478 |
434 HInstruction readThis() { | 479 HInstruction readThis() { |
435 HInstruction res = readLocal(closureData.thisLocal); | 480 HInstruction res = readLocal(closureData.thisLocal); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 directLocals[local] = value; | 516 directLocals[local] = value; |
472 } else if (isBoxed(local)) { | 517 } else if (isBoxed(local)) { |
473 BoxFieldElement redirect = redirectionMapping[local]; | 518 BoxFieldElement redirect = redirectionMapping[local]; |
474 // The box itself could be captured, or be local. A local variable that | 519 // The box itself could be captured, or be local. A local variable that |
475 // is captured will be boxed, but the box itself will be a local. | 520 // is captured will be boxed, but the box itself will be a local. |
476 // Inside the closure the box is stored in a closure-field and cannot | 521 // Inside the closure the box is stored in a closure-field and cannot |
477 // be accessed directly. | 522 // be accessed directly. |
478 HInstruction box = readLocal(redirect.box); | 523 HInstruction box = readLocal(redirect.box); |
479 builder.add(new HFieldSet(redirect, box, value)); | 524 builder.add(new HFieldSet(redirect, box, value)); |
480 } else { | 525 } else { |
481 assert(isUsedInTry(local)); | 526 assert(isUsedInTryOrGenerator(local)); |
482 HLocalValue localValue = getLocal(local); | 527 HLocalValue localValue = getLocal(local); |
483 builder.add(new HLocalSet(local, localValue, value)); | 528 builder.add(new HLocalSet(local, localValue, value)); |
484 } | 529 } |
485 } | 530 } |
486 | 531 |
487 /** | 532 /** |
488 * This function, startLoop, must be called before visiting any children of | 533 * This function, startLoop, must be called before visiting any children of |
489 * the loop. In particular it needs to be called before executing the | 534 * the loop. In particular it needs to be called before executing the |
490 * initializers. | 535 * initializers. |
491 * | 536 * |
(...skipping 4665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5157 visitThrow(ast.Throw node) { | 5202 visitThrow(ast.Throw node) { |
5158 visitThrowExpression(node.expression); | 5203 visitThrowExpression(node.expression); |
5159 if (isReachable) { | 5204 if (isReachable) { |
5160 handleInTryStatement(); | 5205 handleInTryStatement(); |
5161 push(new HThrowExpression(pop())); | 5206 push(new HThrowExpression(pop())); |
5162 isReachable = false; | 5207 isReachable = false; |
5163 } | 5208 } |
5164 } | 5209 } |
5165 | 5210 |
5166 visitYield(ast.Yield node) { | 5211 visitYield(ast.Yield node) { |
5167 // Dummy implementation. | |
5168 visit(node.expression); | 5212 visit(node.expression); |
5169 pop(); | 5213 HInstruction yielded = pop(); |
| 5214 add(new HYield(yielded, node.hasStar)); |
5170 } | 5215 } |
5171 | 5216 |
5172 visitAwait(ast.Await node) { | 5217 visitAwait(ast.Await node) { |
5173 // Dummy implementation. | |
5174 visit(node.expression); | 5218 visit(node.expression); |
| 5219 HInstruction awaited = pop(); |
| 5220 // TODO(herhut): Improve this type. |
| 5221 push(new HAwait(awaited, new TypeMask.subclass(compiler.objectClass, |
| 5222 compiler.world))); |
5175 } | 5223 } |
5176 | 5224 |
5177 visitTypeAnnotation(ast.TypeAnnotation node) { | 5225 visitTypeAnnotation(ast.TypeAnnotation node) { |
5178 compiler.internalError(node, | 5226 compiler.internalError(node, |
5179 'Visiting type annotation in SSA builder.'); | 5227 'Visiting type annotation in SSA builder.'); |
5180 } | 5228 } |
5181 | 5229 |
5182 visitVariableDefinitions(ast.VariableDefinitions node) { | 5230 visitVariableDefinitions(ast.VariableDefinitions node) { |
5183 assert(isReachable); | 5231 assert(isReachable); |
5184 for (Link<ast.Node> link = node.definitions.nodes; | 5232 for (Link<ast.Node> link = node.definitions.nodes; |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5308 return new NullJumpHandler(compiler); | 5356 return new NullJumpHandler(compiler); |
5309 } | 5357 } |
5310 if (isLoopJump && node is ast.SwitchStatement) { | 5358 if (isLoopJump && node is ast.SwitchStatement) { |
5311 // Create a special jump handler for loops created for switch statements | 5359 // Create a special jump handler for loops created for switch statements |
5312 // with continue statements. | 5360 // with continue statements. |
5313 return new SwitchCaseJumpHandler(this, element, node); | 5361 return new SwitchCaseJumpHandler(this, element, node); |
5314 } | 5362 } |
5315 return new JumpHandler(this, element); | 5363 return new JumpHandler(this, element); |
5316 } | 5364 } |
5317 | 5365 |
| 5366 buildAsyncForIn(ast.ForIn node) { |
| 5367 assert(node.isAsync); |
| 5368 // The async-for is implemented with a StreamIterator. |
| 5369 HInstruction streamIterator; |
| 5370 |
| 5371 visit(node.expression); |
| 5372 HInstruction expression = pop(); |
| 5373 pushInvokeStatic(node, |
| 5374 backend.getStreamIteratorConstructor(), |
| 5375 [expression, graph.addConstantNull(compiler)]); |
| 5376 streamIterator = pop(); |
| 5377 |
| 5378 void buildInitializer() {} |
| 5379 |
| 5380 HInstruction buildCondition() { |
| 5381 Selector selector = elements.getMoveNextSelector(node); |
| 5382 pushInvokeDynamic(node, selector, [streamIterator]); |
| 5383 HInstruction future = pop(); |
| 5384 push(new HAwait(future, new TypeMask.subclass(compiler.objectClass, |
| 5385 compiler.world))); |
| 5386 return popBoolified(); |
| 5387 } |
| 5388 void buildBody() { |
| 5389 Selector call = elements.getCurrentSelector(node); |
| 5390 pushInvokeDynamic(node, call, [streamIterator]); |
| 5391 |
| 5392 ast.Node identifier = node.declaredIdentifier; |
| 5393 Element variable = elements.getForInVariable(node); |
| 5394 Selector selector = elements.getSelector(identifier); |
| 5395 |
| 5396 HInstruction value = pop(); |
| 5397 if (identifier.asSend() != null |
| 5398 && Elements.isInstanceSend(identifier, elements)) { |
| 5399 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 5400 assert(receiver != null); |
| 5401 generateInstanceSetterWithCompiledReceiver( |
| 5402 null, |
| 5403 receiver, |
| 5404 value, |
| 5405 selector: selector, |
| 5406 location: identifier); |
| 5407 } else { |
| 5408 generateNonInstanceSetter( |
| 5409 null, variable, value, location: identifier); |
| 5410 } |
| 5411 pop(); // Pop the value pushed by the setter call. |
| 5412 |
| 5413 visit(node.body); |
| 5414 } |
| 5415 |
| 5416 void buildUpdate() {}; |
| 5417 |
| 5418 buildProtectedByFinally(() { |
| 5419 handleLoop(node, |
| 5420 buildInitializer, |
| 5421 buildCondition, |
| 5422 buildUpdate, |
| 5423 buildBody); |
| 5424 }, () { |
| 5425 pushInvokeDynamic(node, new Selector.call("cancel", null, 0), |
| 5426 [streamIterator]); |
| 5427 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, |
| 5428 compiler.world))); |
| 5429 pop(); |
| 5430 }); |
| 5431 } |
| 5432 |
5318 visitForIn(ast.ForIn node) { | 5433 visitForIn(ast.ForIn node) { |
| 5434 if (node.isAsync) { |
| 5435 return buildAsyncForIn(node); |
| 5436 } |
| 5437 |
5319 // Generate a structure equivalent to: | 5438 // Generate a structure equivalent to: |
5320 // Iterator<E> $iter = <iterable>.iterator; | 5439 // Iterator<E> $iter = <iterable>.iterator; |
5321 // while ($iter.moveNext()) { | 5440 // while ($iter.moveNext()) { |
5322 // E <declaredIdentifier> = $iter.current; | 5441 // E <declaredIdentifier> = $iter.current; |
5323 // <body> | 5442 // <body> |
5324 // } | 5443 // } |
5325 | 5444 |
5326 // The iterator is shared between initializer, condition and body. | 5445 // The iterator is shared between initializer, condition and body. |
5327 HInstruction iterator; | 5446 HInstruction iterator; |
5328 void buildInitializer() { | 5447 void buildInitializer() { |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5844 } | 5963 } |
5845 | 5964 |
5846 visitSwitchCase(ast.SwitchCase node) { | 5965 visitSwitchCase(ast.SwitchCase node) { |
5847 compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); | 5966 compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); |
5848 } | 5967 } |
5849 | 5968 |
5850 visitCaseMatch(ast.CaseMatch node) { | 5969 visitCaseMatch(ast.CaseMatch node) { |
5851 compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.'); | 5970 compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.'); |
5852 } | 5971 } |
5853 | 5972 |
| 5973 /// Calls [buildTry] inside a synthetic try block with [buildFinally] in the |
| 5974 /// finally block. |
| 5975 void buildProtectedByFinally(void buildTry(), void buildFinally()) { |
| 5976 HBasicBlock enterBlock = openNewBlock(); |
| 5977 HTry tryInstruction = new HTry(); |
| 5978 close(tryInstruction); |
| 5979 bool oldInTryStatement = inTryStatement; |
| 5980 inTryStatement = true; |
| 5981 |
| 5982 HBasicBlock startTryBlock; |
| 5983 HBasicBlock endTryBlock; |
| 5984 HBasicBlock startFinallyBlock; |
| 5985 HBasicBlock endFinallyBlock; |
| 5986 |
| 5987 startTryBlock = graph.addNewBlock(); |
| 5988 open(startTryBlock); |
| 5989 buildTry(); |
| 5990 // We use a [HExitTry] instead of a [HGoto] for the try block |
| 5991 // because it will have two successors: the join block, and |
| 5992 // the finally block. |
| 5993 if (!isAborted()) endTryBlock = close(new HExitTry()); |
| 5994 SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock); |
| 5995 |
| 5996 SubGraph finallyGraph = null; |
| 5997 |
| 5998 startFinallyBlock = graph.addNewBlock(); |
| 5999 open(startFinallyBlock); |
| 6000 buildFinally(); |
| 6001 if (!isAborted()) endFinallyBlock = close(new HGoto()); |
| 6002 tryInstruction.finallyBlock = startFinallyBlock; |
| 6003 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); |
| 6004 |
| 6005 HBasicBlock exitBlock = graph.addNewBlock(); |
| 6006 |
| 6007 void addExitTrySuccessor(HBasicBlock successor) { |
| 6008 // Iterate over all blocks created inside this try/catch, and |
| 6009 // attach successor information to blocks that end with |
| 6010 // [HExitTry]. |
| 6011 for (int i = startTryBlock.id; i < successor.id; i++) { |
| 6012 HBasicBlock block = graph.blocks[i]; |
| 6013 var last = block.last; |
| 6014 if (last is HExitTry) { |
| 6015 block.addSuccessor(successor); |
| 6016 } |
| 6017 } |
| 6018 } |
| 6019 |
| 6020 // Setup all successors. The entry block that contains the [HTry] |
| 6021 // has 1) the body 2) the finally, and 4) the exit |
| 6022 // blocks as successors. |
| 6023 enterBlock.addSuccessor(startTryBlock); |
| 6024 enterBlock.addSuccessor(startFinallyBlock); |
| 6025 enterBlock.addSuccessor(exitBlock); |
| 6026 |
| 6027 // The body has the finally block as successor. |
| 6028 if (endTryBlock != null) { |
| 6029 endTryBlock.addSuccessor(startFinallyBlock); |
| 6030 endTryBlock.addSuccessor(exitBlock); |
| 6031 } |
| 6032 |
| 6033 // The finally block has the exit block as successor. |
| 6034 endFinallyBlock.addSuccessor(exitBlock); |
| 6035 |
| 6036 // If a block inside try/catch aborts (eg with a return statement), |
| 6037 // we explicitely mark this block a predecessor of the catch |
| 6038 // block and the finally block. |
| 6039 addExitTrySuccessor(startFinallyBlock); |
| 6040 |
| 6041 open(exitBlock); |
| 6042 enterBlock.setBlockFlow( |
| 6043 new HTryBlockInformation( |
| 6044 wrapStatementGraph(bodyGraph), |
| 6045 null, // No catch-variable. |
| 6046 null, // No catchGraph. |
| 6047 wrapStatementGraph(finallyGraph)), |
| 6048 exitBlock); |
| 6049 inTryStatement = oldInTryStatement; |
| 6050 } |
| 6051 |
5854 visitTryStatement(ast.TryStatement node) { | 6052 visitTryStatement(ast.TryStatement node) { |
5855 // Save the current locals. The catch block and the finally block | 6053 // Save the current locals. The catch block and the finally block |
5856 // must not reuse the existing locals handler. None of the variables | 6054 // must not reuse the existing locals handler. None of the variables |
5857 // that have been defined in the body-block will be used, but for | 6055 // that have been defined in the body-block will be used, but for |
5858 // loops we will add (unnecessary) phis that will reference the body | 6056 // loops we will add (unnecessary) phis that will reference the body |
5859 // variables. This makes it look as if the variables were used | 6057 // variables. This makes it look as if the variables were used |
5860 // in a non-dominated block. | 6058 // in a non-dominated block. |
5861 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 6059 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
5862 HBasicBlock enterBlock = openNewBlock(); | 6060 HBasicBlock enterBlock = openNewBlock(); |
5863 HTry tryInstruction = new HTry(); | 6061 HTry tryInstruction = new HTry(); |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6215 this.allowLoops); | 6413 this.allowLoops); |
6216 | 6414 |
6217 static bool canBeInlined(ast.FunctionExpression functionExpression, | 6415 static bool canBeInlined(ast.FunctionExpression functionExpression, |
6218 int maxInliningNodes, | 6416 int maxInliningNodes, |
6219 bool useMaxInliningNodes, | 6417 bool useMaxInliningNodes, |
6220 {bool allowLoops: false}) { | 6418 {bool allowLoops: false}) { |
6221 InlineWeeder weeder = | 6419 InlineWeeder weeder = |
6222 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); | 6420 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); |
6223 weeder.visit(functionExpression.initializers); | 6421 weeder.visit(functionExpression.initializers); |
6224 weeder.visit(functionExpression.body); | 6422 weeder.visit(functionExpression.body); |
| 6423 weeder.visit(functionExpression.asyncModifier); |
6225 return !weeder.tooDifficult; | 6424 return !weeder.tooDifficult; |
6226 } | 6425 } |
6227 | 6426 |
6228 bool registerNode() { | 6427 bool registerNode() { |
6229 if (!useMaxInliningNodes) return true; | 6428 if (!useMaxInliningNodes) return true; |
6230 if (nodeCount++ > maxInliningNodes) { | 6429 if (nodeCount++ > maxInliningNodes) { |
6231 tooDifficult = true; | 6430 tooDifficult = true; |
6232 return false; | 6431 return false; |
6233 } else { | 6432 } else { |
6234 return true; | 6433 return true; |
6235 } | 6434 } |
6236 } | 6435 } |
6237 | 6436 |
6238 void visit(ast.Node node) { | 6437 void visit(ast.Node node) { |
6239 if (node != null) node.accept(this); | 6438 if (node != null) node.accept(this); |
6240 } | 6439 } |
6241 | 6440 |
6242 void visitNode(ast.Node node) { | 6441 void visitNode(ast.Node node) { |
6243 if (!registerNode()) return; | 6442 if (!registerNode()) return; |
6244 if (seenReturn) { | 6443 if (seenReturn) { |
6245 tooDifficult = true; | 6444 tooDifficult = true; |
6246 } else { | 6445 } else { |
6247 node.visitChildren(this); | 6446 node.visitChildren(this); |
6248 } | 6447 } |
6249 } | 6448 } |
6250 | 6449 |
| 6450 @override |
| 6451 void visitAsyncModifier(ast.AsyncModifier node) { |
| 6452 if (node.isYielding || node.isAsynchronous) { |
| 6453 tooDifficult = true; |
| 6454 } |
| 6455 } |
| 6456 |
6251 void visitFunctionExpression(ast.Node node) { | 6457 void visitFunctionExpression(ast.Node node) { |
6252 if (!registerNode()) return; | 6458 if (!registerNode()) return; |
6253 tooDifficult = true; | 6459 tooDifficult = true; |
6254 } | 6460 } |
6255 | 6461 |
6256 void visitFunctionDeclaration(ast.Node node) { | 6462 void visitFunctionDeclaration(ast.Node node) { |
6257 if (!registerNode()) return; | 6463 if (!registerNode()) return; |
6258 tooDifficult = true; | 6464 tooDifficult = true; |
6259 } | 6465 } |
6260 | 6466 |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6670 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 6876 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
6671 unaliased.accept(this, builder); | 6877 unaliased.accept(this, builder); |
6672 } | 6878 } |
6673 | 6879 |
6674 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 6880 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
6675 JavaScriptBackend backend = builder.compiler.backend; | 6881 JavaScriptBackend backend = builder.compiler.backend; |
6676 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 6882 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
6677 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 6883 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
6678 } | 6884 } |
6679 } | 6885 } |
OLD | NEW |