| 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 // IrNodes are kept in a separate library to have precise control over their | 5 // IrNodes are kept in a separate library to have precise control over their |
| 6 // dependencies on other parts of the system. | 6 // dependencies on other parts of the system. |
| 7 library dart2js.ir_nodes; | 7 library dart2js.ir_nodes; |
| 8 | 8 |
| 9 import '../dart2jslib.dart' as dart2js show Constant; | 9 import '../dart2jslib.dart' as dart2js show Constant; |
| 10 import '../elements/elements.dart' | 10 import '../elements/elements.dart' |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 /// The base class of things that variables can refer to: primitives, | 26 /// The base class of things that variables can refer to: primitives, |
| 27 /// continuations, function and continuation parameters, etc. | 27 /// continuations, function and continuation parameters, etc. |
| 28 abstract class Definition extends Node { | 28 abstract class Definition extends Node { |
| 29 // The head of a linked-list of occurrences, in no particular order. | 29 // The head of a linked-list of occurrences, in no particular order. |
| 30 Reference firstRef = null; | 30 Reference firstRef = null; |
| 31 | 31 |
| 32 bool get hasAtMostOneUse => firstRef == null || firstRef.nextRef == null; | 32 bool get hasAtMostOneUse => firstRef == null || firstRef.nextRef == null; |
| 33 bool get hasExactlyOneUse => firstRef != null && firstRef.nextRef == null; | 33 bool get hasExactlyOneUse => firstRef != null && firstRef.nextRef == null; |
| 34 bool get hasAtLeastOneUse => firstRef != null; | 34 bool get hasAtLeastOneUse => firstRef != null; |
| 35 |
| 36 void substituteFor(Definition other) { |
| 37 if (other.firstRef == null) return; |
| 38 Reference previous, current = other.firstRef; |
| 39 do { |
| 40 current.definition = this; |
| 41 previous = current; |
| 42 current = current.nextRef; |
| 43 } while (current != null); |
| 44 previous.nextRef = firstRef; |
| 45 firstRef = other.firstRef; |
| 46 } |
| 35 } | 47 } |
| 36 | 48 |
| 37 abstract class Primitive extends Definition { | 49 abstract class Primitive extends Definition { |
| 38 } | 50 } |
| 39 | 51 |
| 40 /// Operands to invocations and primitives are always variables. They point to | 52 /// Operands to invocations and primitives are always variables. They point to |
| 41 /// their definition and are linked into a list of occurrences. | 53 /// their definition and are linked into a list of occurrences. |
| 42 class Reference { | 54 class Reference { |
| 43 Definition definition; | 55 Definition definition; |
| 44 Reference nextRef = null; | 56 Reference nextRef = null; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 assert(selector.kind == SelectorKind.CALL); | 120 assert(selector.kind == SelectorKind.CALL); |
| 109 assert(selector.name == target.name); | 121 assert(selector.name == target.name); |
| 110 } | 122 } |
| 111 | 123 |
| 112 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 124 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
| 113 } | 125 } |
| 114 | 126 |
| 115 /// Invoke a continuation in tail position. | 127 /// Invoke a continuation in tail position. |
| 116 class InvokeContinuation extends Expression { | 128 class InvokeContinuation extends Expression { |
| 117 final Reference continuation; | 129 final Reference continuation; |
| 118 final Reference argument; | 130 final List<Reference> arguments; |
| 119 | 131 |
| 120 InvokeContinuation(Continuation cont, Definition arg) | 132 InvokeContinuation(Continuation cont, List<Definition> args) |
| 121 : continuation = new Reference(cont), | 133 : continuation = new Reference(cont), |
| 122 argument = new Reference(arg); | 134 arguments = args.map((t) => new Reference(t)).toList(growable: false); |
| 135 accept(Visitor visitor) => visitor.visitInvokeContinuation(this); |
| 136 } |
| 123 | 137 |
| 124 accept(Visitor visitor) => visitor.visitInvokeContinuation(this); | 138 /// The base class of things which can be tested and branched on. |
| 139 abstract class Condition extends Node { |
| 140 } |
| 141 |
| 142 class IsTrue extends Condition { |
| 143 final Reference value; |
| 144 |
| 145 IsTrue(Definition val) : value = new Reference(val); |
| 146 |
| 147 accept(Visitor visitor) => visitor.visitIsTrue(this); |
| 148 } |
| 149 |
| 150 /// Choose between a pair of continuations based on a condition value. |
| 151 class Branch extends Expression { |
| 152 final Condition condition; |
| 153 final Reference trueContinuation; |
| 154 final Reference falseContinuation; |
| 155 |
| 156 Branch(this.condition, Continuation trueCont, Continuation falseCont) |
| 157 : trueContinuation = new Reference(trueCont), |
| 158 falseContinuation = new Reference(falseCont); |
| 159 |
| 160 accept(Visitor visitor) => visitor.visitBranch(this); |
| 125 } | 161 } |
| 126 | 162 |
| 127 class Constant extends Primitive { | 163 class Constant extends Primitive { |
| 128 final dart2js.Constant value; | 164 final dart2js.Constant value; |
| 129 | 165 |
| 130 Constant(this.value); | 166 Constant(this.value); |
| 131 | 167 |
| 132 accept(Visitor visitor) => visitor.visitConstant(this); | 168 accept(Visitor visitor) => visitor.visitConstant(this); |
| 133 } | 169 } |
| 134 | 170 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 accept(Visitor visitor) => visitor.visitFunctionDefinition(this); | 206 accept(Visitor visitor) => visitor.visitFunctionDefinition(this); |
| 171 } | 207 } |
| 172 | 208 |
| 173 abstract class Visitor<T> { | 209 abstract class Visitor<T> { |
| 174 T visit(Node node) => node.accept(this); | 210 T visit(Node node) => node.accept(this); |
| 175 // Abstract classes. | 211 // Abstract classes. |
| 176 T visitNode(Node node) => null; | 212 T visitNode(Node node) => null; |
| 177 T visitExpression(Expression node) => visitNode(node); | 213 T visitExpression(Expression node) => visitNode(node); |
| 178 T visitDefinition(Definition node) => visitNode(node); | 214 T visitDefinition(Definition node) => visitNode(node); |
| 179 T visitPrimitive(Primitive node) => visitDefinition(node); | 215 T visitPrimitive(Primitive node) => visitDefinition(node); |
| 216 T visitCondition(Condition node) => visitNode(node); |
| 180 | 217 |
| 181 // Concrete classes. | 218 // Concrete classes. |
| 182 T visitFunctionDefinition(FunctionDefinition node) => visitNode(node); | 219 T visitFunctionDefinition(FunctionDefinition node) => visitNode(node); |
| 183 | 220 |
| 221 // Expressions. |
| 184 T visitLetPrim(LetPrim node) => visitExpression(node); | 222 T visitLetPrim(LetPrim node) => visitExpression(node); |
| 185 T visitLetCont(LetCont node) => visitExpression(node); | 223 T visitLetCont(LetCont node) => visitExpression(node); |
| 186 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); | 224 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); |
| 187 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node); | 225 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node); |
| 226 T visitBranch(Branch node) => visitExpression(node); |
| 188 | 227 |
| 228 // Definitions. |
| 189 T visitConstant(Constant node) => visitPrimitive(node); | 229 T visitConstant(Constant node) => visitPrimitive(node); |
| 190 T visitParameter(Parameter node) => visitPrimitive(node); | 230 T visitParameter(Parameter node) => visitPrimitive(node); |
| 191 T visitContinuation(Continuation node) => visitDefinition(node); | 231 T visitContinuation(Continuation node) => visitDefinition(node); |
| 232 |
| 233 // Conditions. |
| 234 T visitIsTrue(IsTrue node) => visitCondition(node); |
| 192 } | 235 } |
| 193 | 236 |
| 194 /// Generate a Lisp-like S-expression representation of an IR node as a string. | 237 /// Generate a Lisp-like S-expression representation of an IR node as a string. |
| 195 /// The representation is not pretty-printed, but it can easily be quoted and | 238 /// The representation is not pretty-printed, but it can easily be quoted and |
| 196 /// dropped into the REPL of one's favorite Lisp or Scheme implementation to be | 239 /// dropped into the REPL of one's favorite Lisp or Scheme implementation to be |
| 197 /// pretty-printed. | 240 /// pretty-printed. |
| 198 class SExpressionStringifier extends Visitor<String> { | 241 class SExpressionStringifier extends Visitor<String> { |
| 199 final Map<Definition, String> names = <Definition, String>{}; | 242 final Map<Definition, String> names = <Definition, String>{}; |
| 200 | 243 |
| 201 int _valueCounter = 0; | 244 int _valueCounter = 0; |
| 202 int _continuationCounter = 0; | 245 int _continuationCounter = 0; |
| 203 | 246 |
| 204 String newValueName() => 'v${_valueCounter++}'; | 247 String newValueName() => 'v${_valueCounter++}'; |
| 205 String newContinuationName() => 'k${_continuationCounter++}'; | 248 String newContinuationName() => 'k${_continuationCounter++}'; |
| 206 | 249 |
| 207 String visitFunctionDefinition(FunctionDefinition node) { | 250 String visitFunctionDefinition(FunctionDefinition node) { |
| 208 names[node.returnContinuation] = 'return'; | 251 names[node.returnContinuation] = 'return'; |
| 209 String parameters = node.parameters | 252 String parameters = node.parameters |
| 210 .map((p) { | 253 .map((p) { |
| 211 String name = p.element.name; | 254 String name = p.element.name; |
| 212 names[p] = name; | 255 names[p] = name; |
| 213 return name; | 256 return name; |
| 214 }) | 257 }) |
| 215 .join(' '); | 258 .join(' '); |
| 216 return '(FunctionDefinition ($parameters) ${node.body.accept(this)})'; | 259 return '(FunctionDefinition ($parameters) ${visit(node.body)})'; |
| 217 } | 260 } |
| 218 | 261 |
| 219 String visitLetPrim(LetPrim expr) { | 262 String visitLetPrim(LetPrim node) { |
| 220 String name = newValueName(); | 263 String name = newValueName(); |
| 221 names[expr.primitive] = name; | 264 names[node.primitive] = name; |
| 222 String value = expr.primitive.accept(this); | 265 String value = visit(node.primitive); |
| 223 String body = expr.body.accept(this); | 266 String body = visit(node.body); |
| 224 return '(LetPrim $name $value) $body'; | 267 return '(LetPrim $name $value) $body'; |
| 225 } | 268 } |
| 226 | 269 |
| 227 String visitLetCont(LetCont expr) { | 270 String visitLetCont(LetCont node) { |
| 228 String cont = newContinuationName(); | 271 String cont = newContinuationName(); |
| 229 names[expr.continuation] = cont; | 272 names[node.continuation] = cont; |
| 230 String parameters = expr.continuation.parameters | 273 String parameters = node.continuation.parameters |
| 231 .map((p) { | 274 .map((p) { |
| 232 String name = newValueName(); | 275 String name = newValueName(); |
| 233 names[p] = name; | 276 names[p] = name; |
| 234 return name; | 277 return ' $name'; |
| 235 }) | 278 }) |
| 236 .join(' '); | 279 .join(''); |
| 237 String contBody = expr.continuation.body.accept(this); | 280 String contBody = visit(node.continuation.body); |
| 238 String body = expr.body.accept(this); | 281 String body = visit(node.body); |
| 239 return '(LetCont ($cont $parameters) $contBody) $body'; | 282 return '(LetCont ($cont$parameters) $contBody) $body'; |
| 240 } | 283 } |
| 241 | 284 |
| 242 String visitInvokeStatic(InvokeStatic expr) { | 285 String visitInvokeStatic(InvokeStatic node) { |
| 243 String name = expr.target.name; | 286 String name = node.target.name; |
| 244 String cont = names[expr.continuation.definition]; | 287 String cont = names[node.continuation.definition]; |
| 245 String args = expr.arguments.map((v) => names[v.definition]).join(' '); | 288 String args = node.arguments.map((v) => names[v.definition]).join(' '); |
| 246 return '(InvokeStatic $name $cont $args)'; | 289 return '(InvokeStatic $name $cont $args)'; |
| 247 } | 290 } |
| 248 | 291 |
| 249 String visitInvokeContinuation(InvokeContinuation expr) { | 292 String visitInvokeContinuation(InvokeContinuation node) { |
| 250 String cont = names[expr.continuation.definition]; | 293 String cont = names[node.continuation.definition]; |
| 251 String arg = names[expr.argument.definition]; | 294 String args = node.arguments.map((v) => names[v.definition]).join(' '); |
| 252 return '(InvokeContinuation $cont $arg)'; | 295 return '(InvokeContinuation $cont $args)'; |
| 253 } | 296 } |
| 254 | 297 |
| 255 String visitConstant(Constant triv) { | 298 String visitBranch(Branch node) { |
| 256 return '(Constant ${triv.value})'; | 299 String condition = visit(node.condition); |
| 300 String trueCont = names[node.trueContinuation.definition]; |
| 301 String falseCont = names[node.falseContinuation.definition]; |
| 302 return '(Branch $condition $trueCont $falseCont)'; |
| 257 } | 303 } |
| 258 | 304 |
| 259 String visitParameter(Parameter triv) { | 305 String visitConstant(Constant node) { |
| 306 return '(Constant ${node.value})'; |
| 307 } |
| 308 |
| 309 String visitParameter(Parameter node) { |
| 260 // Parameters are visited directly in visitLetCont. | 310 // Parameters are visited directly in visitLetCont. |
| 261 return '(Unexpected Parameter)'; | 311 return '(Unexpected Parameter)'; |
| 262 } | 312 } |
| 263 | 313 |
| 264 String visitContinuation(Continuation triv) { | 314 String visitContinuation(Continuation node) { |
| 265 // Continuations are visited directly in visitLetCont. | 315 // Continuations are visited directly in visitLetCont. |
| 266 return '(Unexpected Continuation)'; | 316 return '(Unexpected Continuation)'; |
| 267 } | 317 } |
| 318 |
| 319 String visitIsTrue(IsTrue node) { |
| 320 String value = names[node.value.definition]; |
| 321 return '(IsTrue $value)'; |
| 322 } |
| 268 } | 323 } |
| OLD | NEW |