Chromium Code Reviews| 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 // TODO(kmillikin): This is still kind of fishy. Refactor to not share | 158 // TODO(kmillikin): This is still kind of fishy. Refactor to not share |
| 159 // name maps or else garbage collect unneeded names. | 159 // name maps or else garbage collect unneeded names. |
| 160 assert(element == null || !variable2index.containsKey(element)); | 160 assert(element == null || !variable2index.containsKey(element)); |
| 161 variable2index[element] = index2variable.length; | 161 variable2index[element] = index2variable.length; |
| 162 index2variable.add(element); | 162 index2variable.add(element); |
| 163 index2value.add(value); | 163 index2value.add(value); |
| 164 } | 164 } |
| 165 | 165 |
| 166 ir.Primitive lookup(Element element) { | 166 ir.Primitive lookup(Element element) { |
| 167 assert(!element.isConst); | 167 assert(!element.isConst); |
| 168 assert(invariant(element, variable2index.containsKey(element), | |
| 169 message: "Unknown variable: $element.")); | |
|
floitsch
2014/10/16 12:23:59
I would indent message to the invariant-args. But
Johnni Winther
2014/10/16 13:01:26
Done.
| |
| 168 return index2value[variable2index[element]]; | 170 return index2value[variable2index[element]]; |
| 169 } | 171 } |
| 170 | 172 |
| 171 void update(Element element, ir.Primitive value) { | 173 void update(Element element, ir.Primitive value) { |
| 172 index2value[variable2index[element]] = value; | 174 index2value[variable2index[element]] = value; |
| 173 } | 175 } |
| 174 | 176 |
| 175 /// Verify that the variable2index and index2variable maps agree up to the | 177 /// Verify that the variable2index and index2variable maps agree up to the |
| 176 /// index [length] exclusive. | 178 /// index [length] exclusive. |
| 177 bool sameDomain(int length, Environment other) { | 179 bool sameDomain(int length, Environment other) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | 232 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. |
| 231 ConstantSystem constantSystem = DART_CONSTANT_SYSTEM; | 233 ConstantSystem constantSystem = DART_CONSTANT_SYSTEM; |
| 232 | 234 |
| 233 ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 235 ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 234 | 236 |
| 235 List<ir.Parameter> _parameters = <ir.Parameter>[]; | 237 List<ir.Parameter> _parameters = <ir.Parameter>[]; |
| 236 | 238 |
| 237 /// A map from variable indexes to their values. | 239 /// A map from variable indexes to their values. |
| 238 Environment environment = new Environment.empty(); | 240 Environment environment = new Environment.empty(); |
| 239 | 241 |
| 242 List<ConstDeclaration> _localConstants = <ConstDeclaration>[]; | |
| 243 | |
| 240 // The IR builder maintains a context, which is an expression with a hole in | 244 // The IR builder maintains a context, which is an expression with a hole in |
| 241 // it. The hole represents the focus where new expressions can be added. | 245 // it. The hole represents the focus where new expressions can be added. |
| 242 // The context is implemented by 'root' which is the root of the expression | 246 // The context is implemented by 'root' which is the root of the expression |
| 243 // and 'current' which is the expression that immediately contains the hole. | 247 // and 'current' which is the expression that immediately contains the hole. |
| 244 // Not all expressions have a hole (e.g., invocations, which always occur in | 248 // Not all expressions have a hole (e.g., invocations, which always occur in |
| 245 // tail position, do not have a hole). Expressions with a hole have a plug | 249 // tail position, do not have a hole). Expressions with a hole have a plug |
| 246 // method. | 250 // method. |
| 247 // | 251 // |
| 248 // Conceptually, visiting a statement takes a context as input and returns | 252 // Conceptually, visiting a statement takes a context as input and returns |
| 249 // either a new context or else an expression without a hole if all | 253 // either a new context or else an expression without a hole if all |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 273 {bool isClosureVariable: false}) { | 277 {bool isClosureVariable: false}) { |
| 274 ir.Parameter parameter = new ir.Parameter(parameterElement); | 278 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 275 _parameters.add(parameter); | 279 _parameters.add(parameter); |
| 276 if (isClosureVariable) { | 280 if (isClosureVariable) { |
| 277 add(new ir.SetClosureVariable(parameterElement, parameter)); | 281 add(new ir.SetClosureVariable(parameterElement, parameter)); |
| 278 } else { | 282 } else { |
| 279 environment.extend(parameterElement, parameter); | 283 environment.extend(parameterElement, parameter); |
| 280 } | 284 } |
| 281 } | 285 } |
| 282 | 286 |
| 287 void declareLocalConstant(LocalVariableElement variableElement, | |
| 288 ConstantExpression value) { | |
| 289 _localConstants.add(new ConstDeclaration(variableElement, value)); | |
| 290 } | |
| 291 | |
| 292 void declareLocalVariable(LocalVariableElement variableElement, | |
| 293 {ir.Primitive initialValue, | |
| 294 bool isClosureVariable: false}) { | |
| 295 assert(isOpen); | |
| 296 if (initialValue == null) { | |
| 297 // TODO(kmillikin): Consider pooling constants. | |
| 298 // The initial value is null. | |
| 299 initialValue = makePrimConst(constantSystem.createNull()); | |
| 300 add(new ir.LetPrim(initialValue)); | |
| 301 } | |
| 302 if (isClosureVariable) { | |
| 303 add(new ir.SetClosureVariable(variableElement, | |
| 304 initialValue, | |
| 305 isDeclaration: true)); | |
| 306 } else { | |
| 307 // In case a primitive was introduced for the initializer expression, | |
| 308 // use this variable element to help derive a good name for it. | |
| 309 initialValue.useElementAsHint(variableElement); | |
| 310 environment.extend(variableElement, initialValue); | |
| 311 } | |
| 312 } | |
| 313 | |
| 283 // Plug an expression into the 'hole' in the context being accumulated. The | 314 // Plug an expression into the 'hole' in the context being accumulated. The |
| 284 // empty context (just a hole) is represented by root (and current) being | 315 // empty context (just a hole) is represented by root (and current) being |
| 285 // null. Since the hole in the current context is filled by this function, | 316 // null. Since the hole in the current context is filled by this function, |
| 286 // the new hole must be in the newly added expression---which becomes the | 317 // the new hole must be in the newly added expression---which becomes the |
| 287 // new value of current. | 318 // new value of current. |
| 288 void add(ir.Expression expr) { | 319 void add(ir.Expression expr) { |
| 289 assert(isOpen); | 320 assert(isOpen); |
| 290 if (_root == null) { | 321 if (_root == null) { |
| 291 _root = _current = expr; | 322 _root = _current = expr; |
| 292 } else { | 323 } else { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 add(new ir.InvokeContinuation(returnContinuation, [constant])); | 402 add(new ir.InvokeContinuation(returnContinuation, [constant])); |
| 372 _current = null; | 403 _current = null; |
| 373 } | 404 } |
| 374 | 405 |
| 375 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. | 406 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. |
| 376 /// | 407 /// |
| 377 /// Parameters must be created before the construction of the body using | 408 /// Parameters must be created before the construction of the body using |
| 378 /// [createParameter]. | 409 /// [createParameter]. |
| 379 ir.FunctionDefinition buildFunctionDefinition( | 410 ir.FunctionDefinition buildFunctionDefinition( |
| 380 FunctionElement element, | 411 FunctionElement element, |
| 381 List<ConstDeclaration> constants, | |
| 382 List<ConstantExpression> defaults) { | 412 List<ConstantExpression> defaults) { |
| 383 if (!element.isAbstract) { | 413 if (!element.isAbstract) { |
| 384 ensureReturn(); | 414 ensureReturn(); |
| 385 return new ir.FunctionDefinition( | 415 return new ir.FunctionDefinition( |
| 386 element, returnContinuation, _parameters, _root, constants, defaults); | 416 element, returnContinuation, _parameters, _root, |
| 417 _localConstants, defaults); | |
| 387 } else { | 418 } else { |
| 388 assert(invariant(element, _root == null, | 419 assert(invariant(element, _root == null, |
| 389 message: "Non-empty body for abstract method $element: $_root")); | 420 message: "Non-empty body for abstract method $element: $_root")); |
| 390 assert(invariant(element, constants.isEmpty, | 421 assert(invariant(element, _localConstants.isEmpty, |
| 391 message: "Local constants for abstract method $element: $constants")); | 422 message: "Local constants for abstract method $element: " |
| 423 "$_localConstants")); | |
| 392 return new ir.FunctionDefinition.abstract( | 424 return new ir.FunctionDefinition.abstract( |
| 393 element, _parameters, defaults); | 425 element, _parameters, defaults); |
| 394 } | 426 } |
| 395 } | 427 } |
| 396 | 428 |
| 397 /// Create a static invocation of [element] with arguments structure defined | 429 /// Create a static invocation of [element] with arguments structure defined |
| 398 /// by [selector] and argument values defined by [arguments]. | 430 /// by [selector] and argument values defined by [arguments]. |
| 399 ir.Primitive buildStaticInvocation(Element element, | 431 ir.Primitive buildStaticInvocation(Element element, |
| 400 Selector selector, | 432 Selector selector, |
| 401 List<ir.Definition> arguments) { | 433 List<ir.Definition> arguments) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 // assigned in the delimited subexpression to their reaching definition --- | 478 // assigned in the delimited subexpression to their reaching definition --- |
| 447 // that is, the definition in effect at the hole in 'current'. These are | 479 // that is, the definition in effect at the hole in 'current'. These are |
| 448 // used to determine if a join-point continuation needs to be passed | 480 // used to determine if a join-point continuation needs to be passed |
| 449 // arguments, and what the arguments are. | 481 // arguments, and what the arguments are. |
| 450 | 482 |
| 451 /// A stack of collectors for breaks. | 483 /// A stack of collectors for breaks. |
| 452 final List<JumpCollector> breakCollectors; | 484 final List<JumpCollector> breakCollectors; |
| 453 /// A stack of collectors for continues. | 485 /// A stack of collectors for continues. |
| 454 final List<JumpCollector> continueCollectors; | 486 final List<JumpCollector> continueCollectors; |
| 455 | 487 |
| 456 final List<ConstDeclaration> localConstants; | |
| 457 | |
| 458 FunctionElement currentFunction; | 488 FunctionElement currentFunction; |
| 459 final DetectClosureVariables closureLocals; | 489 final DetectClosureVariables closureLocals; |
| 460 | 490 |
| 461 /// Construct a top-level visitor. | 491 /// Construct a top-level visitor. |
| 462 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) | 492 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) |
| 463 : breakCollectors = <JumpCollector>[], | 493 : breakCollectors = <JumpCollector>[], |
| 464 continueCollectors = <JumpCollector>[], | 494 continueCollectors = <JumpCollector>[], |
| 465 localConstants = <ConstDeclaration>[], | |
| 466 closureLocals = new DetectClosureVariables(elements), | 495 closureLocals = new DetectClosureVariables(elements), |
| 467 super(elements) { | 496 super(elements) { |
| 468 constantSystem = compiler.backend.constantSystem; | 497 constantSystem = compiler.backend.constantSystem; |
| 469 } | 498 } |
| 470 | 499 |
| 471 /// Construct a delimited visitor for visiting a subtree. | 500 /// Construct a delimited visitor for visiting a subtree. |
| 472 /// | 501 /// |
| 473 /// The delimited visitor has its own compile-time environment mapping | 502 /// The delimited visitor has its own compile-time environment mapping |
| 474 /// local variables to their values, which is initially a copy of the parent | 503 /// local variables to their values, which is initially a copy of the parent |
| 475 /// environment. It has its own context for building an IR expression, so | 504 /// environment. It has its own context for building an IR expression, so |
| 476 /// the built expression is not plugged into the parent's context. | 505 /// the built expression is not plugged into the parent's context. |
| 477 IrBuilderVisitor.delimited(IrBuilderVisitor parent) | 506 IrBuilderVisitor.delimited(IrBuilderVisitor parent) |
| 478 : compiler = parent.compiler, | 507 : compiler = parent.compiler, |
| 479 sourceFile = parent.sourceFile, | 508 sourceFile = parent.sourceFile, |
| 480 breakCollectors = parent.breakCollectors, | 509 breakCollectors = parent.breakCollectors, |
| 481 continueCollectors = parent.continueCollectors, | 510 continueCollectors = parent.continueCollectors, |
| 482 localConstants = parent.localConstants, | |
| 483 currentFunction = parent.currentFunction, | 511 currentFunction = parent.currentFunction, |
| 484 closureLocals = parent.closureLocals, | 512 closureLocals = parent.closureLocals, |
| 485 super(parent.elements) { | 513 super(parent.elements) { |
| 486 constantSystem = parent.constantSystem; | 514 constantSystem = parent.constantSystem; |
| 487 returnContinuation = parent.returnContinuation; | 515 returnContinuation = parent.returnContinuation; |
| 516 _localConstants = parent._localConstants; | |
| 488 environment = new Environment.from(parent.environment); | 517 environment = new Environment.from(parent.environment); |
| 489 } | 518 } |
| 490 | 519 |
| 491 /// Construct a visitor for a recursive continuation. | 520 /// Construct a visitor for a recursive continuation. |
| 492 /// | 521 /// |
| 493 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) | 522 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) |
| 494 /// for all the local variables in the parent, because the invocation sites | 523 /// for all the local variables in the parent, because the invocation sites |
| 495 /// of the continuation are not all known when the builder is created. The | 524 /// of the continuation are not all known when the builder is created. The |
| 496 /// recursive invocations will be passed values for all the local variables, | 525 /// recursive invocations will be passed values for all the local variables, |
| 497 /// which may be eliminated later if they are redundant---if they take on | 526 /// which may be eliminated later if they are redundant---if they take on |
| 498 /// the same value at all invocation sites. | 527 /// the same value at all invocation sites. |
| 499 IrBuilderVisitor.recursive(IrBuilderVisitor parent) | 528 IrBuilderVisitor.recursive(IrBuilderVisitor parent) |
| 500 : compiler = parent.compiler, | 529 : compiler = parent.compiler, |
| 501 sourceFile = parent.sourceFile, | 530 sourceFile = parent.sourceFile, |
| 502 breakCollectors = parent.breakCollectors, | 531 breakCollectors = parent.breakCollectors, |
| 503 continueCollectors = parent.continueCollectors, | 532 continueCollectors = parent.continueCollectors, |
| 504 localConstants = parent.localConstants, | |
| 505 currentFunction = parent.currentFunction, | 533 currentFunction = parent.currentFunction, |
| 506 closureLocals = parent.closureLocals, | 534 closureLocals = parent.closureLocals, |
| 507 super(parent.elements) { | 535 super(parent.elements) { |
| 508 constantSystem = parent.constantSystem; | 536 constantSystem = parent.constantSystem; |
| 509 returnContinuation = parent.returnContinuation; | 537 returnContinuation = parent.returnContinuation; |
| 538 _localConstants = parent._localConstants; | |
| 510 parent.environment.index2variable.forEach(createParameter); | 539 parent.environment.index2variable.forEach(createParameter); |
| 511 } | 540 } |
| 512 | 541 |
| 513 /** | 542 /** |
| 514 * Builds the [ir.FunctionDefinition] for a function element. In case the | 543 * Builds the [ir.FunctionDefinition] for a function element. In case the |
| 515 * function uses features that cannot be expressed in the IR, this function | 544 * function uses features that cannot be expressed in the IR, this function |
| 516 * returns `null`. | 545 * returns `null`. |
| 517 */ | 546 */ |
| 518 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { | 547 ir.FunctionDefinition buildFunction(FunctionElement functionElement) { |
| 519 return nullIfGiveup(() => buildFunctionInternal(functionElement)); | 548 return nullIfGiveup(() => buildFunctionInternal(functionElement)); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 536 createParameter(parameterElement, | 565 createParameter(parameterElement, |
| 537 isClosureVariable: isClosureVariable(parameterElement)); | 566 isClosureVariable: isClosureVariable(parameterElement)); |
| 538 }); | 567 }); |
| 539 | 568 |
| 540 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 569 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 541 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 570 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 542 defaults.add(getConstantForVariable(element)); | 571 defaults.add(getConstantForVariable(element)); |
| 543 }); | 572 }); |
| 544 | 573 |
| 545 visit(function.body); | 574 visit(function.body); |
| 546 return buildFunctionDefinition(element, localConstants, defaults); | 575 return buildFunctionDefinition(element, defaults); |
| 547 } | 576 } |
| 548 | 577 |
| 549 ir.Primitive visit(ast.Node node) => node.accept(this); | 578 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 550 | 579 |
| 551 // ==== Statements ==== | 580 // ==== Statements ==== |
| 552 // Build(Block(stamements), C) = C' | 581 // Build(Block(stamements), C) = C' |
| 553 // where C' = statements.fold(Build, C) | 582 // where C' = statements.fold(Build, C) |
| 554 ir.Primitive visitBlock(ast.Block node) { | 583 ir.Primitive visitBlock(ast.Block node) { |
| 555 assert(isOpen); | 584 assert(isOpen); |
| 556 for (ast.Node n in node.statements.nodes) { | 585 for (ast.Node n in node.statements.nodes) { |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1134 } | 1163 } |
| 1135 | 1164 |
| 1136 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 1165 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 1137 assert(isOpen); | 1166 assert(isOpen); |
| 1138 if (node.modifiers.isConst) { | 1167 if (node.modifiers.isConst) { |
| 1139 for (ast.SendSet definition in node.definitions.nodes) { | 1168 for (ast.SendSet definition in node.definitions.nodes) { |
| 1140 assert(!definition.arguments.isEmpty); | 1169 assert(!definition.arguments.isEmpty); |
| 1141 assert(definition.arguments.tail.isEmpty); | 1170 assert(definition.arguments.tail.isEmpty); |
| 1142 VariableElement element = elements[definition]; | 1171 VariableElement element = elements[definition]; |
| 1143 ConstantExpression value = getConstantForVariable(element); | 1172 ConstantExpression value = getConstantForVariable(element); |
| 1144 localConstants.add(new ConstDeclaration(element, value)); | 1173 declareLocalConstant(element, value); |
| 1145 } | 1174 } |
| 1146 } else { | 1175 } else { |
| 1147 for (ast.Node definition in node.definitions.nodes) { | 1176 for (ast.Node definition in node.definitions.nodes) { |
| 1148 Element element = elements[definition]; | 1177 Element element = elements[definition]; |
| 1149 ir.Primitive initialValue; | 1178 ir.Primitive initialValue; |
| 1150 // Definitions are either SendSets if there is an initializer, or | 1179 // Definitions are either SendSets if there is an initializer, or |
| 1151 // Identifiers if there is no initializer. | 1180 // Identifiers if there is no initializer. |
| 1152 if (definition is ast.SendSet) { | 1181 if (definition is ast.SendSet) { |
| 1153 assert(!definition.arguments.isEmpty); | 1182 assert(!definition.arguments.isEmpty); |
| 1154 assert(definition.arguments.tail.isEmpty); | 1183 assert(definition.arguments.tail.isEmpty); |
| 1155 initialValue = visit(definition.arguments.head); | 1184 initialValue = visit(definition.arguments.head); |
| 1156 } else { | 1185 } else { |
| 1157 assert(definition is ast.Identifier); | 1186 assert(definition is ast.Identifier); |
| 1158 // The initial value is null. | |
| 1159 // TODO(kmillikin): Consider pooling constants. | |
| 1160 initialValue = makePrimConst(constantSystem.createNull()); | |
| 1161 add(new ir.LetPrim(initialValue)); | |
| 1162 } | 1187 } |
| 1163 if (isClosureVariable(element)) { | 1188 declareLocalVariable(element, |
| 1164 LocalElement local = element; | 1189 initialValue: initialValue, |
| 1165 add(new ir.SetClosureVariable(local, initialValue, | 1190 isClosureVariable: isClosureVariable(element)); |
| 1166 isDeclaration: true)); | |
| 1167 } else { | |
| 1168 // In case a primitive was introduced for the initializer expression, | |
| 1169 // use this variable element to help derive a good name for it. | |
| 1170 initialValue.useElementAsHint(element); | |
| 1171 environment.extend(element, initialValue); | |
| 1172 } | |
| 1173 } | 1191 } |
| 1174 } | 1192 } |
| 1175 return null; | 1193 return null; |
| 1176 } | 1194 } |
| 1177 | 1195 |
| 1178 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1196 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1179 // where (C', x) = Build(e, C) | 1197 // where (C', x) = Build(e, C) |
| 1180 // | 1198 // |
| 1181 // Return without a subexpression is translated as if it were return null. | 1199 // Return without a subexpression is translated as if it were return null. |
| 1182 ir.Primitive visitReturn(ast.Return node) { | 1200 ir.Primitive visitReturn(ast.Return node) { |
| (...skipping 770 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1953 } | 1971 } |
| 1954 | 1972 |
| 1955 visitFunctionExpression(ast.FunctionExpression node) { | 1973 visitFunctionExpression(ast.FunctionExpression node) { |
| 1956 FunctionElement oldFunction = currentFunction; | 1974 FunctionElement oldFunction = currentFunction; |
| 1957 currentFunction = elements[node]; | 1975 currentFunction = elements[node]; |
| 1958 visit(node.body); | 1976 visit(node.body); |
| 1959 currentFunction = oldFunction; | 1977 currentFunction = oldFunction; |
| 1960 } | 1978 } |
| 1961 | 1979 |
| 1962 } | 1980 } |
| OLD | NEW |