| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 IrBuilder.recursive(IrBuilder parent) | 338 IrBuilder.recursive(IrBuilder parent) |
| 339 : this.state = parent.state, | 339 : this.state = parent.state, |
| 340 this.environment = new Environment.empty() { | 340 this.environment = new Environment.empty() { |
| 341 parent.environment.index2variable.forEach(createParameter); | 341 parent.environment.index2variable.forEach(createParameter); |
| 342 } | 342 } |
| 343 | 343 |
| 344 | 344 |
| 345 bool get isOpen => _root == null || _current != null; | 345 bool get isOpen => _root == null || _current != null; |
| 346 | 346 |
| 347 /// Create a parameter for [parameterElement] and add it to the current | 347 /// Create a parameter for [parameterElement] and add it to the current |
| 348 /// environment. If [isClosureVariable] marks whether [parameterElement] is | 348 /// environment. |
| 349 /// accessed from an inner function. | 349 /// |
| 350 /// [isClosureVariable] marks whether [parameterElement] is accessed from an |
| 351 /// inner function. |
| 350 void createParameter(LocalElement parameterElement, | 352 void createParameter(LocalElement parameterElement, |
| 351 {bool isClosureVariable: false}) { | 353 {bool isClosureVariable: false}) { |
| 352 ir.Parameter parameter = new ir.Parameter(parameterElement); | 354 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 353 _parameters.add(parameter); | 355 _parameters.add(parameter); |
| 354 if (isClosureVariable) { | 356 if (isClosureVariable) { |
| 355 add(new ir.SetClosureVariable(parameterElement, parameter)); | 357 add(new ir.SetClosureVariable(parameterElement, parameter)); |
| 356 } else { | 358 } else { |
| 357 environment.extend(parameterElement, parameter); | 359 environment.extend(parameterElement, parameter); |
| 358 } | 360 } |
| 359 } | 361 } |
| 360 | 362 |
| 363 /// Add the constant [variableElement] to the environment with [value] as its |
| 364 /// constant value. |
| 361 void declareLocalConstant(LocalVariableElement variableElement, | 365 void declareLocalConstant(LocalVariableElement variableElement, |
| 362 ConstantExpression value) { | 366 ConstantExpression value) { |
| 363 state.localConstants.add(new ConstDeclaration(variableElement, value)); | 367 state.localConstants.add(new ConstDeclaration(variableElement, value)); |
| 364 } | 368 } |
| 365 | 369 |
| 370 /// Add [variableElement] to the environment with [initialValue] as its |
| 371 /// initial value. |
| 372 /// |
| 373 /// [isClosureVariable] marks whether [variableElement] is accessed from an |
| 374 /// inner function. |
| 366 void declareLocalVariable(LocalVariableElement variableElement, | 375 void declareLocalVariable(LocalVariableElement variableElement, |
| 367 {ir.Primitive initialValue, | 376 {ir.Primitive initialValue, |
| 368 bool isClosureVariable: false}) { | 377 bool isClosureVariable: false}) { |
| 369 assert(isOpen); | 378 assert(isOpen); |
| 370 if (initialValue == null) { | 379 if (initialValue == null) { |
| 371 // TODO(kmillikin): Consider pooling constants. | 380 // TODO(kmillikin): Consider pooling constants. |
| 372 // The initial value is null. | 381 // The initial value is null. |
| 373 initialValue = makePrimConst(state.constantSystem.createNull()); | 382 initialValue = makePrimConst(state.constantSystem.createNull()); |
| 374 add(new ir.LetPrim(initialValue)); | 383 add(new ir.LetPrim(initialValue)); |
| 375 } | 384 } |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 return buildPrimConst(state.constantSystem.createNull()); | 453 return buildPrimConst(state.constantSystem.createNull()); |
| 445 } | 454 } |
| 446 | 455 |
| 447 /// Create a string literal. | 456 /// Create a string literal. |
| 448 ir.Constant buildStringLiteral(String value) { | 457 ir.Constant buildStringLiteral(String value) { |
| 449 return buildPrimConst( | 458 return buildPrimConst( |
| 450 state.constantSystem.createString(new ast.DartString.literal(value))); | 459 state.constantSystem.createString(new ast.DartString.literal(value))); |
| 451 } | 460 } |
| 452 | 461 |
| 453 /// Create a get access of [local]. | 462 /// Create a get access of [local]. |
| 454 ir.Primitive buildGetLocal(Element local) { | 463 ir.Primitive buildLocalGet(Element local) { |
| 455 assert(isOpen); | 464 assert(isOpen); |
| 456 return environment.lookup(local); | 465 return environment.lookup(local); |
| 457 } | 466 } |
| 458 | 467 |
| 459 /// Create a get access of the static [element]. | 468 /// Create a get access of the static [element]. |
| 460 ir.Primitive buildGetStatic(Element element, Selector selector) { | 469 ir.Primitive buildStaticGet(Element element, Selector selector) { |
| 461 assert(isOpen); | 470 assert(isOpen); |
| 462 assert(selector.isGetter); | 471 assert(selector.isGetter); |
| 463 return continueWithExpression( | 472 return continueWithExpression( |
| 464 (k) => new ir.InvokeStatic(element, selector, k, [])); | 473 (k) => new ir.InvokeStatic( |
| 474 element, selector, k, const <ir.Definition>[])); |
| 475 } |
| 476 |
| 477 /// Create a dynamic get access on [receiver] where the property is defined |
| 478 /// by the getter [selector]. |
| 479 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector) { |
| 480 assert(isOpen); |
| 481 assert(selector.isGetter); |
| 482 return continueWithExpression( |
| 483 (k) => new ir.InvokeMethod( |
| 484 receiver, selector, k, const <ir.Definition>[])); |
| 465 } | 485 } |
| 466 | 486 |
| 467 /** | 487 /** |
| 468 * Add an explicit `return null` for functions that don't have a return | 488 * Add an explicit `return null` for functions that don't have a return |
| 469 * statement on each branch. This includes functions with an empty body, | 489 * statement on each branch. This includes functions with an empty body, |
| 470 * such as `foo(){ }`. | 490 * such as `foo(){ }`. |
| 471 */ | 491 */ |
| 472 void ensureReturn() { | 492 void ensureReturn() { |
| 473 if (!isOpen) return; | 493 if (!isOpen) return; |
| 474 ir.Constant constant = makePrimConst(state.constantSystem.createNull()); | 494 ir.Constant constant = makePrimConst(state.constantSystem.createNull()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 493 assert(invariant(element, _root == null, | 513 assert(invariant(element, _root == null, |
| 494 message: "Non-empty body for abstract method $element: $_root")); | 514 message: "Non-empty body for abstract method $element: $_root")); |
| 495 assert(invariant(element, state.localConstants.isEmpty, | 515 assert(invariant(element, state.localConstants.isEmpty, |
| 496 message: "Local constants for abstract method $element: " | 516 message: "Local constants for abstract method $element: " |
| 497 "${state.localConstants}")); | 517 "${state.localConstants}")); |
| 498 return new ir.FunctionDefinition.abstract( | 518 return new ir.FunctionDefinition.abstract( |
| 499 element, _parameters, defaults); | 519 element, _parameters, defaults); |
| 500 } | 520 } |
| 501 } | 521 } |
| 502 | 522 |
| 523 |
| 524 /// Create a super invocation with method name and arguments structure defined |
| 525 /// by [selector] and argument values defined by [arguments]. |
| 526 ir.Primitive buildSuperInvocation(Selector selector, |
| 527 List<ir.Definition> arguments) { |
| 528 assert(isOpen); |
| 529 return continueWithExpression( |
| 530 (k) => new ir.InvokeSuperMethod(selector, k, arguments)); |
| 531 |
| 532 } |
| 533 |
| 534 /// Create a dynamic invocation on [receiver] with method name and arguments |
| 535 /// structure defined by [selector] and argument values defined by |
| 536 /// [arguments]. |
| 537 ir.Primitive buildDynamicInvocation(ir.Definition receiver, |
| 538 Selector selector, |
| 539 List<ir.Definition> arguments) { |
| 540 assert(isOpen); |
| 541 return continueWithExpression( |
| 542 (k) => new ir.InvokeMethod(receiver, selector, k, arguments)); |
| 543 } |
| 544 |
| 503 /// Create a static invocation of [element] with arguments structure defined | 545 /// Create a static invocation of [element] with arguments structure defined |
| 504 /// by [selector] and argument values defined by [arguments]. | 546 /// by [selector] and argument values defined by [arguments]. |
| 505 ir.Primitive buildStaticInvocation(Element element, | 547 ir.Primitive buildStaticInvocation(Element element, |
| 506 Selector selector, | 548 Selector selector, |
| 507 List<ir.Definition> arguments) { | 549 List<ir.Definition> arguments) { |
| 508 return continueWithExpression( | 550 return continueWithExpression( |
| 509 (k) => new ir.InvokeStatic(element, selector, k, arguments)); | 551 (k) => new ir.InvokeStatic(element, selector, k, arguments)); |
| 510 } | 552 } |
| 511 | 553 |
| 512 /// Create a return statement `return value;` or `return;` if [value] is | 554 /// Create a return statement `return value;` or `return;` if [value] is |
| (...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1478 } | 1520 } |
| 1479 | 1521 |
| 1480 ir.Primitive visitDynamicSend(ast.Send node) { | 1522 ir.Primitive visitDynamicSend(ast.Send node) { |
| 1481 assert(irBuilder.isOpen); | 1523 assert(irBuilder.isOpen); |
| 1482 Selector selector = elements.getSelector(node); | 1524 Selector selector = elements.getSelector(node); |
| 1483 ir.Primitive receiver = visitReceiver(node.receiver); | 1525 ir.Primitive receiver = visitReceiver(node.receiver); |
| 1484 List<ir.Primitive> arguments = new List<ir.Primitive>(); | 1526 List<ir.Primitive> arguments = new List<ir.Primitive>(); |
| 1485 for (ast.Node n in node.arguments) { | 1527 for (ast.Node n in node.arguments) { |
| 1486 arguments.add(visit(n)); | 1528 arguments.add(visit(n)); |
| 1487 } | 1529 } |
| 1488 return irBuilder.continueWithExpression( | 1530 return irBuilder.buildDynamicInvocation(receiver, selector, arguments); |
| 1489 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | |
| 1490 } | 1531 } |
| 1491 | 1532 |
| 1492 _GetterElements translateGetter(ast.Send node, Selector selector) { | 1533 _GetterElements translateGetter(ast.Send node, Selector selector) { |
| 1493 Element element = elements[node]; | 1534 Element element = elements[node]; |
| 1494 ir.Primitive result; | 1535 ir.Primitive result; |
| 1495 ir.Primitive receiver; | 1536 ir.Primitive receiver; |
| 1496 ir.Primitive index; | 1537 ir.Primitive index; |
| 1497 | 1538 |
| 1498 if (element != null && element.isConst) { | 1539 if (element != null && element.isConst) { |
| 1499 // Reference to constant local, top-level or static field | 1540 // Reference to constant local, top-level or static field |
| 1500 result = translateConstant(node); | 1541 result = translateConstant(node); |
| 1501 } else if (isClosureVariable(element)) { | 1542 } else if (isClosureVariable(element)) { |
| 1502 LocalElement local = element; | 1543 LocalElement local = element; |
| 1503 result = new ir.GetClosureVariable(local); | 1544 result = new ir.GetClosureVariable(local); |
| 1504 irBuilder.add(new ir.LetPrim(result)); | 1545 irBuilder.add(new ir.LetPrim(result)); |
| 1505 } else if (Elements.isLocal(element)) { | 1546 } else if (Elements.isLocal(element)) { |
| 1506 // Reference to local variable | 1547 // Reference to local variable |
| 1507 result = irBuilder.buildGetLocal(element); | 1548 result = irBuilder.buildLocalGet(element); |
| 1508 } else if (element == null || | 1549 } else if (element == null || |
| 1509 Elements.isInstanceField(element) || | 1550 Elements.isInstanceField(element) || |
| 1510 Elements.isInstanceMethod(element) || | 1551 Elements.isInstanceMethod(element) || |
| 1511 selector.isIndex || | 1552 selector.isIndex || |
| 1512 // TODO(johnniwinther): clean up semantics of resolution. | 1553 // TODO(johnniwinther): clean up semantics of resolution. |
| 1513 node.isSuperCall) { | 1554 node.isSuperCall) { |
| 1514 // Dynamic dispatch to a getter. Sometimes resolution will suggest a | 1555 // Dynamic dispatch to a getter. Sometimes resolution will suggest a |
| 1515 // target element, but in these cases we must still emit a dynamic | 1556 // target element, but in these cases we must still emit a dynamic |
| 1516 // dispatch. The target element may be an instance method in case we are | 1557 // dispatch. The target element may be an instance method in case we are |
| 1517 // converting a method to a function object. | 1558 // converting a method to a function object. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1528 result = irBuilder.continueWithExpression( | 1569 result = irBuilder.continueWithExpression( |
| 1529 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); | 1570 (k) => createDynamicInvoke(node, selector, receiver, k, arguments)); |
| 1530 } else if (element.isField || element.isGetter || element.isErroneous || | 1571 } else if (element.isField || element.isGetter || element.isErroneous || |
| 1531 element.isSetter) { | 1572 element.isSetter) { |
| 1532 // TODO(johnniwinther): Change handling of setter selectors. | 1573 // TODO(johnniwinther): Change handling of setter selectors. |
| 1533 // Access to a static field or getter (non-static case handled above). | 1574 // Access to a static field or getter (non-static case handled above). |
| 1534 // Even if there is only a setter, we compile as if it was a getter, | 1575 // Even if there is only a setter, we compile as if it was a getter, |
| 1535 // so the vm can fail at runtime. | 1576 // so the vm can fail at runtime. |
| 1536 assert(selector.kind == SelectorKind.GETTER || | 1577 assert(selector.kind == SelectorKind.GETTER || |
| 1537 selector.kind == SelectorKind.SETTER); | 1578 selector.kind == SelectorKind.SETTER); |
| 1538 result = irBuilder.buildGetStatic(element, selector); | 1579 result = irBuilder.buildStaticGet(element, selector); |
| 1539 } else if (Elements.isStaticOrTopLevelFunction(element)) { | 1580 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| 1540 // Convert a top-level or static function to a function object. | 1581 // Convert a top-level or static function to a function object. |
| 1541 result = translateConstant(node); | 1582 result = translateConstant(node); |
| 1542 } else { | 1583 } else { |
| 1543 throw "Unexpected SendSet getter: $node, $element"; | 1584 throw "Unexpected SendSet getter: $node, $element"; |
| 1544 } | 1585 } |
| 1545 return new _GetterElements( | 1586 return new _GetterElements( |
| 1546 result: result,index: index, receiver: receiver); | 1587 result: result,index: index, receiver: receiver); |
| 1547 } | 1588 } |
| 1548 | 1589 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1721 growable:false); | 1762 growable:false); |
| 1722 return irBuilder.buildStaticInvocation(element, selector, arguments); | 1763 return irBuilder.buildStaticInvocation(element, selector, arguments); |
| 1723 } | 1764 } |
| 1724 | 1765 |
| 1725 | 1766 |
| 1726 ir.Primitive visitSuperSend(ast.Send node) { | 1767 ir.Primitive visitSuperSend(ast.Send node) { |
| 1727 assert(irBuilder.isOpen); | 1768 assert(irBuilder.isOpen); |
| 1728 if (node.isPropertyAccess) { | 1769 if (node.isPropertyAccess) { |
| 1729 return visitGetterSend(node); | 1770 return visitGetterSend(node); |
| 1730 } else { | 1771 } else { |
| 1731 return visitDynamicSend(node); | 1772 Selector selector = elements.getSelector(node); |
| 1773 List<ir.Primitive> arguments = |
| 1774 node.arguments.mapToList(visit, growable: false); |
| 1775 return irBuilder.buildSuperInvocation(selector, arguments); |
| 1732 } | 1776 } |
| 1733 } | 1777 } |
| 1734 | 1778 |
| 1735 visitTypePrefixSend(ast.Send node) { | 1779 visitTypePrefixSend(ast.Send node) { |
| 1736 compiler.internalError(node, "visitTypePrefixSend should not be called."); | 1780 compiler.internalError(node, "visitTypePrefixSend should not be called."); |
| 1737 } | 1781 } |
| 1738 | 1782 |
| 1739 ir.Primitive visitTypeLiteralSend(ast.Send node) { | 1783 ir.Primitive visitTypeLiteralSend(ast.Send node) { |
| 1740 assert(irBuilder.isOpen); | 1784 assert(irBuilder.isOpen); |
| 1741 // If the user is trying to invoke the type literal or variable, | 1785 // If the user is trying to invoke the type literal or variable, |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2022 } | 2066 } |
| 2023 | 2067 |
| 2024 visitFunctionExpression(ast.FunctionExpression node) { | 2068 visitFunctionExpression(ast.FunctionExpression node) { |
| 2025 FunctionElement oldFunction = currentFunction; | 2069 FunctionElement oldFunction = currentFunction; |
| 2026 currentFunction = elements[node]; | 2070 currentFunction = elements[node]; |
| 2027 visit(node.body); | 2071 visit(node.body); |
| 2028 currentFunction = oldFunction; | 2072 currentFunction = oldFunction; |
| 2029 } | 2073 } |
| 2030 | 2074 |
| 2031 } | 2075 } |
| OLD | NEW |