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 class Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 122 } | 122 } |
| 123 new HTracer.singleton().traceCompilation(name); | 123 new HTracer.singleton().traceCompilation(name); |
| 124 new HTracer.singleton().traceGraph('builder', graph); | 124 new HTracer.singleton().traceGraph('builder', graph); |
| 125 } | 125 } |
| 126 return graph; | 126 return graph; |
| 127 }); | 127 }); |
| 128 } | 128 } |
| 129 | 129 |
| 130 HGraph compileConstructor(SsaBuilder builder, WorkItem work) { | 130 HGraph compileConstructor(SsaBuilder builder, WorkItem work) { |
| 131 // The body of the constructor will be generated in a separate function. | 131 // The body of the constructor will be generated in a separate function. |
| 132 ClassElement classElement = work.element.enclosingElement; | 132 final ClassElement classElement = work.element.enclosingElement; |
| 133 ConstructorBodyElement bodyElement; | 133 return builder.buildFactory(classElement, work.element); |
| 134 // In case of a bailout version, the constructor body has already | 134 } |
| 135 // been created. | 135 |
| 136 if (work.isBailoutVersion()) { | 136 HGraph compileConstructorBody(SsaBuilder builder, |
|
floitsch
2012/02/07 17:19:37
remove this method.
karlklose
2012/02/08 14:12:00
Done.
| |
| 137 for (Link<Element> backendMembers = classElement.backendMembers; | 137 FunctionElement element, |
| 138 !backendMembers.isEmpty(); | 138 TreeElements elements) { |
| 139 backendMembers = backendMembers.tail) { | 139 return builder.buildMethod(element); |
| 140 Element current = backendMembers.head; | 140 } |
| 141 if (current.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 141 |
| 142 ConstructorBodyElement temp = current; | 142 HGraph compileMethod(SsaBuilder builder, |
|
floitsch
2012/02/07 17:19:38
ditto.
karlklose
2012/02/08 14:12:00
Done.
| |
| 143 if (temp.constructor == work.element) { | 143 FunctionElement element, |
| 144 bodyElement = temp; | 144 TreeElements elements) { |
| 145 break; | 145 return builder.buildMethod(element); |
| 146 } | |
| 147 } | |
| 148 } | |
| 149 } else { | |
| 150 bodyElement = new ConstructorBodyElement(work.element); | |
| 151 compiler.enqueue( | |
| 152 new WorkItem.toCodegen(bodyElement, work.resolutionTree)); | |
| 153 classElement.backendMembers = | |
| 154 classElement.backendMembers.prepend(bodyElement); | |
| 155 } | |
| 156 // TODO(floitsch): pass initializer-list to builder. | |
| 157 return builder.buildFactory(classElement, bodyElement, work.element); | |
| 158 } | 146 } |
| 159 } | 147 } |
| 160 | 148 |
| 161 /** | 149 /** |
| 162 * Keeps track of locals (including parameters and phis) when building. The | 150 * Keeps track of locals (including parameters and phis) when building. The |
| 163 * 'this' reference is treated as parameter and hence handled by this class, | 151 * 'this' reference is treated as parameter and hence handled by this class, |
| 164 * too. | 152 * too. |
| 165 */ | 153 */ |
| 166 class LocalsHandler { | 154 class LocalsHandler { |
| 167 // The values of locals that can be directly accessed (without redirections | 155 // The values of locals that can be directly accessed (without redirections |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 joinBlock.addPhi(phi); | 392 joinBlock.addPhi(phi); |
| 405 joinedLocals[element] = phi; | 393 joinedLocals[element] = phi; |
| 406 } | 394 } |
| 407 }); | 395 }); |
| 408 directLocals = joinedLocals; | 396 directLocals = joinedLocals; |
| 409 } | 397 } |
| 410 } | 398 } |
| 411 | 399 |
| 412 class SsaBuilder implements Visitor { | 400 class SsaBuilder implements Visitor { |
| 413 final Compiler compiler; | 401 final Compiler compiler; |
| 414 final TreeElements elements; | 402 TreeElements elements; |
| 415 final Interceptors interceptors; | 403 final Interceptors interceptors; |
| 416 bool methodInterceptionEnabled; | 404 bool methodInterceptionEnabled; |
| 417 HGraph graph; | 405 HGraph graph; |
| 418 LocalsHandler localsHandler; | 406 LocalsHandler localsHandler; |
| 419 | 407 |
| 420 // We build the Ssa graph by simulating a stack machine. | 408 // We build the Ssa graph by simulating a stack machine. |
| 421 List<HInstruction> stack; | 409 List<HInstruction> stack; |
| 422 | 410 |
| 423 // The current block to add instructions to. Might be null, if we are | 411 // The current block to add instructions to. Might be null, if we are |
| 424 // visiting dead code. | 412 // visiting dead code. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 443 methodInterceptionEnabled = true; | 431 methodInterceptionEnabled = true; |
| 444 } | 432 } |
| 445 | 433 |
| 446 HGraph buildMethod(FunctionElement functionElement) { | 434 HGraph buildMethod(FunctionElement functionElement) { |
| 447 FunctionExpression function = functionElement.parseNode(compiler); | 435 FunctionExpression function = functionElement.parseNode(compiler); |
| 448 openFunction(functionElement, function); | 436 openFunction(functionElement, function); |
| 449 function.body.accept(this); | 437 function.body.accept(this); |
| 450 return closeFunction(); | 438 return closeFunction(); |
| 451 } | 439 } |
| 452 | 440 |
| 441 /** | |
| 442 * Returns the constructor body associated with the given constructor or | |
| 443 * creates a new constructor body, if none can be found. | |
| 444 */ | |
| 445 ConstructorBodyElement getConstructorBody(ClassElement classElement, | |
| 446 FunctionElement constructor) { | |
| 447 assert(constructor.kind === ElementKind.GENERATIVE_CONSTRUCTOR); | |
| 448 ConstructorBodyElement bodyElement; | |
| 449 for (Link<Element> backendMembers = classElement.backendMembers; | |
| 450 !backendMembers.isEmpty(); | |
| 451 backendMembers = backendMembers.tail) { | |
| 452 Element backendMember = backendMembers.head; | |
| 453 if (backendMember.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | |
| 454 ConstructorBodyElement body = backendMember; | |
| 455 if (body.constructor== constructor) { | |
|
ngeoffray
2012/02/07 14:25:59
space missing before '=='
karlklose
2012/02/08 14:12:00
Done.
| |
| 456 bodyElement = backendMember; | |
| 457 break; | |
| 458 } | |
| 459 } | |
| 460 } | |
| 461 if (bodyElement === null) { | |
| 462 bodyElement = new ConstructorBodyElement(constructor); | |
| 463 compiler.enqueue( | |
|
floitsch
2012/02/07 17:19:38
one line?
karlklose
2012/02/08 14:12:00
Done.
| |
| 464 new WorkItem.toCompile(bodyElement)); | |
| 465 classElement.backendMembers = | |
| 466 classElement.backendMembers.prepend(bodyElement); | |
| 467 } | |
| 468 assert(bodyElement !== null && | |
|
floitsch
2012/02/07 17:19:38
bodyElement is trivially non null.
I would remove
karlklose
2012/02/08 14:12:00
Done.
| |
| 469 bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); | |
| 470 return bodyElement; | |
| 471 } | |
| 472 | |
| 473 /** | |
| 474 * Call [forEach] for every argument and parameter and element of [target] | |
|
ngeoffray
2012/02/07 14:25:59
Shouldn't it just be 'argument'? If there are rema
karlklose
2012/02/08 14:12:00
Done. I do not use environments anymore, so addSta
| |
| 475 * that is used in the invocation [send]. | |
| 476 */ | |
| 477 forEachArgument(Send send, FunctionElement target, | |
| 478 forEach(VariableElement parameter, Node argument)) { | |
|
floitsch
2012/02/07 17:19:38
please name to something else. Even 'f' would be b
karlklose
2012/02/08 14:12:00
Done.
| |
| 479 final FunctionParameters parameters = target.computeParameters(compiler); | |
| 480 Link<Element> parameterElements = parameters.requiredParameters; | |
| 481 for (Link<Node> arguments = send.arguments; | |
| 482 !arguments.isEmpty(); | |
| 483 arguments = arguments.tail) { | |
| 484 if (parameterElements.isEmpty()) { | |
| 485 parameterElements = parameters.optionalParameters; | |
| 486 } | |
| 487 forEach(parameterElements.head, arguments.head); | |
| 488 parameterElements = parameterElements.tail; | |
| 489 }; | |
| 490 } | |
| 491 | |
| 492 /** | |
| 493 * Build the factory function corresponding to the constructor [bodyElement]: | |
|
floitsch
2012/02/07 17:19:38
s/bodyElement/functionElement.
karlklose
2012/02/08 14:12:00
Done.
| |
| 494 * - Initialize fields with the values of the field initializers of the | |
| 495 * current constructor and super constructors or constructors redirected | |
| 496 * to, starting from the current constructor. | |
| 497 * - Call the the constructor bodies, starting from the constructor(s) in the | |
| 498 * super class(es). | |
| 499 */ | |
| 453 HGraph buildFactory(ClassElement classElement, | 500 HGraph buildFactory(ClassElement classElement, |
| 454 ConstructorBodyElement bodyElement, | |
| 455 FunctionElement functionElement) { | 501 FunctionElement functionElement) { |
| 456 FunctionExpression function = functionElement.parseNode(compiler); | 502 FunctionExpression function = functionElement.parseNode(compiler); |
| 457 // The initializer list could contain closures. | 503 // The initializer list could contain closures. |
| 458 openFunction(functionElement, function); | 504 openFunction(functionElement, function); |
| 459 | 505 |
| 460 NodeList initializers = function.initializers; | 506 final Map<FunctionElement, TreeElements> constructorElements = |
|
ngeoffray
2012/02/07 14:25:59
Why is this one final and not the others? For cons
karlklose
2012/02/08 14:12:00
Done, I removed unused variables and the environme
| |
| 507 compiler.resolver.constructorElements; | |
| 508 List<FunctionElement> constructors = new List<FunctionElement>(); | |
| 509 Map<FunctionElement, List<HInstruction>> environments = | |
| 510 new Map<FunctionElement, List<HInstruction>>(); | |
|
ngeoffray
2012/02/07 14:25:59
If this method was a LinkedHashMap, would you need
karlklose
2012/02/08 14:12:00
see above.
| |
| 461 | 511 |
| 462 // Run through the initializers. | 512 // Prepare initial environment used to call body of this constructor. |
| 463 if (initializers !== null) { | 513 FunctionElement next = functionElement; |
|
ngeoffray
2012/02/07 14:25:59
next -> nextSuperCall ?
karlklose
2012/02/08 14:12:00
Changed to nextConstructor.
| |
| 514 List<HInstruction> initialEnvironment = new List<HInstruction>(); | |
| 515 functionElement.functionParameters.forEachParameter((parameter) { | |
| 516 initialEnvironment.addLast(localsHandler.readLocal(parameter)); | |
| 517 }); | |
|
ngeoffray
2012/02/07 14:25:59
strange indentation.
karlklose
2012/02/08 14:12:00
Removed.
| |
| 518 environments[functionElement] = initialEnvironment; | |
| 519 constructors.addLast(functionElement); | |
| 520 | |
| 521 // Analyze the constructor and all referenced constructors and collect | |
| 522 // initializers and constructor bodies. | |
| 523 while (next != null) { | |
| 524 final FunctionElement constructor = next; | |
| 525 next = null; | |
| 526 elements = compiler.resolver.resolveMethodElement(constructor); | |
| 527 compiler.enqueue(new WorkItem.toCompile(constructor)); | |
|
floitsch
2012/02/07 17:19:38
remove enqueuing here.
karlklose
2012/02/08 14:12:00
Done.
| |
| 528 final FunctionExpression functionNode = constructor.parseNode(compiler); | |
| 529 final NodeList initializers = functionNode.initializers; | |
| 530 | |
| 531 if (initializers === null) continue; | |
|
ngeoffray
2012/02/07 14:25:59
break?
floitsch
2012/02/07 17:19:38
We have to find the implicit super-constructor ins
karlklose
2012/02/08 14:12:00
Done.
karlklose
2012/02/08 14:12:00
Changed to set initializers to an empty list.
| |
| 532 | |
| 533 // Run through the initializers. Collect all field initializers and | |
| 534 // analyze referenced superinitializers and constructor redirections. | |
|
ngeoffray
2012/02/07 14:25:59
Maybe add a function for the code running through
karlklose
2012/02/08 14:12:00
Done.
| |
| 464 for (Link<Node> link = initializers.nodes; | 535 for (Link<Node> link = initializers.nodes; |
|
floitsch
2012/02/07 17:19:38
once you evaluate the initializers with the curren
karlklose
2012/02/08 14:12:00
Done.
| |
| 465 !link.isEmpty(); | 536 !link.isEmpty(); |
| 466 link = link.tail) { | 537 link = link.tail) { |
| 467 assert(link.head is Send); | 538 assert(link.head is Send); |
| 539 | |
| 468 if (link.head is !SendSet) { | 540 if (link.head is !SendSet) { |
| 469 compiler.unimplemented('SsaBuilder.buildFactory super-init'); | 541 Send call = link.head; |
| 542 // A super initializer or constructor redirection. | |
|
floitsch
2012/02/07 17:19:38
move comment one line up.
karlklose
2012/02/08 14:12:00
Done.
| |
| 543 if (Initializers.isSuperConstructorCall(link.head)) { | |
|
floitsch
2012/02/07 17:19:38
s/link.head/call
karlklose
2012/02/08 14:12:00
Done.
| |
| 544 FunctionElement superconstructor = elements[link.head]; | |
|
floitsch
2012/02/07 17:19:38
superConstructor and s/link.head/call.
karlklose
2012/02/08 14:12:00
Done.
| |
| 545 FunctionExpression superNode = superconstructor.parseNode(compiler); | |
|
ngeoffray
2012/02/07 14:25:59
Unused variable.
karlklose
2012/02/08 14:12:00
Done.
| |
| 546 List<HInstruction> environment = new List<HInstruction>(); | |
| 547 Link<Element> argumentElements = | |
| 548 superconstructor.functionParameters.requiredParameters; | |
|
ngeoffray
2012/02/07 14:25:59
This variable seems unnecessary.
karlklose
2012/02/08 14:12:00
Done.
| |
| 549 // Visit arguments and map the corresponding parameter value to | |
| 550 // the resulting HInstruction value. | |
| 551 forEachArgument(call, superconstructor, (parameter, node) { | |
| 552 visit(node); | |
| 553 HInstruction value = pop(); | |
| 554 updateElementDefinition(parameter, value); | |
| 555 // Store environment for invocation of constructor body. | |
| 556 environment.addLast(value); | |
| 557 argumentElements = argumentElements.tail; | |
| 558 }); | |
| 559 // Setup constructor and environment for later and process it next. | |
| 560 constructors.addLast(superconstructor); | |
| 561 environments[superconstructor] = environment; | |
| 562 next = superconstructor; | |
| 563 } else { | |
| 564 compiler.unimplemented('SsaBuilder.buildFactory redirect'); | |
| 565 } | |
| 470 } else { | 566 } else { |
| 567 // A field initializer. | |
| 471 SendSet init = link.head; | 568 SendSet init = link.head; |
| 472 Link<Node> arguments = init.arguments; | 569 Link<Node> arguments = init.arguments; |
| 473 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); | 570 assert(!arguments.isEmpty() && arguments.tail.isEmpty()); |
| 474 visit(arguments.head); | 571 visit(arguments.head); |
| 475 // We treat the init field-elements like locals. In the context of | 572 // We treat the init field-elements like locals. In the context of |
| 476 // the factory this is correct, and simplifies dealing with | 573 // the factory this is correct, and simplifies dealing with |
| 477 // parameter-initializers (like A(this.x)). | 574 // parameter-initializers (like A(this.x)). |
| 478 localsHandler.updateLocal(elements[init], pop()); | 575 localsHandler.updateLocal(elements[init], pop()); |
| 479 } | 576 } |
| 480 } | 577 } |
| 481 } | 578 } |
| 482 | |
| 483 // Call the JavaScript constructor with the fields as argument. | 579 // Call the JavaScript constructor with the fields as argument. |
| 484 // TODO(floitsch): allow super calls. | |
| 485 // TODO(floitsch): allow inits at field declarations. | |
| 486 List<HInstruction> constructorArguments = <HInstruction>[]; | 580 List<HInstruction> constructorArguments = <HInstruction>[]; |
| 487 for (Element member in classElement.members) { | 581 ClassElement element = classElement; |
| 488 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | 582 while (element != null) { |
|
floitsch
2012/02/07 17:19:38
add TODO to share this code with the emitter. Ther
karlklose
2012/02/08 14:12:00
Done.
| |
| 583 for (Element member in element.members) { | |
| 584 if (member.isInstanceMember() && member.kind == ElementKind.FIELD) { | |
| 489 HInstruction value; | 585 HInstruction value; |
| 490 if (localsHandler.hasValueForDirectLocal(member)) { | 586 if (localsHandler.hasValueForDirectLocal(member)) { |
| 491 value = localsHandler.readLocal(member); | 587 value = localsHandler.readLocal(member); |
| 492 } else { | 588 } else { |
| 493 value = new HLiteral(null, HType.UNKNOWN); | 589 value = new HLiteral(null, HType.UNKNOWN); |
|
floitsch
2012/02/07 17:19:38
Add TODO that we need to get the default-values if
karlklose
2012/02/08 14:12:00
Done.
| |
| 494 add(value); | 590 add(value); |
| 591 } | |
| 592 constructorArguments.add(value); | |
|
ngeoffray
2012/02/07 14:25:59
strange indentation.
karlklose
2012/02/08 14:12:00
Done.
| |
| 495 } | 593 } |
| 496 constructorArguments.add(value); | |
| 497 } | 594 } |
| 595 element = element.superclass; | |
| 498 } | 596 } |
| 499 HForeignNew newObject = new HForeignNew(classElement, constructorArguments); | 597 HForeignNew newObject = new HForeignNew(classElement, constructorArguments); |
| 500 add(newObject); | 598 add(newObject); |
| 501 | 599 // Generate calls to the constructor bodies. |
| 502 // Call the method body. | 600 for (int index = constructors.length - 1; index >= 0; index--) { |
| 503 SourceString methodName = bodyElement.name; | 601 FunctionElement constructor = constructors[index]; |
| 504 | 602 List bodyCallInputs = <HInstruction>[]; |
| 505 List bodyCallInputs = <HInstruction>[]; | 603 bodyCallInputs.add(newObject); |
| 506 bodyCallInputs.add(newObject); | 604 int argumentCount = 0; |
| 507 FunctionParameters parameters = functionElement.computeParameters(compiler); | 605 List<HInstruction> environment = environments[constructor]; |
| 508 parameters.forEachParameter((Element parameterElement) { | 606 for (HInstruction value in environment) { |
|
ngeoffray
2012/02/07 14:25:59
Instead of creating a new list and adding the inst
karlklose
2012/02/08 14:12:00
I removed the environments.
| |
| 509 HInstruction currentValue = localsHandler.readLocal(parameterElement); | 607 bodyCallInputs.add(value); |
| 510 bodyCallInputs.add(currentValue); | 608 argumentCount++; |
| 511 }); | 609 } |
| 512 add(new HInvokeDynamicMethod(null, methodName, bodyCallInputs)); | 610 Selector selector = new Invocation(argumentCount); |
| 611 ConstructorBodyElement body = this.getConstructorBody(classElement, | |
| 612 constructor); | |
| 613 // Call the method body. | |
| 614 SourceString methodName = body.name; | |
| 615 add(new HInvokeDynamicMethod(selector, methodName, bodyCallInputs)); | |
|
ngeoffray
2012/02/07 14:25:59
I believe you don't need a selector for this HInvo
karlklose
2012/02/08 14:12:00
Removed.
| |
| 616 } | |
| 513 close(new HReturn(newObject)).addSuccessor(graph.exit); | 617 close(new HReturn(newObject)).addSuccessor(graph.exit); |
| 514 return closeFunction(); | 618 return closeFunction(); |
| 515 } | 619 } |
| 516 | 620 |
| 517 void openFunction(FunctionElement functionElement, | 621 void openFunction(FunctionElement functionElement, |
| 518 FunctionExpression node) { | 622 FunctionExpression node) { |
| 519 HBasicBlock block = graph.addNewBlock(); | 623 HBasicBlock block = graph.addNewBlock(); |
| 520 open(graph.entry); | 624 open(graph.entry); |
| 521 | 625 |
| 522 localsHandler.startFunction(functionElement, node); | 626 localsHandler.startFunction(functionElement, node); |
| (...skipping 838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1361 // static call to a factory. | 1465 // static call to a factory. |
| 1362 visitStaticSend(node); | 1466 visitStaticSend(node); |
| 1363 } else { | 1467 } else { |
| 1364 compiler.internalError("Cannot generate code for send", node: node); | 1468 compiler.internalError("Cannot generate code for send", node: node); |
| 1365 } | 1469 } |
| 1366 } | 1470 } |
| 1367 } | 1471 } |
| 1368 | 1472 |
| 1369 visitNewExpression(NewExpression node) => visitSend(node.send); | 1473 visitNewExpression(NewExpression node) => visitSend(node.send); |
| 1370 | 1474 |
| 1475 HInstruction updateElementDefinition(Element element, HInstruction value) { | |
|
ngeoffray
2012/02/07 14:25:59
Since this method is only used once, I would inlin
karlklose
2012/02/08 14:12:00
Done.
| |
| 1476 localsHandler.updateLocal(element, value); | |
| 1477 return value; | |
| 1478 } | |
| 1479 | |
| 1371 visitSendSet(SendSet node) { | 1480 visitSendSet(SendSet node) { |
| 1372 Operator op = node.assignmentOperator; | 1481 Operator op = node.assignmentOperator; |
| 1373 if (node.isIndex) { | 1482 if (node.isIndex) { |
| 1374 if (!methodInterceptionEnabled) { | 1483 if (!methodInterceptionEnabled) { |
| 1375 assert(op.source.stringValue === '='); | 1484 assert(op.source.stringValue === '='); |
| 1376 visitDynamicSend(node); | 1485 visitDynamicSend(node); |
| 1377 } else { | 1486 } else { |
| 1378 HStatic target = new HStatic( | 1487 HStatic target = new HStatic( |
| 1379 interceptors.getIndexAssignmentInterceptor()); | 1488 interceptors.getIndexAssignmentInterceptor()); |
| 1380 add(target); | 1489 add(target); |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1711 } | 1820 } |
| 1712 | 1821 |
| 1713 visitCatchBlock(CatchBlock node) { | 1822 visitCatchBlock(CatchBlock node) { |
| 1714 compiler.unimplemented('SsaBuilder.visitCatchBlock', node: node); | 1823 compiler.unimplemented('SsaBuilder.visitCatchBlock', node: node); |
| 1715 } | 1824 } |
| 1716 | 1825 |
| 1717 visitTypedef(Typedef node) { | 1826 visitTypedef(Typedef node) { |
| 1718 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 1827 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
| 1719 } | 1828 } |
| 1720 } | 1829 } |
| OLD | NEW |