| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library tree_ir_nodes; | |
| 6 | |
| 7 import '../constants/values.dart' as values; | |
| 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | |
| 9 import '../elements/elements.dart'; | |
| 10 import '../io/source_information.dart' show SourceInformation; | |
| 11 import '../types/types.dart' show TypeMask; | |
| 12 import '../universe/selector.dart' show Selector; | |
| 13 | |
| 14 import '../cps_ir/builtin_operator.dart'; | |
| 15 export '../cps_ir/builtin_operator.dart'; | |
| 16 import '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind; | |
| 17 export '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind; | |
| 18 | |
| 19 // These imports are only used for the JavaScript specific nodes. If we want to | |
| 20 // support more than one native backend, we should probably create better | |
| 21 // abstractions for native code and its type and effect system. | |
| 22 import '../js/js.dart' as js show Template; | |
| 23 import '../native/native.dart' as native show NativeBehavior; | |
| 24 import '../types/types.dart' as types show TypeMask; | |
| 25 | |
| 26 // The Tree language is the target of translation out of the CPS-based IR. | |
| 27 // | |
| 28 // The translation from CPS to Dart consists of several stages. Among the | |
| 29 // stages are translation to direct style, translation out of SSA, eliminating | |
| 30 // unnecessary names, recognizing high-level control constructs. Combining | |
| 31 // these separate concerns is complicated and the constraints of the CPS-based | |
| 32 // language do not permit a multi-stage translation. | |
| 33 // | |
| 34 // For that reason, CPS is translated to the direct-style language Tree. | |
| 35 // Translation out of SSA, unnaming, and control-flow, as well as 'instruction | |
| 36 // selection' are performed on the Tree language. | |
| 37 // | |
| 38 // In contrast to the CPS-based IR, non-primitive expressions can be named and | |
| 39 // arguments (to calls, primitives, and blocks) can be arbitrary expressions. | |
| 40 // | |
| 41 // Additionally, variables are considered in scope within inner functions; | |
| 42 // closure variables are thus handled directly instead of using ref cells. | |
| 43 | |
| 44 /** | |
| 45 * The base class of all Tree nodes. | |
| 46 */ | |
| 47 abstract class Node { | |
| 48 /// Workaround for a slow Object.hashCode in the VM. | |
| 49 static int _usedHashCodes = 0; | |
| 50 final int hashCode = ++_usedHashCodes; | |
| 51 } | |
| 52 | |
| 53 /** | |
| 54 * The base class of [Expression]s. | |
| 55 */ | |
| 56 abstract class Expression extends Node { | |
| 57 accept(ExpressionVisitor v); | |
| 58 accept1(ExpressionVisitor1 v, arg); | |
| 59 | |
| 60 SourceInformation get sourceInformation => null; | |
| 61 } | |
| 62 | |
| 63 abstract class Statement extends Node { | |
| 64 Statement get next; | |
| 65 void set next(Statement s); | |
| 66 accept(StatementVisitor v); | |
| 67 accept1(StatementVisitor1 v, arg); | |
| 68 } | |
| 69 | |
| 70 /** | |
| 71 * Labels name [LabeledStatement]s. | |
| 72 */ | |
| 73 class Label { | |
| 74 /// Number of [Break] or [Continue] statements that target this label. | |
| 75 /// The [Break] constructor will increment this automatically, but the | |
| 76 /// counter must be decremented by hand when a [Break] becomes orphaned. | |
| 77 int useCount = 0; | |
| 78 | |
| 79 /// The [LabeledStatement] or [WhileTrue] binding this label. | |
| 80 JumpTarget binding; | |
| 81 } | |
| 82 | |
| 83 /** | |
| 84 * A local variable in the tree IR. | |
| 85 * | |
| 86 * All tree IR variables are mutable. | |
| 87 * | |
| 88 * To use a variable as an expression, reference it from a [VariableUse], with | |
| 89 * one [VariableUse] per expression. | |
| 90 * | |
| 91 * [Variable]s are reference counted. The node constructors [VariableUse], | |
| 92 * [Assign], [FunctionDefinition], and [Try] automatically update the reference | |
| 93 * count for their variables, but when transforming the tree, the transformer | |
| 94 * is responsible for updating reference counts. | |
| 95 */ | |
| 96 class Variable extends Node { | |
| 97 /// Function that declares this variable. | |
| 98 ExecutableElement host; | |
| 99 | |
| 100 /// [Entity] used for synthesizing a name for the variable. | |
| 101 /// Different variables may have the same entity. May be null. | |
| 102 Entity element; | |
| 103 | |
| 104 /// Number of places where this variable occurs in a [VariableUse]. | |
| 105 int readCount = 0; | |
| 106 | |
| 107 /// Number of places where this variable occurs as: | |
| 108 /// - left-hand of an [Assign] | |
| 109 /// - parameter in a [FunctionDefinition] | |
| 110 /// - catch parameter in a [Try] | |
| 111 int writeCount = 0; | |
| 112 | |
| 113 /// True if an inner JS function might access this variable through a | |
| 114 /// [ForeignCode] node. | |
| 115 bool isCaptured = false; | |
| 116 | |
| 117 Variable(this.host, this.element) { | |
| 118 assert(host != null); | |
| 119 } | |
| 120 | |
| 121 String toString() => | |
| 122 element == null ? 'Variable.${hashCode}' : element.toString(); | |
| 123 } | |
| 124 | |
| 125 /// Read the value of a variable. | |
| 126 class VariableUse extends Expression { | |
| 127 Variable variable; | |
| 128 SourceInformation sourceInformation; | |
| 129 | |
| 130 /// Creates a use of [variable] and updates its `readCount`. | |
| 131 VariableUse(this.variable, {this.sourceInformation}) { | |
| 132 variable.readCount++; | |
| 133 } | |
| 134 | |
| 135 accept(ExpressionVisitor visitor) => visitor.visitVariableUse(this); | |
| 136 accept1(ExpressionVisitor1 visitor, arg) { | |
| 137 return visitor.visitVariableUse(this, arg); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 class Assign extends Expression { | |
| 142 Variable variable; | |
| 143 Expression value; | |
| 144 SourceInformation sourceInformation; | |
| 145 | |
| 146 Assign(this.variable, this.value, {this.sourceInformation}) { | |
| 147 variable.writeCount++; | |
| 148 } | |
| 149 | |
| 150 accept(ExpressionVisitor v) => v.visitAssign(this); | |
| 151 accept1(ExpressionVisitor1 v, arg) => v.visitAssign(this, arg); | |
| 152 | |
| 153 static ExpressionStatement makeStatement(Variable variable, Expression value, | |
| 154 [Statement next]) { | |
| 155 return new ExpressionStatement(new Assign(variable, value), next); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 /** | |
| 160 * Common interface for invocations with arguments. | |
| 161 */ | |
| 162 abstract class Invoke { | |
| 163 List<Expression> get arguments; | |
| 164 } | |
| 165 | |
| 166 /** | |
| 167 * A call to a static function or getter/setter to a static field. | |
| 168 * | |
| 169 * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. | |
| 170 */ | |
| 171 class InvokeStatic extends Expression implements Invoke { | |
| 172 final Entity target; | |
| 173 final List<Expression> arguments; | |
| 174 final Selector selector; | |
| 175 final SourceInformation sourceInformation; | |
| 176 | |
| 177 InvokeStatic(this.target, this.selector, this.arguments, | |
| 178 [this.sourceInformation]); | |
| 179 | |
| 180 accept(ExpressionVisitor visitor) => visitor.visitInvokeStatic(this); | |
| 181 accept1(ExpressionVisitor1 visitor, arg) { | |
| 182 return visitor.visitInvokeStatic(this, arg); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * A call to a method, operator, getter, setter or index getter/setter. | |
| 188 * | |
| 189 * If [receiver] is `null`, an error is thrown before the arguments are | |
| 190 * evaluated. This corresponds to the JS evaluation order. | |
| 191 */ | |
| 192 class InvokeMethod extends Expression implements Invoke { | |
| 193 Expression receiver; | |
| 194 final Selector selector; | |
| 195 final TypeMask mask; | |
| 196 final List<Expression> arguments; | |
| 197 final SourceInformation sourceInformation; | |
| 198 | |
| 199 /// If true, it is known that the receiver cannot be `null`. | |
| 200 bool receiverIsNotNull = false; | |
| 201 | |
| 202 InvokeMethod(this.receiver, this.selector, this.mask, this.arguments, | |
| 203 this.sourceInformation) { | |
| 204 assert(receiver != null); | |
| 205 } | |
| 206 | |
| 207 accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this); | |
| 208 accept1(ExpressionVisitor1 visitor, arg) { | |
| 209 return visitor.visitInvokeMethod(this, arg); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 /// Invoke [target] on [receiver], bypassing ordinary dispatch semantics. | |
| 214 /// | |
| 215 /// Since the [receiver] is not used for method lookup, it may be `null` | |
| 216 /// without an error being thrown. | |
| 217 class InvokeMethodDirectly extends Expression implements Invoke { | |
| 218 Expression receiver; | |
| 219 final Element target; | |
| 220 final Selector selector; | |
| 221 final List<Expression> arguments; | |
| 222 final SourceInformation sourceInformation; | |
| 223 | |
| 224 InvokeMethodDirectly(this.receiver, this.target, this.selector, | |
| 225 this.arguments, this.sourceInformation); | |
| 226 | |
| 227 bool get isTearOff => selector.isGetter && !target.isGetter; | |
| 228 | |
| 229 accept(ExpressionVisitor visitor) => visitor.visitInvokeMethodDirectly(this); | |
| 230 accept1(ExpressionVisitor1 visitor, arg) { | |
| 231 return visitor.visitInvokeMethodDirectly(this, arg); | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 /** | |
| 236 * Call to a factory or generative constructor. | |
| 237 */ | |
| 238 class InvokeConstructor extends Expression implements Invoke { | |
| 239 final DartType type; | |
| 240 final FunctionElement target; | |
| 241 final List<Expression> arguments; | |
| 242 final Selector selector; | |
| 243 final SourceInformation sourceInformation; | |
| 244 | |
| 245 /// TODO(karlklose): get rid of this field. Instead use the constant's | |
| 246 /// expression to find the constructor to be called in dart2dart. | |
| 247 final values.ConstantValue constant; | |
| 248 | |
| 249 InvokeConstructor(this.type, this.target, this.selector, this.arguments, | |
| 250 this.sourceInformation, | |
| 251 [this.constant]); | |
| 252 | |
| 253 ClassElement get targetClass => target.enclosingElement; | |
| 254 | |
| 255 accept(ExpressionVisitor visitor) { | |
| 256 return visitor.visitInvokeConstructor(this); | |
| 257 } | |
| 258 | |
| 259 accept1(ExpressionVisitor1 visitor, arg) { | |
| 260 return visitor.visitInvokeConstructor(this, arg); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 /// Call a method using a one-shot interceptor. | |
| 265 /// | |
| 266 /// There is no explicit receiver, the first argument serves that purpose. | |
| 267 class OneShotInterceptor extends Expression implements Invoke { | |
| 268 final Selector selector; | |
| 269 final TypeMask mask; | |
| 270 final List<Expression> arguments; | |
| 271 final SourceInformation sourceInformation; | |
| 272 | |
| 273 OneShotInterceptor( | |
| 274 this.selector, this.mask, this.arguments, this.sourceInformation); | |
| 275 | |
| 276 accept(ExpressionVisitor visitor) => visitor.visitOneShotInterceptor(this); | |
| 277 accept1(ExpressionVisitor1 visitor, arg) { | |
| 278 return visitor.visitOneShotInterceptor(this, arg); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 /** | |
| 283 * A constant. | |
| 284 */ | |
| 285 class Constant extends Expression { | |
| 286 final values.ConstantValue value; | |
| 287 final SourceInformation sourceInformation; | |
| 288 | |
| 289 Constant(this.value, {this.sourceInformation}); | |
| 290 | |
| 291 Constant.bool(values.BoolConstantValue constantValue) | |
| 292 : value = constantValue, | |
| 293 sourceInformation = null; | |
| 294 | |
| 295 accept(ExpressionVisitor visitor) => visitor.visitConstant(this); | |
| 296 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitConstant(this, arg); | |
| 297 | |
| 298 String toString() => 'Constant(value=${value.toStructuredText()})'; | |
| 299 } | |
| 300 | |
| 301 class This extends Expression { | |
| 302 accept(ExpressionVisitor visitor) => visitor.visitThis(this); | |
| 303 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitThis(this, arg); | |
| 304 } | |
| 305 | |
| 306 class LiteralList extends Expression { | |
| 307 final InterfaceType type; | |
| 308 final List<Expression> values; | |
| 309 | |
| 310 LiteralList(this.type, this.values); | |
| 311 | |
| 312 accept(ExpressionVisitor visitor) => visitor.visitLiteralList(this); | |
| 313 accept1(ExpressionVisitor1 visitor, arg) { | |
| 314 return visitor.visitLiteralList(this, arg); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 /// Type test or type cast. | |
| 319 /// | |
| 320 /// Note that if this is a type test, then [type] cannot be `Object`, `dynamic`, | |
| 321 /// or the `Null` type. These cases are compiled to other node types. | |
| 322 class TypeOperator extends Expression { | |
| 323 Expression value; | |
| 324 final DartType type; | |
| 325 final List<Expression> typeArguments; | |
| 326 final bool isTypeTest; | |
| 327 | |
| 328 TypeOperator(this.value, this.type, this.typeArguments, | |
| 329 {bool this.isTypeTest}); | |
| 330 | |
| 331 accept(ExpressionVisitor visitor) => visitor.visitTypeOperator(this); | |
| 332 accept1(ExpressionVisitor1 visitor, arg) { | |
| 333 return visitor.visitTypeOperator(this, arg); | |
| 334 } | |
| 335 | |
| 336 String get operator => isTypeTest ? 'is' : 'as'; | |
| 337 } | |
| 338 | |
| 339 /** | |
| 340 * Apply a built-in operator. | |
| 341 * | |
| 342 * It must be known that the arguments have the proper types. | |
| 343 * Null is not a valid argument to any of the built-in operators. | |
| 344 */ | |
| 345 class ApplyBuiltinOperator extends Expression { | |
| 346 BuiltinOperator operator; | |
| 347 List<Expression> arguments; | |
| 348 SourceInformation sourceInformation; | |
| 349 | |
| 350 ApplyBuiltinOperator(this.operator, this.arguments, this.sourceInformation); | |
| 351 | |
| 352 accept(ExpressionVisitor visitor) { | |
| 353 return visitor.visitApplyBuiltinOperator(this); | |
| 354 } | |
| 355 | |
| 356 accept1(ExpressionVisitor1 visitor, arg) { | |
| 357 return visitor.visitApplyBuiltinOperator(this, arg); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 class ApplyBuiltinMethod extends Expression { | |
| 362 BuiltinMethod method; | |
| 363 Expression receiver; | |
| 364 List<Expression> arguments; | |
| 365 | |
| 366 bool receiverIsNotNull; | |
| 367 | |
| 368 ApplyBuiltinMethod(this.method, this.receiver, this.arguments, | |
| 369 {this.receiverIsNotNull: false}); | |
| 370 | |
| 371 accept(ExpressionVisitor visitor) { | |
| 372 return visitor.visitApplyBuiltinMethod(this); | |
| 373 } | |
| 374 | |
| 375 accept1(ExpressionVisitor1 visitor, arg) { | |
| 376 return visitor.visitApplyBuiltinMethod(this, arg); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 /// A conditional expression. | |
| 381 class Conditional extends Expression { | |
| 382 Expression condition; | |
| 383 Expression thenExpression; | |
| 384 Expression elseExpression; | |
| 385 | |
| 386 Conditional(this.condition, this.thenExpression, this.elseExpression); | |
| 387 | |
| 388 accept(ExpressionVisitor visitor) => visitor.visitConditional(this); | |
| 389 accept1(ExpressionVisitor1 visitor, arg) { | |
| 390 return visitor.visitConditional(this, arg); | |
| 391 } | |
| 392 | |
| 393 String toString() => 'Conditional(condition=$condition,thenExpression=' | |
| 394 '$thenExpression,elseExpression=$elseExpression)'; | |
| 395 } | |
| 396 | |
| 397 /// An && or || expression. The operator is internally represented as a boolean | |
| 398 /// [isAnd] to simplify rewriting of logical operators. | |
| 399 /// Note the result of && and || is one of the arguments, which might not be | |
| 400 /// boolean. 'ShortCircuitOperator' might have been a better name. | |
| 401 class LogicalOperator extends Expression { | |
| 402 Expression left; | |
| 403 bool isAnd; | |
| 404 Expression right; | |
| 405 | |
| 406 LogicalOperator(this.left, this.right, this.isAnd); | |
| 407 LogicalOperator.and(this.left, this.right) : isAnd = true; | |
| 408 LogicalOperator.or(this.left, this.right) : isAnd = false; | |
| 409 | |
| 410 String get operator => isAnd ? '&&' : '||'; | |
| 411 | |
| 412 accept(ExpressionVisitor visitor) => visitor.visitLogicalOperator(this); | |
| 413 accept1(ExpressionVisitor1 visitor, arg) { | |
| 414 return visitor.visitLogicalOperator(this, arg); | |
| 415 } | |
| 416 | |
| 417 String toString() => 'LogicalOperator(left=$left,right=$right,isAnd=$isAnd)'; | |
| 418 } | |
| 419 | |
| 420 /// Logical negation. | |
| 421 // TODO(asgerf): Replace this class with the IsFalsy builtin operator? | |
| 422 // Right now the tree builder compiles IsFalsy to Not. | |
| 423 class Not extends Expression { | |
| 424 Expression operand; | |
| 425 | |
| 426 Not(this.operand); | |
| 427 | |
| 428 accept(ExpressionVisitor visitor) => visitor.visitNot(this); | |
| 429 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitNot(this, arg); | |
| 430 } | |
| 431 | |
| 432 /// A [LabeledStatement] or [WhileTrue] or [For]. | |
| 433 abstract class JumpTarget extends Statement { | |
| 434 Label get label; | |
| 435 Statement get body; | |
| 436 } | |
| 437 | |
| 438 /** | |
| 439 * A labeled statement. Breaks to the label within the labeled statement | |
| 440 * target the successor statement. | |
| 441 */ | |
| 442 class LabeledStatement extends JumpTarget { | |
| 443 Statement next; | |
| 444 final Label label; | |
| 445 Statement body; | |
| 446 | |
| 447 LabeledStatement(this.label, this.body, this.next) { | |
| 448 assert(label.binding == null); | |
| 449 label.binding = this; | |
| 450 } | |
| 451 | |
| 452 accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this); | |
| 453 accept1(StatementVisitor1 visitor, arg) { | |
| 454 return visitor.visitLabeledStatement(this, arg); | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 /// A [WhileTrue] or [For] loop. | |
| 459 abstract class Loop extends JumpTarget {} | |
| 460 | |
| 461 /** | |
| 462 * A labeled while(true) loop. | |
| 463 */ | |
| 464 class WhileTrue extends Loop { | |
| 465 final Label label; | |
| 466 Statement body; | |
| 467 | |
| 468 WhileTrue(this.label, this.body) { | |
| 469 assert(label.binding == null); | |
| 470 label.binding = this; | |
| 471 } | |
| 472 | |
| 473 Statement get next => null; | |
| 474 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 475 | |
| 476 accept(StatementVisitor visitor) => visitor.visitWhileTrue(this); | |
| 477 accept1(StatementVisitor1 visitor, arg) => visitor.visitWhileTrue(this, arg); | |
| 478 } | |
| 479 | |
| 480 /** | |
| 481 * A loop with a condition and update expressions. If there are any update | |
| 482 * expressions, this generates a for loop, otherwise a while loop. | |
| 483 * | |
| 484 * When the condition is false, control resumes at the [next] statement. | |
| 485 * | |
| 486 * It is NOT valid to target this statement with a [Break]. | |
| 487 * The only way to reach [next] is for the condition to evaluate to false. | |
| 488 * | |
| 489 * [For] statements are introduced in the [LoopRewriter] and are | |
| 490 * assumed not to occur before then. | |
| 491 */ | |
| 492 class For extends Loop { | |
| 493 final Label label; | |
| 494 Expression condition; | |
| 495 List<Expression> updates; | |
| 496 Statement body; | |
| 497 Statement next; | |
| 498 | |
| 499 For(this.label, this.condition, this.updates, this.body, this.next) { | |
| 500 assert(label.binding == null); | |
| 501 label.binding = this; | |
| 502 } | |
| 503 | |
| 504 accept(StatementVisitor visitor) => visitor.visitFor(this); | |
| 505 accept1(StatementVisitor1 visitor, arg) { | |
| 506 return visitor.visitFor(this, arg); | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 /// A [Break] or [Continue] statement. | |
| 511 abstract class Jump extends Statement { | |
| 512 Label get target; | |
| 513 } | |
| 514 | |
| 515 /** | |
| 516 * A break from an enclosing [LabeledStatement]. The break targets the | |
| 517 * labeled statement's successor statement. | |
| 518 */ | |
| 519 class Break extends Jump { | |
| 520 final Label target; | |
| 521 | |
| 522 Statement get next => null; | |
| 523 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 524 | |
| 525 Break(this.target) { | |
| 526 ++target.useCount; | |
| 527 } | |
| 528 | |
| 529 accept(StatementVisitor visitor) => visitor.visitBreak(this); | |
| 530 accept1(StatementVisitor1 visitor, arg) => visitor.visitBreak(this, arg); | |
| 531 } | |
| 532 | |
| 533 /** | |
| 534 * A continue to an enclosing [WhileTrue] or [For] loop. | |
| 535 * The continue targets the loop's body. | |
| 536 */ | |
| 537 class Continue extends Jump { | |
| 538 final Label target; | |
| 539 | |
| 540 Statement get next => null; | |
| 541 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 542 | |
| 543 Continue(this.target) { | |
| 544 ++target.useCount; | |
| 545 } | |
| 546 | |
| 547 accept(StatementVisitor visitor) => visitor.visitContinue(this); | |
| 548 accept1(StatementVisitor1 visitor, arg) => visitor.visitContinue(this, arg); | |
| 549 } | |
| 550 | |
| 551 /** | |
| 552 * A return exit from the function. | |
| 553 * | |
| 554 * In contrast to the CPS-based IR, the return value is an arbitrary | |
| 555 * expression. | |
| 556 */ | |
| 557 class Return extends Statement { | |
| 558 /// Should not be null. Use [Constant] with [NullConstantValue] for void | |
| 559 /// returns. | |
| 560 /// Even in constructors this holds true. Take special care when translating | |
| 561 /// back to dart, where `return null;` in a constructor is an error. | |
| 562 Expression value; | |
| 563 SourceInformation sourceInformation; | |
| 564 | |
| 565 Statement get next => null; | |
| 566 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 567 | |
| 568 Return(this.value, {this.sourceInformation}); | |
| 569 | |
| 570 accept(StatementVisitor visitor) => visitor.visitReturn(this); | |
| 571 accept1(StatementVisitor1 visitor, arg) => visitor.visitReturn(this, arg); | |
| 572 } | |
| 573 | |
| 574 /// A throw statement. | |
| 575 /// | |
| 576 /// In the Tree IR, throw is a statement (like JavaScript and unlike Dart). | |
| 577 /// It does not have a successor statement. | |
| 578 class Throw extends Statement { | |
| 579 Expression value; | |
| 580 | |
| 581 Statement get next => null; | |
| 582 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 583 | |
| 584 Throw(this.value); | |
| 585 | |
| 586 accept(StatementVisitor visitor) => visitor.visitThrow(this); | |
| 587 accept1(StatementVisitor1 visitor, arg) => visitor.visitThrow(this, arg); | |
| 588 } | |
| 589 | |
| 590 /** | |
| 591 * A conditional branch based on the true value of an [Expression]. | |
| 592 */ | |
| 593 class If extends Statement { | |
| 594 Expression condition; | |
| 595 Statement thenStatement; | |
| 596 Statement elseStatement; | |
| 597 SourceInformation sourceInformation; | |
| 598 | |
| 599 Statement get next => null; | |
| 600 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 601 | |
| 602 If(this.condition, this.thenStatement, this.elseStatement, | |
| 603 this.sourceInformation); | |
| 604 | |
| 605 accept(StatementVisitor visitor) => visitor.visitIf(this); | |
| 606 accept1(StatementVisitor1 visitor, arg) => visitor.visitIf(this, arg); | |
| 607 } | |
| 608 | |
| 609 class ExpressionStatement extends Statement { | |
| 610 Statement next; | |
| 611 Expression expression; | |
| 612 | |
| 613 ExpressionStatement(this.expression, this.next); | |
| 614 | |
| 615 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); | |
| 616 accept1(StatementVisitor1 visitor, arg) { | |
| 617 return visitor.visitExpressionStatement(this, arg); | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 class Try extends Statement { | |
| 622 Statement tryBody; | |
| 623 List<Variable> catchParameters; | |
| 624 Statement catchBody; | |
| 625 | |
| 626 Statement get next => null; | |
| 627 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 628 | |
| 629 Try(this.tryBody, this.catchParameters, this.catchBody) { | |
| 630 for (Variable variable in catchParameters) { | |
| 631 variable.writeCount++; // Being a catch parameter counts as a write. | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 accept(StatementVisitor visitor) => visitor.visitTry(this); | |
| 636 accept1(StatementVisitor1 visitor, arg) { | |
| 637 return visitor.visitTry(this, arg); | |
| 638 } | |
| 639 } | |
| 640 | |
| 641 /// A statement that is known to be unreachable. | |
| 642 class Unreachable extends Statement { | |
| 643 Statement get next => null; | |
| 644 void set next(Statement value) => throw 'UNREACHABLE'; | |
| 645 | |
| 646 accept(StatementVisitor visitor) => visitor.visitUnreachable(this); | |
| 647 accept1(StatementVisitor1 visitor, arg) { | |
| 648 return visitor.visitUnreachable(this, arg); | |
| 649 } | |
| 650 } | |
| 651 | |
| 652 class FunctionDefinition extends Node { | |
| 653 final ExecutableElement element; | |
| 654 final List<Variable> parameters; | |
| 655 final SourceInformation sourceInformation; | |
| 656 Statement body; | |
| 657 | |
| 658 /// Creates a function definition and updates `writeCount` for [parameters]. | |
| 659 FunctionDefinition(this.element, this.parameters, this.body, | |
| 660 {this.sourceInformation}) { | |
| 661 for (Variable param in parameters) { | |
| 662 param.writeCount++; // Being a parameter counts as a write. | |
| 663 } | |
| 664 } | |
| 665 } | |
| 666 | |
| 667 class CreateBox extends Expression { | |
| 668 accept(ExpressionVisitor visitor) => visitor.visitCreateBox(this); | |
| 669 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitCreateBox(this, arg); | |
| 670 } | |
| 671 | |
| 672 class CreateInstance extends Expression { | |
| 673 ClassElement classElement; | |
| 674 List<Expression> arguments; | |
| 675 Expression typeInformation; | |
| 676 SourceInformation sourceInformation; | |
| 677 | |
| 678 CreateInstance(this.classElement, this.arguments, this.typeInformation, | |
| 679 this.sourceInformation); | |
| 680 | |
| 681 accept(ExpressionVisitor visitor) => visitor.visitCreateInstance(this); | |
| 682 accept1(ExpressionVisitor1 visitor, arg) { | |
| 683 return visitor.visitCreateInstance(this, arg); | |
| 684 } | |
| 685 } | |
| 686 | |
| 687 class GetField extends Expression { | |
| 688 Expression object; | |
| 689 Element field; | |
| 690 bool objectIsNotNull; | |
| 691 SourceInformation sourceInformation; | |
| 692 | |
| 693 GetField(this.object, this.field, this.sourceInformation, | |
| 694 {this.objectIsNotNull: false}); | |
| 695 | |
| 696 accept(ExpressionVisitor visitor) => visitor.visitGetField(this); | |
| 697 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitGetField(this, arg); | |
| 698 } | |
| 699 | |
| 700 class SetField extends Expression { | |
| 701 Expression object; | |
| 702 Element field; | |
| 703 Expression value; | |
| 704 SourceInformation sourceInformation; | |
| 705 | |
| 706 /// If non-null, this is a compound assignment to the field, using the given | |
| 707 /// operator. The operator must be a compoundable operator. | |
| 708 BuiltinOperator compound; | |
| 709 | |
| 710 SetField(this.object, this.field, this.value, this.sourceInformation, | |
| 711 {this.compound}); | |
| 712 | |
| 713 accept(ExpressionVisitor visitor) => visitor.visitSetField(this); | |
| 714 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetField(this, arg); | |
| 715 } | |
| 716 | |
| 717 /// Read the type test property from [object]. The value is truthy/fasly rather | |
| 718 /// than bool. [object] must not be `null`. | |
| 719 class GetTypeTestProperty extends Expression { | |
| 720 Expression object; | |
| 721 DartType dartType; | |
| 722 | |
| 723 GetTypeTestProperty(this.object, this.dartType); | |
| 724 | |
| 725 accept(ExpressionVisitor visitor) => visitor.visitGetTypeTestProperty(this); | |
| 726 accept1(ExpressionVisitor1 visitor, arg) => | |
| 727 visitor.visitGetTypeTestProperty(this, arg); | |
| 728 } | |
| 729 | |
| 730 /// Read the value of a field, possibly provoking its initializer to evaluate, | |
| 731 /// or tear off a static method. | |
| 732 class GetStatic extends Expression { | |
| 733 Element element; | |
| 734 SourceInformation sourceInformation; | |
| 735 bool useLazyGetter = false; | |
| 736 | |
| 737 GetStatic(this.element, this.sourceInformation); | |
| 738 | |
| 739 GetStatic.lazy(this.element, this.sourceInformation) : useLazyGetter = true; | |
| 740 | |
| 741 accept(ExpressionVisitor visitor) => visitor.visitGetStatic(this); | |
| 742 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitGetStatic(this, arg); | |
| 743 } | |
| 744 | |
| 745 class SetStatic extends Expression { | |
| 746 Element element; | |
| 747 Expression value; | |
| 748 SourceInformation sourceInformation; | |
| 749 BuiltinOperator compound; | |
| 750 | |
| 751 SetStatic(this.element, this.value, this.sourceInformation, {this.compound}); | |
| 752 | |
| 753 accept(ExpressionVisitor visitor) => visitor.visitSetStatic(this); | |
| 754 accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetStatic(this, arg); | |
| 755 } | |
| 756 | |
| 757 class GetLength extends Expression { | |
| 758 Expression object; | |
| 759 | |
| 760 GetLength(this.object); | |
| 761 | |
| 762 accept(ExpressionVisitor v) => v.visitGetLength(this); | |
| 763 accept1(ExpressionVisitor1 v, arg) => v.visitGetLength(this, arg); | |
| 764 } | |
| 765 | |
| 766 class GetIndex extends Expression { | |
| 767 Expression object; | |
| 768 Expression index; | |
| 769 | |
| 770 GetIndex(this.object, this.index); | |
| 771 | |
| 772 accept(ExpressionVisitor v) => v.visitGetIndex(this); | |
| 773 accept1(ExpressionVisitor1 v, arg) => v.visitGetIndex(this, arg); | |
| 774 } | |
| 775 | |
| 776 class SetIndex extends Expression { | |
| 777 Expression object; | |
| 778 Expression index; | |
| 779 Expression value; | |
| 780 BuiltinOperator compound; | |
| 781 | |
| 782 SetIndex(this.object, this.index, this.value, {this.compound}); | |
| 783 | |
| 784 accept(ExpressionVisitor v) => v.visitSetIndex(this); | |
| 785 accept1(ExpressionVisitor1 v, arg) => v.visitSetIndex(this, arg); | |
| 786 } | |
| 787 | |
| 788 class ReifyRuntimeType extends Expression { | |
| 789 Expression value; | |
| 790 SourceInformation sourceInformation; | |
| 791 | |
| 792 ReifyRuntimeType(this.value, this.sourceInformation); | |
| 793 | |
| 794 accept(ExpressionVisitor visitor) { | |
| 795 return visitor.visitReifyRuntimeType(this); | |
| 796 } | |
| 797 | |
| 798 accept1(ExpressionVisitor1 visitor, arg) { | |
| 799 return visitor.visitReifyRuntimeType(this, arg); | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 class ReadTypeVariable extends Expression { | |
| 804 final TypeVariableType variable; | |
| 805 Expression target; | |
| 806 final SourceInformation sourceInformation; | |
| 807 | |
| 808 ReadTypeVariable(this.variable, this.target, this.sourceInformation); | |
| 809 | |
| 810 accept(ExpressionVisitor visitor) { | |
| 811 return visitor.visitReadTypeVariable(this); | |
| 812 } | |
| 813 | |
| 814 accept1(ExpressionVisitor1 visitor, arg) { | |
| 815 return visitor.visitReadTypeVariable(this, arg); | |
| 816 } | |
| 817 } | |
| 818 | |
| 819 class CreateInvocationMirror extends Expression { | |
| 820 final Selector selector; | |
| 821 final List<Expression> arguments; | |
| 822 | |
| 823 CreateInvocationMirror(this.selector, this.arguments); | |
| 824 | |
| 825 accept(ExpressionVisitor visitor) { | |
| 826 return visitor.visitCreateInvocationMirror(this); | |
| 827 } | |
| 828 | |
| 829 accept1(ExpressionVisitor1 visitor, arg) { | |
| 830 return visitor.visitCreateInvocationMirror(this, arg); | |
| 831 } | |
| 832 } | |
| 833 | |
| 834 class Interceptor extends Expression { | |
| 835 Expression input; | |
| 836 Set<ClassElement> interceptedClasses; | |
| 837 final SourceInformation sourceInformation; | |
| 838 | |
| 839 Interceptor(this.input, this.interceptedClasses, this.sourceInformation); | |
| 840 | |
| 841 accept(ExpressionVisitor visitor) { | |
| 842 return visitor.visitInterceptor(this); | |
| 843 } | |
| 844 | |
| 845 accept1(ExpressionVisitor1 visitor, arg) { | |
| 846 return visitor.visitInterceptor(this, arg); | |
| 847 } | |
| 848 } | |
| 849 | |
| 850 class ForeignCode extends Node { | |
| 851 final js.Template codeTemplate; | |
| 852 final types.TypeMask type; | |
| 853 final List<Expression> arguments; | |
| 854 final native.NativeBehavior nativeBehavior; | |
| 855 final List<bool> nullableArguments; // One 'bit' per argument. | |
| 856 final Element dependency; | |
| 857 final SourceInformation sourceInformation; | |
| 858 | |
| 859 ForeignCode(this.codeTemplate, this.type, this.arguments, this.nativeBehavior, | |
| 860 this.nullableArguments, this.dependency, this.sourceInformation) { | |
| 861 assert(arguments.length == nullableArguments.length); | |
| 862 } | |
| 863 } | |
| 864 | |
| 865 class ForeignExpression extends ForeignCode implements Expression { | |
| 866 ForeignExpression( | |
| 867 js.Template codeTemplate, | |
| 868 types.TypeMask type, | |
| 869 List<Expression> arguments, | |
| 870 native.NativeBehavior nativeBehavior, | |
| 871 List<bool> nullableArguments, | |
| 872 Element dependency, | |
| 873 SourceInformation sourceInformation) | |
| 874 : super(codeTemplate, type, arguments, nativeBehavior, nullableArguments, | |
| 875 dependency, sourceInformation); | |
| 876 | |
| 877 accept(ExpressionVisitor visitor) { | |
| 878 return visitor.visitForeignExpression(this); | |
| 879 } | |
| 880 | |
| 881 accept1(ExpressionVisitor1 visitor, arg) { | |
| 882 return visitor.visitForeignExpression(this, arg); | |
| 883 } | |
| 884 } | |
| 885 | |
| 886 class ForeignStatement extends ForeignCode implements Statement { | |
| 887 ForeignStatement( | |
| 888 js.Template codeTemplate, | |
| 889 types.TypeMask type, | |
| 890 List<Expression> arguments, | |
| 891 native.NativeBehavior nativeBehavior, | |
| 892 List<bool> nullableArguments, | |
| 893 Element dependency, | |
| 894 SourceInformation sourceInformation) | |
| 895 : super(codeTemplate, type, arguments, nativeBehavior, nullableArguments, | |
| 896 dependency, sourceInformation); | |
| 897 | |
| 898 accept(StatementVisitor visitor) { | |
| 899 return visitor.visitForeignStatement(this); | |
| 900 } | |
| 901 | |
| 902 accept1(StatementVisitor1 visitor, arg) { | |
| 903 return visitor.visitForeignStatement(this, arg); | |
| 904 } | |
| 905 | |
| 906 @override | |
| 907 Statement get next => null; | |
| 908 | |
| 909 @override | |
| 910 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 911 } | |
| 912 | |
| 913 /// Denotes the internal representation of [dartType], where all type variables | |
| 914 /// are replaced by the values in [arguments]. | |
| 915 /// (See documentation on the TypeExpression CPS node for more details.) | |
| 916 class TypeExpression extends Expression { | |
| 917 final TypeExpressionKind kind; | |
| 918 final DartType dartType; | |
| 919 final List<Expression> arguments; | |
| 920 | |
| 921 TypeExpression(this.kind, this.dartType, this.arguments); | |
| 922 | |
| 923 accept(ExpressionVisitor visitor) { | |
| 924 return visitor.visitTypeExpression(this); | |
| 925 } | |
| 926 | |
| 927 accept1(ExpressionVisitor1 visitor, arg) { | |
| 928 return visitor.visitTypeExpression(this, arg); | |
| 929 } | |
| 930 } | |
| 931 | |
| 932 class Await extends Expression { | |
| 933 Expression input; | |
| 934 | |
| 935 Await(this.input); | |
| 936 | |
| 937 accept(ExpressionVisitor visitor) { | |
| 938 return visitor.visitAwait(this); | |
| 939 } | |
| 940 | |
| 941 accept1(ExpressionVisitor1 visitor, arg) { | |
| 942 return visitor.visitAwait(this, arg); | |
| 943 } | |
| 944 } | |
| 945 | |
| 946 class Yield extends Statement { | |
| 947 Statement next; | |
| 948 Expression input; | |
| 949 final bool hasStar; | |
| 950 | |
| 951 Yield(this.input, this.hasStar, this.next); | |
| 952 | |
| 953 accept(StatementVisitor visitor) { | |
| 954 return visitor.visitYield(this); | |
| 955 } | |
| 956 | |
| 957 accept1(StatementVisitor1 visitor, arg) { | |
| 958 return visitor.visitYield(this, arg); | |
| 959 } | |
| 960 } | |
| 961 | |
| 962 class ReceiverCheck extends Statement { | |
| 963 Expression condition; | |
| 964 Expression value; | |
| 965 Selector selector; | |
| 966 bool useSelector; | |
| 967 bool useInvoke; | |
| 968 Statement next; | |
| 969 SourceInformation sourceInformation; | |
| 970 | |
| 971 ReceiverCheck( | |
| 972 {this.condition, | |
| 973 this.value, | |
| 974 this.selector, | |
| 975 this.useSelector, | |
| 976 this.useInvoke, | |
| 977 this.next, | |
| 978 this.sourceInformation}); | |
| 979 | |
| 980 accept(StatementVisitor visitor) { | |
| 981 return visitor.visitReceiverCheck(this); | |
| 982 } | |
| 983 | |
| 984 accept1(StatementVisitor1 visitor, arg) { | |
| 985 return visitor.visitReceiverCheck(this, arg); | |
| 986 } | |
| 987 } | |
| 988 | |
| 989 abstract class ExpressionVisitor<E> { | |
| 990 E visitExpression(Expression node) => node.accept(this); | |
| 991 E visitVariableUse(VariableUse node); | |
| 992 E visitAssign(Assign node); | |
| 993 E visitInvokeStatic(InvokeStatic node); | |
| 994 E visitInvokeMethod(InvokeMethod node); | |
| 995 E visitInvokeMethodDirectly(InvokeMethodDirectly node); | |
| 996 E visitInvokeConstructor(InvokeConstructor node); | |
| 997 E visitOneShotInterceptor(OneShotInterceptor node); | |
| 998 E visitConstant(Constant node); | |
| 999 E visitThis(This node); | |
| 1000 E visitConditional(Conditional node); | |
| 1001 E visitLogicalOperator(LogicalOperator node); | |
| 1002 E visitNot(Not node); | |
| 1003 E visitLiteralList(LiteralList node); | |
| 1004 E visitTypeOperator(TypeOperator node); | |
| 1005 E visitGetField(GetField node); | |
| 1006 E visitSetField(SetField node); | |
| 1007 E visitGetStatic(GetStatic node); | |
| 1008 E visitSetStatic(SetStatic node); | |
| 1009 E visitGetTypeTestProperty(GetTypeTestProperty node); | |
| 1010 E visitCreateBox(CreateBox node); | |
| 1011 E visitCreateInstance(CreateInstance node); | |
| 1012 E visitReifyRuntimeType(ReifyRuntimeType node); | |
| 1013 E visitReadTypeVariable(ReadTypeVariable node); | |
| 1014 E visitTypeExpression(TypeExpression node); | |
| 1015 E visitCreateInvocationMirror(CreateInvocationMirror node); | |
| 1016 E visitInterceptor(Interceptor node); | |
| 1017 E visitApplyBuiltinOperator(ApplyBuiltinOperator node); | |
| 1018 E visitApplyBuiltinMethod(ApplyBuiltinMethod node); | |
| 1019 E visitForeignExpression(ForeignExpression node); | |
| 1020 E visitGetLength(GetLength node); | |
| 1021 E visitGetIndex(GetIndex node); | |
| 1022 E visitSetIndex(SetIndex node); | |
| 1023 E visitAwait(Await node); | |
| 1024 } | |
| 1025 | |
| 1026 abstract class ExpressionVisitor1<E, A> { | |
| 1027 E visitExpression(Expression node, A arg) => node.accept1(this, arg); | |
| 1028 E visitVariableUse(VariableUse node, A arg); | |
| 1029 E visitAssign(Assign node, A arg); | |
| 1030 E visitInvokeStatic(InvokeStatic node, A arg); | |
| 1031 E visitInvokeMethod(InvokeMethod node, A arg); | |
| 1032 E visitInvokeMethodDirectly(InvokeMethodDirectly node, A arg); | |
| 1033 E visitInvokeConstructor(InvokeConstructor node, A arg); | |
| 1034 E visitOneShotInterceptor(OneShotInterceptor node, A arg); | |
| 1035 E visitConstant(Constant node, A arg); | |
| 1036 E visitThis(This node, A arg); | |
| 1037 E visitConditional(Conditional node, A arg); | |
| 1038 E visitLogicalOperator(LogicalOperator node, A arg); | |
| 1039 E visitNot(Not node, A arg); | |
| 1040 E visitLiteralList(LiteralList node, A arg); | |
| 1041 E visitTypeOperator(TypeOperator node, A arg); | |
| 1042 E visitGetField(GetField node, A arg); | |
| 1043 E visitSetField(SetField node, A arg); | |
| 1044 E visitGetStatic(GetStatic node, A arg); | |
| 1045 E visitSetStatic(SetStatic node, A arg); | |
| 1046 E visitGetTypeTestProperty(GetTypeTestProperty node, A arg); | |
| 1047 E visitCreateBox(CreateBox node, A arg); | |
| 1048 E visitCreateInstance(CreateInstance node, A arg); | |
| 1049 E visitReifyRuntimeType(ReifyRuntimeType node, A arg); | |
| 1050 E visitReadTypeVariable(ReadTypeVariable node, A arg); | |
| 1051 E visitTypeExpression(TypeExpression node, A arg); | |
| 1052 E visitCreateInvocationMirror(CreateInvocationMirror node, A arg); | |
| 1053 E visitInterceptor(Interceptor node, A arg); | |
| 1054 E visitApplyBuiltinOperator(ApplyBuiltinOperator node, A arg); | |
| 1055 E visitApplyBuiltinMethod(ApplyBuiltinMethod node, A arg); | |
| 1056 E visitForeignExpression(ForeignExpression node, A arg); | |
| 1057 E visitGetLength(GetLength node, A arg); | |
| 1058 E visitGetIndex(GetIndex node, A arg); | |
| 1059 E visitSetIndex(SetIndex node, A arg); | |
| 1060 E visitAwait(Await node, A arg); | |
| 1061 } | |
| 1062 | |
| 1063 abstract class StatementVisitor<S> { | |
| 1064 S visitStatement(Statement node) => node.accept(this); | |
| 1065 S visitLabeledStatement(LabeledStatement node); | |
| 1066 S visitReturn(Return node); | |
| 1067 S visitThrow(Throw node); | |
| 1068 S visitBreak(Break node); | |
| 1069 S visitContinue(Continue node); | |
| 1070 S visitIf(If node); | |
| 1071 S visitWhileTrue(WhileTrue node); | |
| 1072 S visitFor(For node); | |
| 1073 S visitExpressionStatement(ExpressionStatement node); | |
| 1074 S visitTry(Try node); | |
| 1075 S visitUnreachable(Unreachable node); | |
| 1076 S visitForeignStatement(ForeignStatement node); | |
| 1077 S visitYield(Yield node); | |
| 1078 S visitReceiverCheck(ReceiverCheck node); | |
| 1079 } | |
| 1080 | |
| 1081 abstract class StatementVisitor1<S, A> { | |
| 1082 S visitStatement(Statement node, A arg) => node.accept1(this, arg); | |
| 1083 S visitLabeledStatement(LabeledStatement node, A arg); | |
| 1084 S visitReturn(Return node, A arg); | |
| 1085 S visitThrow(Throw node, A arg); | |
| 1086 S visitBreak(Break node, A arg); | |
| 1087 S visitContinue(Continue node, A arg); | |
| 1088 S visitIf(If node, A arg); | |
| 1089 S visitWhileTrue(WhileTrue node, A arg); | |
| 1090 S visitFor(For node, A arg); | |
| 1091 S visitExpressionStatement(ExpressionStatement node, A arg); | |
| 1092 S visitTry(Try node, A arg); | |
| 1093 S visitUnreachable(Unreachable node, A arg); | |
| 1094 S visitForeignStatement(ForeignStatement node, A arg); | |
| 1095 S visitYield(Yield node, A arg); | |
| 1096 S visitReceiverCheck(ReceiverCheck node, A arg); | |
| 1097 } | |
| 1098 | |
| 1099 abstract class RecursiveVisitor implements StatementVisitor, ExpressionVisitor { | |
| 1100 visitExpression(Expression e) => e.accept(this); | |
| 1101 visitStatement(Statement s) => s.accept(this); | |
| 1102 | |
| 1103 visitVariable(Variable variable) {} | |
| 1104 | |
| 1105 visitVariableUse(VariableUse node) { | |
| 1106 visitVariable(node.variable); | |
| 1107 } | |
| 1108 | |
| 1109 visitAssign(Assign node) { | |
| 1110 visitVariable(node.variable); | |
| 1111 visitExpression(node.value); | |
| 1112 } | |
| 1113 | |
| 1114 visitInvokeStatic(InvokeStatic node) { | |
| 1115 node.arguments.forEach(visitExpression); | |
| 1116 } | |
| 1117 | |
| 1118 visitInvokeMethod(InvokeMethod node) { | |
| 1119 visitExpression(node.receiver); | |
| 1120 node.arguments.forEach(visitExpression); | |
| 1121 } | |
| 1122 | |
| 1123 visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 1124 visitExpression(node.receiver); | |
| 1125 node.arguments.forEach(visitExpression); | |
| 1126 } | |
| 1127 | |
| 1128 visitInvokeConstructor(InvokeConstructor node) { | |
| 1129 node.arguments.forEach(visitExpression); | |
| 1130 } | |
| 1131 | |
| 1132 visitOneShotInterceptor(OneShotInterceptor node) { | |
| 1133 node.arguments.forEach(visitExpression); | |
| 1134 } | |
| 1135 | |
| 1136 visitConstant(Constant node) {} | |
| 1137 | |
| 1138 visitThis(This node) {} | |
| 1139 | |
| 1140 visitConditional(Conditional node) { | |
| 1141 visitExpression(node.condition); | |
| 1142 visitExpression(node.thenExpression); | |
| 1143 visitExpression(node.elseExpression); | |
| 1144 } | |
| 1145 | |
| 1146 visitLogicalOperator(LogicalOperator node) { | |
| 1147 visitExpression(node.left); | |
| 1148 visitExpression(node.right); | |
| 1149 } | |
| 1150 | |
| 1151 visitNot(Not node) { | |
| 1152 visitExpression(node.operand); | |
| 1153 } | |
| 1154 | |
| 1155 visitLiteralList(LiteralList node) { | |
| 1156 node.values.forEach(visitExpression); | |
| 1157 } | |
| 1158 | |
| 1159 visitTypeOperator(TypeOperator node) { | |
| 1160 visitExpression(node.value); | |
| 1161 node.typeArguments.forEach(visitExpression); | |
| 1162 } | |
| 1163 | |
| 1164 visitLabeledStatement(LabeledStatement node) { | |
| 1165 visitStatement(node.body); | |
| 1166 visitStatement(node.next); | |
| 1167 } | |
| 1168 | |
| 1169 visitReturn(Return node) { | |
| 1170 visitExpression(node.value); | |
| 1171 } | |
| 1172 | |
| 1173 visitThrow(Throw node) { | |
| 1174 visitExpression(node.value); | |
| 1175 } | |
| 1176 | |
| 1177 visitBreak(Break node) {} | |
| 1178 | |
| 1179 visitContinue(Continue node) {} | |
| 1180 | |
| 1181 visitIf(If node) { | |
| 1182 visitExpression(node.condition); | |
| 1183 visitStatement(node.thenStatement); | |
| 1184 visitStatement(node.elseStatement); | |
| 1185 } | |
| 1186 | |
| 1187 visitWhileTrue(WhileTrue node) { | |
| 1188 visitStatement(node.body); | |
| 1189 } | |
| 1190 | |
| 1191 visitFor(For node) { | |
| 1192 visitExpression(node.condition); | |
| 1193 node.updates.forEach(visitExpression); | |
| 1194 visitStatement(node.body); | |
| 1195 visitStatement(node.next); | |
| 1196 } | |
| 1197 | |
| 1198 visitExpressionStatement(ExpressionStatement inputNode) { | |
| 1199 // Iterate over chains of expression statements to avoid deep recursion. | |
| 1200 Statement node = inputNode; | |
| 1201 while (node is ExpressionStatement) { | |
| 1202 ExpressionStatement stmt = node; | |
| 1203 visitExpression(stmt.expression); | |
| 1204 node = stmt.next; | |
| 1205 } | |
| 1206 visitStatement(node); | |
| 1207 } | |
| 1208 | |
| 1209 visitTry(Try node) { | |
| 1210 visitStatement(node.tryBody); | |
| 1211 visitStatement(node.catchBody); | |
| 1212 } | |
| 1213 | |
| 1214 visitGetField(GetField node) { | |
| 1215 visitExpression(node.object); | |
| 1216 } | |
| 1217 | |
| 1218 visitSetField(SetField node) { | |
| 1219 visitExpression(node.object); | |
| 1220 visitExpression(node.value); | |
| 1221 } | |
| 1222 | |
| 1223 visitGetStatic(GetStatic node) {} | |
| 1224 | |
| 1225 visitSetStatic(SetStatic node) { | |
| 1226 visitExpression(node.value); | |
| 1227 } | |
| 1228 | |
| 1229 visitGetTypeTestProperty(GetTypeTestProperty node) { | |
| 1230 visitExpression(node.object); | |
| 1231 } | |
| 1232 | |
| 1233 visitCreateBox(CreateBox node) {} | |
| 1234 | |
| 1235 visitCreateInstance(CreateInstance node) { | |
| 1236 node.arguments.forEach(visitExpression); | |
| 1237 if (node.typeInformation != null) visitExpression(node.typeInformation); | |
| 1238 } | |
| 1239 | |
| 1240 visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 1241 visitExpression(node.value); | |
| 1242 } | |
| 1243 | |
| 1244 visitReadTypeVariable(ReadTypeVariable node) { | |
| 1245 visitExpression(node.target); | |
| 1246 } | |
| 1247 | |
| 1248 visitTypeExpression(TypeExpression node) { | |
| 1249 node.arguments.forEach(visitExpression); | |
| 1250 } | |
| 1251 | |
| 1252 visitCreateInvocationMirror(CreateInvocationMirror node) { | |
| 1253 node.arguments.forEach(visitExpression); | |
| 1254 } | |
| 1255 | |
| 1256 visitUnreachable(Unreachable node) {} | |
| 1257 | |
| 1258 visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | |
| 1259 node.arguments.forEach(visitExpression); | |
| 1260 } | |
| 1261 | |
| 1262 visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | |
| 1263 visitExpression(node.receiver); | |
| 1264 node.arguments.forEach(visitExpression); | |
| 1265 } | |
| 1266 | |
| 1267 visitInterceptor(Interceptor node) { | |
| 1268 visitExpression(node.input); | |
| 1269 } | |
| 1270 | |
| 1271 visitForeignCode(ForeignCode node) { | |
| 1272 node.arguments.forEach(visitExpression); | |
| 1273 } | |
| 1274 | |
| 1275 visitForeignExpression(ForeignExpression node) => visitForeignCode(node); | |
| 1276 visitForeignStatement(ForeignStatement node) => visitForeignCode(node); | |
| 1277 | |
| 1278 visitGetLength(GetLength node) { | |
| 1279 visitExpression(node.object); | |
| 1280 } | |
| 1281 | |
| 1282 visitGetIndex(GetIndex node) { | |
| 1283 visitExpression(node.object); | |
| 1284 visitExpression(node.index); | |
| 1285 } | |
| 1286 | |
| 1287 visitSetIndex(SetIndex node) { | |
| 1288 visitExpression(node.object); | |
| 1289 visitExpression(node.index); | |
| 1290 visitExpression(node.value); | |
| 1291 } | |
| 1292 | |
| 1293 visitAwait(Await node) { | |
| 1294 visitExpression(node.input); | |
| 1295 } | |
| 1296 | |
| 1297 visitYield(Yield node) { | |
| 1298 visitExpression(node.input); | |
| 1299 visitStatement(node.next); | |
| 1300 } | |
| 1301 | |
| 1302 visitReceiverCheck(ReceiverCheck node) { | |
| 1303 if (node.condition != null) visitExpression(node.condition); | |
| 1304 visitExpression(node.value); | |
| 1305 visitStatement(node.next); | |
| 1306 } | |
| 1307 } | |
| 1308 | |
| 1309 abstract class Transformer | |
| 1310 implements ExpressionVisitor<Expression>, StatementVisitor<Statement> { | |
| 1311 Expression visitExpression(Expression e) => e.accept(this); | |
| 1312 Statement visitStatement(Statement s) => s.accept(this); | |
| 1313 } | |
| 1314 | |
| 1315 class RecursiveTransformer extends Transformer { | |
| 1316 void _replaceExpressions(List<Expression> list) { | |
| 1317 for (int i = 0; i < list.length; i++) { | |
| 1318 list[i] = visitExpression(list[i]); | |
| 1319 } | |
| 1320 } | |
| 1321 | |
| 1322 visitVariableUse(VariableUse node) => node; | |
| 1323 | |
| 1324 visitAssign(Assign node) { | |
| 1325 node.value = visitExpression(node.value); | |
| 1326 return node; | |
| 1327 } | |
| 1328 | |
| 1329 visitInvokeStatic(InvokeStatic node) { | |
| 1330 _replaceExpressions(node.arguments); | |
| 1331 return node; | |
| 1332 } | |
| 1333 | |
| 1334 visitInvokeMethod(InvokeMethod node) { | |
| 1335 node.receiver = visitExpression(node.receiver); | |
| 1336 _replaceExpressions(node.arguments); | |
| 1337 return node; | |
| 1338 } | |
| 1339 | |
| 1340 visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 1341 node.receiver = visitExpression(node.receiver); | |
| 1342 _replaceExpressions(node.arguments); | |
| 1343 return node; | |
| 1344 } | |
| 1345 | |
| 1346 visitInvokeConstructor(InvokeConstructor node) { | |
| 1347 _replaceExpressions(node.arguments); | |
| 1348 return node; | |
| 1349 } | |
| 1350 | |
| 1351 visitOneShotInterceptor(OneShotInterceptor node) { | |
| 1352 _replaceExpressions(node.arguments); | |
| 1353 return node; | |
| 1354 } | |
| 1355 | |
| 1356 visitConstant(Constant node) => node; | |
| 1357 | |
| 1358 visitThis(This node) => node; | |
| 1359 | |
| 1360 visitConditional(Conditional node) { | |
| 1361 node.condition = visitExpression(node.condition); | |
| 1362 node.thenExpression = visitExpression(node.thenExpression); | |
| 1363 node.elseExpression = visitExpression(node.elseExpression); | |
| 1364 return node; | |
| 1365 } | |
| 1366 | |
| 1367 visitLogicalOperator(LogicalOperator node) { | |
| 1368 node.left = visitExpression(node.left); | |
| 1369 node.right = visitExpression(node.right); | |
| 1370 return node; | |
| 1371 } | |
| 1372 | |
| 1373 visitNot(Not node) { | |
| 1374 node.operand = visitExpression(node.operand); | |
| 1375 return node; | |
| 1376 } | |
| 1377 | |
| 1378 visitLiteralList(LiteralList node) { | |
| 1379 _replaceExpressions(node.values); | |
| 1380 return node; | |
| 1381 } | |
| 1382 | |
| 1383 visitTypeOperator(TypeOperator node) { | |
| 1384 node.value = visitExpression(node.value); | |
| 1385 _replaceExpressions(node.typeArguments); | |
| 1386 return node; | |
| 1387 } | |
| 1388 | |
| 1389 visitLabeledStatement(LabeledStatement node) { | |
| 1390 node.body = visitStatement(node.body); | |
| 1391 node.next = visitStatement(node.next); | |
| 1392 return node; | |
| 1393 } | |
| 1394 | |
| 1395 visitReturn(Return node) { | |
| 1396 node.value = visitExpression(node.value); | |
| 1397 return node; | |
| 1398 } | |
| 1399 | |
| 1400 visitThrow(Throw node) { | |
| 1401 node.value = visitExpression(node.value); | |
| 1402 return node; | |
| 1403 } | |
| 1404 | |
| 1405 visitBreak(Break node) => node; | |
| 1406 | |
| 1407 visitContinue(Continue node) => node; | |
| 1408 | |
| 1409 visitIf(If node) { | |
| 1410 node.condition = visitExpression(node.condition); | |
| 1411 node.thenStatement = visitStatement(node.thenStatement); | |
| 1412 node.elseStatement = visitStatement(node.elseStatement); | |
| 1413 return node; | |
| 1414 } | |
| 1415 | |
| 1416 visitWhileTrue(WhileTrue node) { | |
| 1417 node.body = visitStatement(node.body); | |
| 1418 return node; | |
| 1419 } | |
| 1420 | |
| 1421 visitFor(For node) { | |
| 1422 node.condition = visitExpression(node.condition); | |
| 1423 _replaceExpressions(node.updates); | |
| 1424 node.body = visitStatement(node.body); | |
| 1425 node.next = visitStatement(node.next); | |
| 1426 return node; | |
| 1427 } | |
| 1428 | |
| 1429 visitExpressionStatement(ExpressionStatement node) { | |
| 1430 // Iterate over chains of expression statements to avoid deep recursion. | |
| 1431 Statement first = node; | |
| 1432 while (true) { | |
| 1433 node.expression = visitExpression(node.expression); | |
| 1434 if (node.next is ExpressionStatement) { | |
| 1435 node = node.next; | |
| 1436 } else { | |
| 1437 break; | |
| 1438 } | |
| 1439 } | |
| 1440 node.next = visitStatement(node.next); | |
| 1441 return first; | |
| 1442 } | |
| 1443 | |
| 1444 visitTry(Try node) { | |
| 1445 node.tryBody = visitStatement(node.tryBody); | |
| 1446 node.catchBody = visitStatement(node.catchBody); | |
| 1447 return node; | |
| 1448 } | |
| 1449 | |
| 1450 visitGetField(GetField node) { | |
| 1451 node.object = visitExpression(node.object); | |
| 1452 return node; | |
| 1453 } | |
| 1454 | |
| 1455 visitSetField(SetField node) { | |
| 1456 node.object = visitExpression(node.object); | |
| 1457 node.value = visitExpression(node.value); | |
| 1458 return node; | |
| 1459 } | |
| 1460 | |
| 1461 visitGetStatic(GetStatic node) => node; | |
| 1462 | |
| 1463 visitSetStatic(SetStatic node) { | |
| 1464 node.value = visitExpression(node.value); | |
| 1465 return node; | |
| 1466 } | |
| 1467 | |
| 1468 visitGetTypeTestProperty(GetTypeTestProperty node) { | |
| 1469 node.object = visitExpression(node.object); | |
| 1470 return node; | |
| 1471 } | |
| 1472 | |
| 1473 visitCreateBox(CreateBox node) => node; | |
| 1474 | |
| 1475 visitCreateInstance(CreateInstance node) { | |
| 1476 _replaceExpressions(node.arguments); | |
| 1477 if (node.typeInformation != null) { | |
| 1478 node.typeInformation = visitExpression(node.typeInformation); | |
| 1479 } | |
| 1480 return node; | |
| 1481 } | |
| 1482 | |
| 1483 visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 1484 node.value = visitExpression(node.value); | |
| 1485 return node; | |
| 1486 } | |
| 1487 | |
| 1488 visitReadTypeVariable(ReadTypeVariable node) { | |
| 1489 node.target = visitExpression(node.target); | |
| 1490 return node; | |
| 1491 } | |
| 1492 | |
| 1493 visitTypeExpression(TypeExpression node) { | |
| 1494 _replaceExpressions(node.arguments); | |
| 1495 return node; | |
| 1496 } | |
| 1497 | |
| 1498 visitCreateInvocationMirror(CreateInvocationMirror node) { | |
| 1499 _replaceExpressions(node.arguments); | |
| 1500 return node; | |
| 1501 } | |
| 1502 | |
| 1503 visitForeignExpression(ForeignExpression node) { | |
| 1504 _replaceExpressions(node.arguments); | |
| 1505 return node; | |
| 1506 } | |
| 1507 | |
| 1508 visitForeignStatement(ForeignStatement node) { | |
| 1509 _replaceExpressions(node.arguments); | |
| 1510 return node; | |
| 1511 } | |
| 1512 | |
| 1513 visitUnreachable(Unreachable node) { | |
| 1514 return node; | |
| 1515 } | |
| 1516 | |
| 1517 visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | |
| 1518 _replaceExpressions(node.arguments); | |
| 1519 return node; | |
| 1520 } | |
| 1521 | |
| 1522 visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | |
| 1523 node.receiver = visitExpression(node.receiver); | |
| 1524 _replaceExpressions(node.arguments); | |
| 1525 return node; | |
| 1526 } | |
| 1527 | |
| 1528 visitInterceptor(Interceptor node) { | |
| 1529 node.input = visitExpression(node.input); | |
| 1530 return node; | |
| 1531 } | |
| 1532 | |
| 1533 visitGetLength(GetLength node) { | |
| 1534 node.object = visitExpression(node.object); | |
| 1535 return node; | |
| 1536 } | |
| 1537 | |
| 1538 visitGetIndex(GetIndex node) { | |
| 1539 node.object = visitExpression(node.object); | |
| 1540 node.index = visitExpression(node.index); | |
| 1541 return node; | |
| 1542 } | |
| 1543 | |
| 1544 visitSetIndex(SetIndex node) { | |
| 1545 node.object = visitExpression(node.object); | |
| 1546 node.index = visitExpression(node.index); | |
| 1547 node.value = visitExpression(node.value); | |
| 1548 return node; | |
| 1549 } | |
| 1550 | |
| 1551 visitAwait(Await node) { | |
| 1552 node.input = visitExpression(node.input); | |
| 1553 return node; | |
| 1554 } | |
| 1555 | |
| 1556 visitYield(Yield node) { | |
| 1557 node.input = visitExpression(node.input); | |
| 1558 node.next = visitStatement(node.next); | |
| 1559 return node; | |
| 1560 } | |
| 1561 | |
| 1562 visitReceiverCheck(ReceiverCheck node) { | |
| 1563 if (node.condition != null) { | |
| 1564 node.condition = visitExpression(node.condition); | |
| 1565 } | |
| 1566 node.value = visitExpression(node.value); | |
| 1567 node.next = visitStatement(node.next); | |
| 1568 return node; | |
| 1569 } | |
| 1570 } | |
| 1571 | |
| 1572 class FallthroughTarget { | |
| 1573 final Statement target; | |
| 1574 int useCount = 0; | |
| 1575 | |
| 1576 FallthroughTarget(this.target); | |
| 1577 } | |
| 1578 | |
| 1579 /// A stack machine for tracking fallthrough while traversing the Tree IR. | |
| 1580 class FallthroughStack { | |
| 1581 final List<FallthroughTarget> _stack = <FallthroughTarget>[ | |
| 1582 new FallthroughTarget(null) | |
| 1583 ]; | |
| 1584 | |
| 1585 /// Set a new fallthrough target. | |
| 1586 void push(Statement newFallthrough) { | |
| 1587 _stack.add(new FallthroughTarget(newFallthrough)); | |
| 1588 } | |
| 1589 | |
| 1590 /// Remove the current fallthrough target. | |
| 1591 void pop() { | |
| 1592 _stack.removeLast(); | |
| 1593 } | |
| 1594 | |
| 1595 /// The current fallthrough target, or `null` if control will fall over | |
| 1596 /// the end of the method. | |
| 1597 Statement get target => _stack.last.target; | |
| 1598 | |
| 1599 /// Number of uses of the current fallthrough target. | |
| 1600 int get useCount => _stack.last.useCount; | |
| 1601 | |
| 1602 /// Indicate that a statement will fall through to the current fallthrough | |
| 1603 /// target. | |
| 1604 void use() { | |
| 1605 ++_stack.last.useCount; | |
| 1606 } | |
| 1607 } | |
| OLD | NEW |