Chromium Code Reviews| 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) { | |
|
floitsch
2015/02/02 22:00:10
For another CL: the FunctionCompiler should *not*
sigurdm
2015/02/03 16:59:31
Acknowledged.
| |
| 25 JavaScriptBackend backend = builder.backend; | |
| 26 if (element.asyncMarker == AsyncMarker.ASYNC) { | |
| 27 result = new AsyncRewriter( | |
| 28 thenHelper: | |
| 29 backend.emitter.staticFunctionAccess(backend.getThenHelper()), | |
| 30 newController: new js.New(backend.emitter.staticFunctionAccess( | |
| 31 backend.getCompleterConstructor()), []), | |
| 32 safeVariableName: backend.namer.safeVariableName) | |
| 33 .rewrite(result); | |
|
floitsch
2015/02/02 22:00:11
The "rewrite" drowns in the whole expression.
Crea
sigurdm
2015/02/03 16:59:31
Done.
| |
| 34 } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) { | |
| 35 result = new AsyncRewriter( | |
| 36 endOfIteration: backend.emitter.staticFunctionAccess( | |
| 37 backend.getEndOfIteration()), | |
| 38 newIterable: backend.emitter.staticFunctionAccess( | |
| 39 backend.getSyncStarIterableConstructor()), | |
| 40 yieldStarExpression: backend.emitter.staticFunctionAccess( | |
| 41 backend.getSyncStarYieldStar()), | |
| 42 safeVariableName: backend.namer.safeVariableName) | |
| 43 .rewrite(result); | |
| 44 } | |
| 45 else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) { | |
| 46 result = new AsyncRewriter( | |
| 47 thenHelper: backend.emitter.staticFunctionAccess( | |
| 48 backend.getStreamHelper()), | |
| 49 newController: new js.Call(backend.emitter.staticFunctionAccess( | |
| 50 backend.getMakeController()), []), | |
| 51 safeVariableName: backend.namer.safeVariableName, | |
| 52 yieldExpression: backend.emitter.staticFunctionAccess( | |
| 53 backend.getYieldSingle())) | |
| 54 .rewrite(result); | |
| 55 } | |
| 56 } | |
| 57 return result; | |
| 23 } | 58 } |
| 24 | 59 |
| 25 Iterable<CompilerTask> get tasks { | 60 Iterable<CompilerTask> get tasks { |
| 26 return <CompilerTask>[builder, optimizer, generator]; | 61 return <CompilerTask>[builder, optimizer, generator]; |
| 27 } | 62 } |
| 28 } | 63 } |
| 29 | 64 |
| 30 /// A synthetic local variable only used with the SSA graph. | 65 /// A synthetic local variable only used with the SSA graph. |
| 31 /// | 66 /// |
| 32 /// For instance used for holding return value of function or the exception of a | 67 /// 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 } | 390 } |
| 356 } | 391 } |
| 357 | 392 |
| 358 /** | 393 /** |
| 359 * Returns true if the local can be accessed directly. Boxed variables or | 394 * Returns true if the local can be accessed directly. Boxed variables or |
| 360 * captured variables that are stored in the closure-field return [:false:]. | 395 * captured variables that are stored in the closure-field return [:false:]. |
| 361 */ | 396 */ |
| 362 bool isAccessedDirectly(Local local) { | 397 bool isAccessedDirectly(Local local) { |
| 363 assert(local != null); | 398 assert(local != null); |
| 364 return !redirectionMapping.containsKey(local) | 399 return !redirectionMapping.containsKey(local) |
| 365 && !closureData.usedVariablesInTry.contains(local); | 400 && !closureData.variablesUsedInTryOrGenerator.contains(local); |
| 366 } | 401 } |
| 367 | 402 |
| 368 bool isStoredInClosureField(Local local) { | 403 bool isStoredInClosureField(Local local) { |
| 369 assert(local != null); | 404 assert(local != null); |
| 370 if (isAccessedDirectly(local)) return false; | 405 if (isAccessedDirectly(local)) return false; |
| 371 CapturedVariable redirectTarget = redirectionMapping[local]; | 406 CapturedVariable redirectTarget = redirectionMapping[local]; |
| 372 if (redirectTarget == null) return false; | 407 if (redirectTarget == null) return false; |
| 373 return redirectTarget is ClosureFieldElement; | 408 return redirectTarget is ClosureFieldElement; |
| 374 } | 409 } |
| 375 | 410 |
| 376 bool isBoxed(Local local) { | 411 bool isBoxed(Local local) { |
| 377 if (isAccessedDirectly(local)) return false; | 412 if (isAccessedDirectly(local)) return false; |
| 378 if (isStoredInClosureField(local)) return false; | 413 if (isStoredInClosureField(local)) return false; |
| 379 return redirectionMapping.containsKey(local); | 414 return redirectionMapping.containsKey(local); |
| 380 } | 415 } |
| 381 | 416 |
| 382 bool isUsedInTry(Local local) { | 417 bool isUsedInTryOrGenerator(Local local) { |
| 383 return closureData.usedVariablesInTry.contains(local); | 418 return closureData.variablesUsedInTryOrGenerator.contains(local); |
| 384 } | 419 } |
| 385 | 420 |
| 386 /** | 421 /** |
| 387 * Returns an [HInstruction] for the given element. If the element is | 422 * 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 | 423 * boxed or stored in a closure then the method generates code to retrieve |
| 389 * the value. | 424 * the value. |
| 390 */ | 425 */ |
| 391 HInstruction readLocal(Local local) { | 426 HInstruction readLocal(Local local) { |
| 392 if (isAccessedDirectly(local)) { | 427 if (isAccessedDirectly(local)) { |
| 393 if (directLocals[local] == null) { | 428 if (directLocals[local] == null) { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 415 // accessed as direct local. Inside the nested closure the box is | 450 // accessed as direct local. Inside the nested closure the box is |
| 416 // accessed through a closure-field. | 451 // accessed through a closure-field. |
| 417 // Calling [readLocal] makes sure we generate the correct code to get | 452 // Calling [readLocal] makes sure we generate the correct code to get |
| 418 // the box. | 453 // the box. |
| 419 HInstruction box = readLocal(redirect.box); | 454 HInstruction box = readLocal(redirect.box); |
| 420 HInstruction lookup = new HFieldGet( | 455 HInstruction lookup = new HFieldGet( |
| 421 redirect, box, builder.getTypeOfCapturedVariable(redirect)); | 456 redirect, box, builder.getTypeOfCapturedVariable(redirect)); |
| 422 builder.add(lookup); | 457 builder.add(lookup); |
| 423 return lookup; | 458 return lookup; |
| 424 } else { | 459 } else { |
| 425 assert(isUsedInTry(local)); | 460 assert(isUsedInTryOrGenerator(local)); |
| 426 HLocalValue localValue = getLocal(local); | 461 HLocalValue localValue = getLocal(local); |
| 427 HInstruction instruction = new HLocalGet( | 462 HInstruction instruction = new HLocalGet( |
| 428 local, localValue, builder.backend.dynamicType); | 463 local, localValue, builder.backend.dynamicType); |
| 429 builder.add(instruction); | 464 builder.add(instruction); |
| 430 return instruction; | 465 return instruction; |
| 431 } | 466 } |
| 432 } | 467 } |
| 433 | 468 |
| 434 HInstruction readThis() { | 469 HInstruction readThis() { |
| 435 HInstruction res = readLocal(closureData.thisLocal); | 470 HInstruction res = readLocal(closureData.thisLocal); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 471 directLocals[local] = value; | 506 directLocals[local] = value; |
| 472 } else if (isBoxed(local)) { | 507 } else if (isBoxed(local)) { |
| 473 BoxFieldElement redirect = redirectionMapping[local]; | 508 BoxFieldElement redirect = redirectionMapping[local]; |
| 474 // The box itself could be captured, or be local. A local variable that | 509 // 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. | 510 // 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 | 511 // Inside the closure the box is stored in a closure-field and cannot |
| 477 // be accessed directly. | 512 // be accessed directly. |
| 478 HInstruction box = readLocal(redirect.box); | 513 HInstruction box = readLocal(redirect.box); |
| 479 builder.add(new HFieldSet(redirect, box, value)); | 514 builder.add(new HFieldSet(redirect, box, value)); |
| 480 } else { | 515 } else { |
| 481 assert(isUsedInTry(local)); | 516 assert(isUsedInTryOrGenerator(local)); |
| 482 HLocalValue localValue = getLocal(local); | 517 HLocalValue localValue = getLocal(local); |
| 483 builder.add(new HLocalSet(local, localValue, value)); | 518 builder.add(new HLocalSet(local, localValue, value)); |
| 484 } | 519 } |
| 485 } | 520 } |
| 486 | 521 |
| 487 /** | 522 /** |
| 488 * This function, startLoop, must be called before visiting any children of | 523 * This function, startLoop, must be called before visiting any children of |
| 489 * the loop. In particular it needs to be called before executing the | 524 * the loop. In particular it needs to be called before executing the |
| 490 * initializers. | 525 * initializers. |
| 491 * | 526 * |
| (...skipping 4665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5157 visitThrow(ast.Throw node) { | 5192 visitThrow(ast.Throw node) { |
| 5158 visitThrowExpression(node.expression); | 5193 visitThrowExpression(node.expression); |
| 5159 if (isReachable) { | 5194 if (isReachable) { |
| 5160 handleInTryStatement(); | 5195 handleInTryStatement(); |
| 5161 push(new HThrowExpression(pop())); | 5196 push(new HThrowExpression(pop())); |
| 5162 isReachable = false; | 5197 isReachable = false; |
| 5163 } | 5198 } |
| 5164 } | 5199 } |
| 5165 | 5200 |
| 5166 visitYield(ast.Yield node) { | 5201 visitYield(ast.Yield node) { |
| 5167 // Dummy implementation. | |
| 5168 visit(node.expression); | 5202 visit(node.expression); |
| 5203 HInstruction yielded = pop(); | |
| 5204 push(new HYield(yielded, node.hasStar)); | |
|
floitsch
2015/02/02 22:00:10
I think there is a function that does this. Maybe
sigurdm
2015/02/03 16:59:31
Right, add does it.
| |
| 5169 pop(); | 5205 pop(); |
| 5170 } | 5206 } |
| 5171 | 5207 |
| 5172 visitAwait(ast.Await node) { | 5208 visitAwait(ast.Await node) { |
| 5173 // Dummy implementation. | |
| 5174 visit(node.expression); | 5209 visit(node.expression); |
| 5210 HInstruction awaited = pop(); | |
| 5211 // TODO(herhut): Improve this type. | |
| 5212 push(new HAwait(awaited, new TypeMask.subclass(compiler.objectClass, | |
| 5213 compiler.world))); | |
| 5175 } | 5214 } |
| 5176 | 5215 |
| 5177 visitTypeAnnotation(ast.TypeAnnotation node) { | 5216 visitTypeAnnotation(ast.TypeAnnotation node) { |
| 5178 compiler.internalError(node, | 5217 compiler.internalError(node, |
| 5179 'Visiting type annotation in SSA builder.'); | 5218 'Visiting type annotation in SSA builder.'); |
| 5180 } | 5219 } |
| 5181 | 5220 |
| 5182 visitVariableDefinitions(ast.VariableDefinitions node) { | 5221 visitVariableDefinitions(ast.VariableDefinitions node) { |
| 5183 assert(isReachable); | 5222 assert(isReachable); |
| 5184 for (Link<ast.Node> link = node.definitions.nodes; | 5223 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); | 5347 return new NullJumpHandler(compiler); |
| 5309 } | 5348 } |
| 5310 if (isLoopJump && node is ast.SwitchStatement) { | 5349 if (isLoopJump && node is ast.SwitchStatement) { |
| 5311 // Create a special jump handler for loops created for switch statements | 5350 // Create a special jump handler for loops created for switch statements |
| 5312 // with continue statements. | 5351 // with continue statements. |
| 5313 return new SwitchCaseJumpHandler(this, element, node); | 5352 return new SwitchCaseJumpHandler(this, element, node); |
| 5314 } | 5353 } |
| 5315 return new JumpHandler(this, element); | 5354 return new JumpHandler(this, element); |
| 5316 } | 5355 } |
| 5317 | 5356 |
| 5357 | |
|
floitsch
2015/02/02 22:00:10
no need for the new line.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5318 visitForIn(ast.ForIn node) { | 5358 visitForIn(ast.ForIn node) { |
| 5359 if (node.isAsync) { | |
|
floitsch
2015/02/02 22:00:10
Move the code into a separate function.
sigurdm
2015/02/03 16:59:32
Done.
| |
| 5360 // The async for is implemented with a StreamIterator. | |
|
floitsch
2015/02/02 22:00:10
async-for
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5361 HInstruction streamIterator; | |
| 5362 | |
| 5363 visit(node.expression); | |
| 5364 HInstruction expression = pop(); | |
| 5365 pushInvokeStatic(node, | |
| 5366 backend.getStreamIteratorConstructor(), | |
| 5367 [expression, graph.addConstantNull(compiler)]); | |
| 5368 streamIterator = pop(); | |
| 5369 void buildInitializer() { | |
|
floitsch
2015/02/02 22:00:11
nested functions should have a new line before and
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5370 } | |
| 5371 HInstruction buildCondition() { | |
| 5372 Selector selector = elements.getMoveNextSelector(node); | |
| 5373 pushInvokeDynamic(node, selector, [streamIterator]); | |
| 5374 HInstruction future = pop(); | |
| 5375 push(new HAwait(future, new TypeMask.subclass(compiler.objectClass, | |
| 5376 compiler.world))); | |
| 5377 return popBoolified(); | |
| 5378 } | |
| 5379 void buildBody() { | |
| 5380 Selector call = elements.getCurrentSelector(node); | |
| 5381 pushInvokeDynamic(node, call, [streamIterator]); | |
| 5382 | |
| 5383 ast.Node identifier = node.declaredIdentifier; | |
| 5384 Element variable = elements.getForInVariable(node); | |
| 5385 Selector selector = elements.getSelector(identifier); | |
| 5386 | |
| 5387 HInstruction value = pop(); | |
| 5388 if (identifier.asSend() != null | |
| 5389 && Elements.isInstanceSend(identifier, elements)) { | |
| 5390 HInstruction receiver = generateInstanceSendReceiver(identifier); | |
| 5391 assert(receiver != null); | |
| 5392 generateInstanceSetterWithCompiledReceiver( | |
| 5393 null, | |
| 5394 receiver, | |
| 5395 value, | |
| 5396 selector: selector, | |
| 5397 location: identifier); | |
| 5398 } else { | |
| 5399 generateNonInstanceSetter( | |
| 5400 null, variable, value, location: identifier); | |
| 5401 } | |
| 5402 pop(); // Pop the value pushed by the setter call. | |
| 5403 | |
| 5404 visit(node.body); | |
| 5405 } | |
| 5406 buildProtected(() { | |
| 5407 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); | |
|
floitsch
2015/02/02 22:00:10
Since you already give a name to the buildInitiali
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5408 }, () { | |
| 5409 pushInvokeDynamic(node, new Selector.call("cancel", null, 0), | |
| 5410 [streamIterator]); | |
| 5411 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, | |
| 5412 compiler.world))); | |
| 5413 pop(); | |
| 5414 }); | |
| 5415 return; | |
| 5416 } | |
| 5417 | |
| 5319 // Generate a structure equivalent to: | 5418 // Generate a structure equivalent to: |
| 5320 // Iterator<E> $iter = <iterable>.iterator; | 5419 // Iterator<E> $iter = <iterable>.iterator; |
| 5321 // while ($iter.moveNext()) { | 5420 // while ($iter.moveNext()) { |
| 5322 // E <declaredIdentifier> = $iter.current; | 5421 // E <declaredIdentifier> = $iter.current; |
| 5323 // <body> | 5422 // <body> |
| 5324 // } | 5423 // } |
| 5325 | 5424 |
| 5326 // The iterator is shared between initializer, condition and body. | 5425 // The iterator is shared between initializer, condition and body. |
| 5327 HInstruction iterator; | 5426 HInstruction iterator; |
| 5328 void buildInitializer() { | 5427 void buildInitializer() { |
| (...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5844 } | 5943 } |
| 5845 | 5944 |
| 5846 visitSwitchCase(ast.SwitchCase node) { | 5945 visitSwitchCase(ast.SwitchCase node) { |
| 5847 compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); | 5946 compiler.internalError(node, 'SsaFromAstMixin.visitSwitchCase.'); |
| 5848 } | 5947 } |
| 5849 | 5948 |
| 5850 visitCaseMatch(ast.CaseMatch node) { | 5949 visitCaseMatch(ast.CaseMatch node) { |
| 5851 compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.'); | 5950 compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.'); |
| 5852 } | 5951 } |
| 5853 | 5952 |
| 5953 buildProtected(void buildTry(), void buildFinally()) { | |
|
floitsch
2015/02/02 22:00:11
return type.
Change name, since it's not a genera
sigurdm
2015/02/03 16:59:32
Done.
floitsch
2015/02/04 12:31:27
That's not what I meant.
If the buildProtected wor
| |
| 5954 // Save the current locals. The catch block and the finally block | |
| 5955 // must not reuse the existing locals handler. None of the variables | |
| 5956 // that have been defined in the body-block will be used, but for | |
| 5957 // loops we will add (unnecessary) phis that will reference the body | |
| 5958 // variables. This makes it look as if the variables were used | |
| 5959 // in a non-dominated block. | |
|
floitsch
2015/02/02 22:00:11
Does this comment apply for us?
Do we really need
sigurdm
2015/02/03 16:59:32
Not sure - I will ask
sigurdm
2015/02/04 11:43:39
I discussed with Karl, and you are right - it is o
floitsch
2015/02/04 12:31:27
I would say no, since the only variable that is us
| |
| 5960 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | |
| 5961 HBasicBlock enterBlock = openNewBlock(); | |
| 5962 HTry tryInstruction = new HTry(); | |
| 5963 close(tryInstruction); | |
| 5964 bool oldInTryStatement = inTryStatement; | |
| 5965 inTryStatement = true; | |
| 5966 | |
| 5967 HBasicBlock startTryBlock; | |
| 5968 HBasicBlock endTryBlock; | |
| 5969 HBasicBlock startFinallyBlock; | |
| 5970 HBasicBlock endFinallyBlock; | |
| 5971 | |
| 5972 startTryBlock = graph.addNewBlock(); | |
| 5973 open(startTryBlock); | |
| 5974 buildTry(); | |
| 5975 // We use a [HExitTry] instead of a [HGoto] for the try block | |
| 5976 // because it will have multiple successors: the join block, and | |
| 5977 // the catch or finally block. | |
|
floitsch
2015/02/02 22:00:10
It won't have any catch block.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5978 if (!isAborted()) endTryBlock = close(new HExitTry()); | |
| 5979 SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock); | |
| 5980 SubGraph catchGraph = null; | |
|
floitsch
2015/02/02 22:00:11
Remove variable.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5981 HLocalValue exception = null; | |
|
floitsch
2015/02/02 22:00:11
Remove (and inline) ?
sigurdm
2015/02/03 16:59:32
Done.
| |
| 5982 | |
| 5983 SubGraph finallyGraph = null; | |
| 5984 | |
| 5985 localsHandler = new LocalsHandler.from(savedLocals); | |
| 5986 startFinallyBlock = graph.addNewBlock(); | |
| 5987 open(startFinallyBlock); | |
| 5988 buildFinally(); | |
| 5989 if (!isAborted()) endFinallyBlock = close(new HGoto()); | |
| 5990 tryInstruction.finallyBlock = startFinallyBlock; | |
| 5991 finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock); | |
| 5992 | |
| 5993 HBasicBlock exitBlock = graph.addNewBlock(); | |
| 5994 | |
| 5995 addExitTrySuccessor(successor) { | |
|
floitsch
2015/02/02 22:00:10
add return type. (especially for nested functions)
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5996 if (successor == null) return; | |
|
floitsch
2015/02/02 22:00:10
Check should be unnecessary.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 5997 // Iterate over all blocks created inside this try/catch, and | |
| 5998 // attach successor information to blocks that end with | |
| 5999 // [HExitTry]. | |
| 6000 for (int i = startTryBlock.id; i < successor.id; i++) { | |
| 6001 HBasicBlock block = graph.blocks[i]; | |
| 6002 var last = block.last; | |
| 6003 if (last is HExitTry) { | |
| 6004 block.addSuccessor(successor); | |
| 6005 } | |
| 6006 } | |
| 6007 } | |
| 6008 | |
| 6009 // Setup all successors. The entry block that contains the [HTry] | |
| 6010 // has 1) the body, 2) the catch, 3) the finally, and 4) the exit | |
|
floitsch
2015/02/02 22:00:11
no catch.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 6011 // blocks as successors. | |
| 6012 enterBlock.addSuccessor(startTryBlock); | |
| 6013 enterBlock.addSuccessor(startFinallyBlock); | |
| 6014 enterBlock.addSuccessor(exitBlock); | |
| 6015 | |
| 6016 // The body has either the catch or the finally block as successor. | |
|
floitsch
2015/02/02 22:00:10
no catch.
sigurdm
2015/02/03 16:59:31
Done.
| |
| 6017 if (endTryBlock != null) { | |
| 6018 endTryBlock.addSuccessor(startFinallyBlock); | |
| 6019 endTryBlock.addSuccessor(exitBlock); | |
| 6020 } | |
| 6021 | |
| 6022 // The finally block has the exit block as successor. | |
| 6023 endFinallyBlock.addSuccessor(exitBlock); | |
| 6024 | |
| 6025 // If a block inside try/catch aborts (eg with a return statement), | |
| 6026 // we explicitely mark this block a predecessor of the catch | |
| 6027 // block and the finally block. | |
| 6028 addExitTrySuccessor(startFinallyBlock); | |
| 6029 | |
| 6030 // Use the locals handler not altered by the catch and finally | |
| 6031 // blocks. | |
| 6032 localsHandler = savedLocals; | |
| 6033 open(exitBlock); | |
| 6034 enterBlock.setBlockFlow( | |
| 6035 new HTryBlockInformation( | |
| 6036 wrapStatementGraph(bodyGraph), | |
| 6037 exception, | |
| 6038 null, // No catchGraph | |
| 6039 wrapStatementGraph(finallyGraph)), | |
| 6040 exitBlock); | |
| 6041 inTryStatement = oldInTryStatement; | |
| 6042 } | |
| 6043 | |
| 5854 visitTryStatement(ast.TryStatement node) { | 6044 visitTryStatement(ast.TryStatement node) { |
| 5855 // Save the current locals. The catch block and the finally block | 6045 // Save the current locals. The catch block and the finally block |
| 5856 // must not reuse the existing locals handler. None of the variables | 6046 // 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 | 6047 // 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 | 6048 // loops we will add (unnecessary) phis that will reference the body |
| 5859 // variables. This makes it look as if the variables were used | 6049 // variables. This makes it look as if the variables were used |
| 5860 // in a non-dominated block. | 6050 // in a non-dominated block. |
| 5861 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 6051 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 5862 HBasicBlock enterBlock = openNewBlock(); | 6052 HBasicBlock enterBlock = openNewBlock(); |
| 5863 HTry tryInstruction = new HTry(); | 6053 HTry tryInstruction = new HTry(); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6038 enterBlock.setBlockFlow( | 6228 enterBlock.setBlockFlow( |
| 6039 new HTryBlockInformation( | 6229 new HTryBlockInformation( |
| 6040 wrapStatementGraph(bodyGraph), | 6230 wrapStatementGraph(bodyGraph), |
| 6041 exception, | 6231 exception, |
| 6042 wrapStatementGraph(catchGraph), | 6232 wrapStatementGraph(catchGraph), |
| 6043 wrapStatementGraph(finallyGraph)), | 6233 wrapStatementGraph(finallyGraph)), |
| 6044 exitBlock); | 6234 exitBlock); |
| 6045 inTryStatement = oldInTryStatement; | 6235 inTryStatement = oldInTryStatement; |
| 6046 } | 6236 } |
| 6047 | 6237 |
| 6238 | |
| 6048 visitCatchBlock(ast.CatchBlock node) { | 6239 visitCatchBlock(ast.CatchBlock node) { |
| 6049 visit(node.block); | 6240 visit(node.block); |
| 6050 } | 6241 } |
| 6051 | 6242 |
| 6052 visitTypedef(ast.Typedef node) { | 6243 visitTypedef(ast.Typedef node) { |
| 6053 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); | 6244 compiler.unimplemented(node, 'SsaFromAstMixin.visitTypedef.'); |
| 6054 } | 6245 } |
| 6055 | 6246 |
| 6056 visitTypeVariable(ast.TypeVariable node) { | 6247 visitTypeVariable(ast.TypeVariable node) { |
| 6057 compiler.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); | 6248 compiler.internalError(node, 'SsaFromAstMixin.visitTypeVariable.'); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6213 InlineWeeder(this.maxInliningNodes, | 6404 InlineWeeder(this.maxInliningNodes, |
| 6214 this.useMaxInliningNodes, | 6405 this.useMaxInliningNodes, |
| 6215 this.allowLoops); | 6406 this.allowLoops); |
| 6216 | 6407 |
| 6217 static bool canBeInlined(ast.FunctionExpression functionExpression, | 6408 static bool canBeInlined(ast.FunctionExpression functionExpression, |
| 6218 int maxInliningNodes, | 6409 int maxInliningNodes, |
| 6219 bool useMaxInliningNodes, | 6410 bool useMaxInliningNodes, |
| 6220 {bool allowLoops: false}) { | 6411 {bool allowLoops: false}) { |
| 6221 InlineWeeder weeder = | 6412 InlineWeeder weeder = |
| 6222 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); | 6413 new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops); |
| 6414 if (functionExpression.asyncModifier != null) return false; | |
| 6223 weeder.visit(functionExpression.initializers); | 6415 weeder.visit(functionExpression.initializers); |
| 6224 weeder.visit(functionExpression.body); | 6416 weeder.visit(functionExpression.body); |
| 6225 return !weeder.tooDifficult; | 6417 return !weeder.tooDifficult; |
| 6226 } | 6418 } |
| 6227 | 6419 |
| 6228 bool registerNode() { | 6420 bool registerNode() { |
| 6229 if (!useMaxInliningNodes) return true; | 6421 if (!useMaxInliningNodes) return true; |
| 6230 if (nodeCount++ > maxInliningNodes) { | 6422 if (nodeCount++ > maxInliningNodes) { |
| 6231 tooDifficult = true; | 6423 tooDifficult = true; |
| 6232 return false; | 6424 return false; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6299 void visitThrow(ast.Throw node) { | 6491 void visitThrow(ast.Throw node) { |
| 6300 if (!registerNode()) return; | 6492 if (!registerNode()) return; |
| 6301 // For now, we don't want to handle throw after a return even if | 6493 // For now, we don't want to handle throw after a return even if |
| 6302 // it is in an "if". | 6494 // it is in an "if". |
| 6303 if (seenReturn) { | 6495 if (seenReturn) { |
| 6304 tooDifficult = true; | 6496 tooDifficult = true; |
| 6305 } else { | 6497 } else { |
| 6306 node.visitChildren(this); | 6498 node.visitChildren(this); |
| 6307 } | 6499 } |
| 6308 } | 6500 } |
| 6501 | |
| 6502 void visitAwait(ast.Await node) { | |
| 6503 if (!registerNode()) return; | |
| 6504 tooDifficult = true; | |
|
floitsch
2015/02/02 22:00:10
How can this happen, when we already return if the
sigurdm
2015/02/03 16:59:32
Right - I added this one first, then realized that
| |
| 6505 } | |
| 6309 } | 6506 } |
| 6310 | 6507 |
| 6311 abstract class InliningState { | 6508 abstract class InliningState { |
| 6312 /** | 6509 /** |
| 6313 * Invariant: [function] must be an implementation element. | 6510 * Invariant: [function] must be an implementation element. |
| 6314 */ | 6511 */ |
| 6315 final FunctionElement function; | 6512 final FunctionElement function; |
| 6316 | 6513 |
| 6317 InliningState(this.function) { | 6514 InliningState(this.function) { |
| 6318 assert(function.isImplementation); | 6515 assert(function.isImplementation); |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6670 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 6867 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 6671 unaliased.accept(this, builder); | 6868 unaliased.accept(this, builder); |
| 6672 } | 6869 } |
| 6673 | 6870 |
| 6674 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 6871 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 6675 JavaScriptBackend backend = builder.compiler.backend; | 6872 JavaScriptBackend backend = builder.compiler.backend; |
| 6676 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 6873 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 6677 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 6874 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 6678 } | 6875 } |
| 6679 } | 6876 } |
| OLD | NEW |