Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 class SsaCodeGeneratorTask extends CompilerTask { | 5 class SsaCodeGeneratorTask extends CompilerTask { |
| 6 final JavaScriptBackend backend; | 6 final JavaScriptBackend backend; |
| 7 SsaCodeGeneratorTask(JavaScriptBackend backend) | 7 SsaCodeGeneratorTask(JavaScriptBackend backend) |
| 8 : this.backend = backend, | 8 : this.backend = backend, |
| 9 super(backend.compiler); | 9 super(backend.compiler); |
| 10 String get name() => 'SSA code generator'; | 10 String get name() => 'SSA code generator'; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 * or possibly several comma-separated expressions. | 134 * or possibly several comma-separated expressions. |
| 135 * - [TYPE_DECLARATION] means that the graph can be generated as an | 135 * - [TYPE_DECLARATION] means that the graph can be generated as an |
| 136 * expression, and that it only generates expressions of the form | 136 * expression, and that it only generates expressions of the form |
| 137 * variable = expression | 137 * variable = expression |
| 138 * which are also valid as parts of a "var" declaration. | 138 * which are also valid as parts of a "var" declaration. |
| 139 */ | 139 */ |
| 140 static final int TYPE_STATEMENT = 0; | 140 static final int TYPE_STATEMENT = 0; |
| 141 static final int TYPE_EXPRESSION = 1; | 141 static final int TYPE_EXPRESSION = 1; |
| 142 static final int TYPE_DECLARATION = 2; | 142 static final int TYPE_DECLARATION = 2; |
| 143 | 143 |
| 144 static final String TEMPORARY_PREFIX = 't'; | |
| 145 | |
| 146 final JavaScriptBackend backend; | 144 final JavaScriptBackend backend; |
| 147 final WorkItem work; | 145 final WorkItem work; |
| 148 final StringBuffer buffer; | 146 final StringBuffer buffer; |
| 149 final String parameters; | 147 final String parameters; |
| 150 | 148 |
| 151 final Map<Element, String> parameterNames; | 149 final Set<String> declaredVariables; |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
Can you add a doc-comment describing what this mea
ngeoffray
2012/05/31 08:48:22
Done.
| |
| 152 final Map<int, String> names; | |
| 153 final Set<String> usedNames; | |
| 154 final Set<HInstruction> declaredInstructions; | |
| 155 final Map<String, int> prefixes; | |
| 156 final Set<HInstruction> generateAtUseSite; | 150 final Set<HInstruction> generateAtUseSite; |
| 157 final Map<HPhi, String> logicalOperations; | 151 final Map<HPhi, String> logicalOperations; |
| 158 final Map<Element, ElementAction> breakAction; | 152 final Map<Element, ElementAction> breakAction; |
| 159 final Map<Element, ElementAction> continueAction; | 153 final Map<Element, ElementAction> continueAction; |
| 160 final Equivalence<HPhi> phiEquivalence; | 154 final List<String> delayedVariablesDeclaration; |
| 155 final Map<Element, String> parameterNames; | |
| 156 VariableNames variableNames; | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
And this one too, to explain the difference from t
ngeoffray
2012/05/31 08:48:22
Done.
| |
| 161 | 157 |
| 162 Element equalsNullElement; | 158 Element equalsNullElement; |
| 163 Element boolifiedEqualsNullElement; | 159 Element boolifiedEqualsNullElement; |
| 164 int indent = 0; | 160 int indent = 0; |
| 165 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; | 161 int expectedPrecedence = JSPrecedence.STATEMENT_PRECEDENCE; |
| 166 JSBinaryOperatorPrecedence unsignedShiftPrecedences; | 162 JSBinaryOperatorPrecedence unsignedShiftPrecedences; |
| 167 HGraph currentGraph; | 163 HGraph currentGraph; |
| 168 /** | 164 /** |
| 169 * Whether the code-generation should try to generate an expression | 165 * Whether the code-generation should try to generate an expression |
| 170 * instead of a sequence of statements. | 166 * instead of a sequence of statements. |
| 171 */ | 167 */ |
| 172 int generationState = STATE_STATEMENT; | 168 int generationState = STATE_STATEMENT; |
| 173 /** | 169 /** |
| 174 * While generating expressions, we can't insert variable declarations. | 170 * While generating expressions, we can't insert variable declarations. |
| 175 * Instead we declare them at the end of the function | 171 * Instead we declare them at the end of the function |
|
floitsch
2012/05/30 18:45:03
Move this comment too.
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 176 */ | 172 */ |
| 177 Link<String> delayedVarDecl = const EmptyLink<String>(); | |
| 178 HBasicBlock currentBlock; | 173 HBasicBlock currentBlock; |
| 179 | 174 |
| 180 // Records a block-information that is being handled specially. | 175 // Records a block-information that is being handled specially. |
| 181 // Used to break bad recursion. | 176 // Used to break bad recursion. |
| 182 HBlockInformation currentBlockInformation; | 177 HBlockInformation currentBlockInformation; |
| 183 // The subgraph is used to delimit traversal for some constructions, e.g., | 178 // The subgraph is used to delimit traversal for some constructions, e.g., |
| 184 // if branches. | 179 // if branches. |
| 185 SubGraph subGraph; | 180 SubGraph subGraph; |
| 186 | 181 |
| 187 LibraryElement get currentLibrary() => work.element.getLibrary(); | 182 LibraryElement get currentLibrary() => work.element.getLibrary(); |
| 188 Compiler get compiler() => backend.compiler; | 183 Compiler get compiler() => backend.compiler; |
| 189 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; | 184 NativeEmitter get nativeEmitter() => backend.emitter.nativeEmitter; |
| 190 Enqueuer get world() => backend.compiler.enqueuer.codegen; | 185 Enqueuer get world() => backend.compiler.enqueuer.codegen; |
| 191 | 186 |
| 192 bool isGenerateAtUseSite(HInstruction instruction) { | 187 bool isGenerateAtUseSite(HInstruction instruction) { |
| 193 return generateAtUseSite.contains(instruction); | 188 return generateAtUseSite.contains(instruction); |
| 194 } | 189 } |
| 195 | 190 |
| 196 SsaCodeGenerator(this.backend, | 191 SsaCodeGenerator(this.backend, |
| 197 this.work, | 192 this.work, |
| 198 this.parameters, | 193 this.parameters, |
| 199 this.parameterNames) | 194 this.parameterNames) |
| 200 : names = new Map<int, String>(), | 195 : declaredVariables = new Set<String>(), |
| 201 prefixes = new Map<String, int>(), | 196 delayedVariablesDeclaration = new List<String>(), |
| 202 usedNames = new Set<String>(), | |
| 203 declaredInstructions = new Set<HInstruction>(), | |
| 204 buffer = new StringBuffer(), | 197 buffer = new StringBuffer(), |
| 205 generateAtUseSite = new Set<HInstruction>(), | 198 generateAtUseSite = new Set<HInstruction>(), |
| 206 logicalOperations = new Map<HPhi, String>(), | 199 logicalOperations = new Map<HPhi, String>(), |
| 207 breakAction = new Map<Element, ElementAction>(), | 200 breakAction = new Map<Element, ElementAction>(), |
| 208 continueAction = new Map<Element, ElementAction>(), | 201 continueAction = new Map<Element, ElementAction>(), |
| 209 phiEquivalence = new Equivalence<HPhi>(), | |
| 210 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { | 202 unsignedShiftPrecedences = JSPrecedence.binary['>>>'] { |
| 211 | 203 |
| 212 for (final name in parameterNames.getValues()) { | |
| 213 prefixes[name] = 0; | |
| 214 } | |
| 215 | |
| 216 // Create a namespace for temporaries. | |
| 217 prefixes[TEMPORARY_PREFIX] = 0; | |
| 218 | |
| 219 Interceptors interceptors = backend.builder.interceptors; | 204 Interceptors interceptors = backend.builder.interceptors; |
| 220 equalsNullElement = interceptors.getEqualsNullInterceptor(); | 205 equalsNullElement = interceptors.getEqualsNullInterceptor(); |
| 221 boolifiedEqualsNullElement = | 206 boolifiedEqualsNullElement = |
| 222 interceptors.getBoolifiedVersionOf(equalsNullElement); | 207 interceptors.getBoolifiedVersionOf(equalsNullElement); |
| 223 } | 208 } |
| 224 | 209 |
| 225 abstract visitTypeGuard(HTypeGuard node); | 210 abstract visitTypeGuard(HTypeGuard node); |
| 226 | 211 |
| 227 abstract beginGraph(HGraph graph); | 212 abstract beginGraph(HGraph graph); |
| 228 abstract endGraph(HGraph graph); | 213 abstract endGraph(HGraph graph); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 251 void endExpression(int precedence) { | 236 void endExpression(int precedence) { |
| 252 if (precedence < expectedPrecedence) { | 237 if (precedence < expectedPrecedence) { |
| 253 buffer.add(')'); | 238 buffer.add(')'); |
| 254 } | 239 } |
| 255 } | 240 } |
| 256 | 241 |
| 257 void preGenerateMethod(HGraph graph) { | 242 void preGenerateMethod(HGraph graph) { |
| 258 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); | 243 new SsaInstructionMerger(generateAtUseSite).visitGraph(graph); |
| 259 new SsaConditionMerger(generateAtUseSite, | 244 new SsaConditionMerger(generateAtUseSite, |
| 260 logicalOperations).visitGraph(graph); | 245 logicalOperations).visitGraph(graph); |
| 261 new PhiEquivalator(phiEquivalence, logicalOperations).analyzeGraph(graph); | 246 SsaLiveIntervalBuilder intervalBuilder = |
|
floitsch
2012/05/30 18:45:03
new SsaLiveIntervalBuilder(compiler).visitGraph(gr
ngeoffray
2012/05/31 08:12:46
No, I need the object to take its liveInstructions
Lasse Reichstein Nielsen
2012/05/31 08:24:56
It's also used below.
| |
| 247 new SsaLiveIntervalBuilder(compiler); | |
| 248 intervalBuilder.visitGraph(graph); | |
| 249 SsaVariableAllocator allocator = new SsaVariableAllocator( | |
| 250 compiler, | |
| 251 intervalBuilder.liveInstructions, | |
| 252 intervalBuilder.liveIntervals, | |
| 253 generateAtUseSite); | |
| 254 allocator.visitGraph(graph); | |
| 255 variableNames = allocator.names; | |
| 262 } | 256 } |
| 263 | 257 |
| 264 visitGraph(HGraph graph) { | 258 visitGraph(HGraph graph) { |
| 265 preGenerateMethod(graph); | 259 preGenerateMethod(graph); |
| 266 currentGraph = graph; | 260 currentGraph = graph; |
| 267 indent++; // We are already inside a function. | 261 indent++; // We are already inside a function. |
| 268 subGraph = new SubGraph(graph.entry, graph.exit); | 262 subGraph = new SubGraph(graph.entry, graph.exit); |
| 269 beginGraph(graph); | 263 beginGraph(graph); |
| 270 visitBasicBlock(graph.entry); | 264 visitBasicBlock(graph.entry); |
| 271 if (!delayedVarDecl.isEmpty()) { | 265 if (!delayedVariablesDeclaration.isEmpty()) { |
| 272 addIndented("var "); | 266 addIndented("var "); |
| 273 while (true) { | 267 buffer.add(Strings.join(delayedVariablesDeclaration, ', ')); |
| 274 buffer.add(delayedVarDecl.head); | |
| 275 delayedVarDecl = delayedVarDecl.tail; | |
| 276 if (delayedVarDecl.isEmpty()) break; | |
| 277 buffer.add(", "); | |
| 278 } | |
| 279 buffer.add(";\n"); | 268 buffer.add(";\n"); |
| 280 } | 269 } |
| 281 endGraph(graph); | 270 endGraph(graph); |
| 282 } | 271 } |
| 283 | 272 |
| 284 void visitSubGraph(SubGraph newSubGraph) { | 273 void visitSubGraph(SubGraph newSubGraph) { |
| 285 SubGraph oldSubGraph = subGraph; | 274 SubGraph oldSubGraph = subGraph; |
| 286 subGraph = newSubGraph; | 275 subGraph = newSubGraph; |
| 287 visitBasicBlock(subGraph.start); | 276 visitBasicBlock(subGraph.start); |
| 288 subGraph = oldSubGraph; | 277 subGraph = oldSubGraph; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 int oldState = generationState; | 395 int oldState = generationState; |
| 407 generationState = STATE_FIRST_DECLARATION; | 396 generationState = STATE_FIRST_DECLARATION; |
| 408 visitSubGraph(expressionSubGraph.subExpression); | 397 visitSubGraph(expressionSubGraph.subExpression); |
| 409 generationState = oldState; | 398 generationState = oldState; |
| 410 } | 399 } |
| 411 | 400 |
| 412 void generateCondition(HBlockInformation condition) { | 401 void generateCondition(HBlockInformation condition) { |
| 413 generateExpression(condition); | 402 generateExpression(condition); |
| 414 } | 403 } |
| 415 | 404 |
| 416 String temporary(HInstruction instruction) { | |
| 417 int id = instruction.id; | |
| 418 String name = names[id]; | |
| 419 if (name !== null) return name; | |
| 420 | |
| 421 String prefix = TEMPORARY_PREFIX; | |
| 422 if (instruction.sourceElement !== null) { | |
| 423 Element element = instruction.sourceElement; | |
| 424 if (element !== null && !element.name.isEmpty()) { | |
| 425 prefix = element.name.slowToString(); | |
| 426 // Special case the variable named [TEMPORARY_PREFIX] to allow | |
| 427 // keeping its name. | |
| 428 if (prefix == TEMPORARY_PREFIX && !usedNames.contains(prefix)) { | |
| 429 return newName(id, prefix); | |
| 430 } | |
| 431 // If we've never seen that prefix before, try to use it | |
| 432 // directly. | |
| 433 if (!prefixes.containsKey(prefix)) { | |
| 434 // Make sure the variable name does not conflict with our mangling. | |
| 435 while (usedNames.contains(prefix)) { | |
| 436 prefix = '${prefix}_'; | |
| 437 } | |
| 438 prefixes[prefix] = 0; | |
| 439 return newName(id, prefix); | |
| 440 } | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 name = '${prefix}${prefixes[prefix]++}'; | |
| 445 while (usedNames.contains(name)) { | |
| 446 name = '${prefix}${prefixes[prefix]++}'; | |
| 447 } | |
| 448 return newName(id, name); | |
| 449 } | |
| 450 | |
| 451 // TODO(floitsch): share more code with [temporary]. | |
| 452 String freshTemporary() { | |
| 453 String prefix = TEMPORARY_PREFIX; | |
| 454 String name = '${prefix}${prefixes[prefix]++}'; | |
| 455 while (usedNames.contains(name)) { | |
| 456 name = '${prefix}${prefixes[prefix]++}'; | |
| 457 } | |
| 458 String result = JsNames.getValid(name); | |
| 459 usedNames.add(result); | |
| 460 return result; | |
| 461 } | |
| 462 | |
| 463 String newName(int id, String name) { | |
| 464 String result = JsNames.getValid(name); | |
| 465 names[id] = result; | |
| 466 usedNames.add(result); | |
| 467 return result; | |
| 468 } | |
| 469 | |
| 470 /** | 405 /** |
| 471 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. | 406 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. |
| 472 */ | 407 */ |
| 473 void visitArguments(List<HInstruction> inputs) { | 408 void visitArguments(List<HInstruction> inputs) { |
| 474 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); | 409 assert(inputs.length >= HInvoke.ARGUMENTS_OFFSET); |
| 475 buffer.add('('); | 410 buffer.add('('); |
| 476 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { | 411 for (int i = HInvoke.ARGUMENTS_OFFSET; i < inputs.length; i++) { |
| 477 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); | 412 if (i != HInvoke.ARGUMENTS_OFFSET) buffer.add(', '); |
| 478 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); | 413 use(inputs[i], JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 479 } | 414 } |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 495 return (generationState == STATE_DECLARATION || | 430 return (generationState == STATE_DECLARATION || |
| 496 generationState == STATE_FIRST_DECLARATION); | 431 generationState == STATE_FIRST_DECLARATION); |
| 497 } | 432 } |
| 498 | 433 |
| 499 /** | 434 /** |
| 500 * Called before writing an expression. | 435 * Called before writing an expression. |
| 501 * Ensures that expressions are comma spearated. | 436 * Ensures that expressions are comma spearated. |
| 502 */ | 437 */ |
| 503 void addExpressionSeparator() { | 438 void addExpressionSeparator() { |
| 504 if (generationState == STATE_FIRST_DECLARATION) { | 439 if (generationState == STATE_FIRST_DECLARATION) { |
| 505 buffer.add("var "); | 440 return; |
|
kasperl
2012/05/31 05:26:03
Maybe change the structure so that you check for S
ngeoffray
2012/05/31 08:12:46
Done.
Lasse Reichstein Nielsen
2012/05/31 08:24:56
Why this change?
Where do you change the state to
ngeoffray
2012/05/31 08:48:22
In declareVariable line 454. I need this change be
| |
| 506 generationState = STATE_DECLARATION; | |
| 507 } else if (generationState == STATE_FIRST_EXPRESSION) { | 441 } else if (generationState == STATE_FIRST_EXPRESSION) { |
| 508 generationState = STATE_EXPRESSION; | 442 generationState = STATE_EXPRESSION; |
| 509 } else { | 443 } else { |
| 510 buffer.add(", "); | 444 buffer.add(", "); |
| 511 } | 445 } |
| 512 } | 446 } |
| 513 | 447 |
| 448 bool isVariableDeclared(String variableName) { | |
| 449 return declaredVariables.contains(variableName); | |
| 450 } | |
| 451 | |
| 514 void declareVariable(String variableName) { | 452 void declareVariable(String variableName) { |
| 515 if (isGeneratingExpression()) { | 453 if (isGeneratingExpression()) { |
| 516 buffer.add(variableName); | 454 if (generationState == STATE_FIRST_DECLARATION) { |
| 517 if (!isGeneratingDeclaration()) { | 455 generationState = STATE_DECLARATION; |
| 518 delayedVarDecl = delayedVarDecl.prepend(variableName); | 456 if (!isVariableDeclared(variableName)) { |
| 457 declaredVariables.add(variableName); | |
| 458 buffer.add("var "); | |
|
floitsch
2012/05/30 18:45:03
The 'var' is emitted conditionally. This means tha
ngeoffray
2012/05/31 08:12:46
After the first declaration we must go into STATE_
| |
| 459 } | |
| 460 } else if (!isGeneratingDeclaration() | |
| 461 && !isVariableDeclared(variableName)) { | |
| 462 delayedVariablesDeclaration.add(variableName); | |
| 519 } | 463 } |
| 520 } else { | 464 } else if (!isVariableDeclared(variableName)) { |
| 465 declaredVariables.add(variableName); | |
| 521 buffer.add("var "); | 466 buffer.add("var "); |
| 522 buffer.add(variableName); | |
| 523 } | 467 } |
| 468 buffer.add(variableName); | |
| 524 } | 469 } |
| 525 | 470 |
| 526 void declareInstruction(HInstruction instruction) { | 471 void declareInstruction(HInstruction instruction) { |
| 527 declaredInstructions.add(instruction); | 472 declareVariable(variableNames.getName(instruction)); |
| 528 String name = temporary(instruction); | |
| 529 declareVariable(name); | |
| 530 } | |
| 531 | |
| 532 bool needsNewVariable(HInstruction instruction) { | |
| 533 bool needsVar = !instruction.usedBy.isEmpty(); | |
| 534 if (needsVar && instruction is HCheck) { | |
| 535 HCheck check = instruction; | |
| 536 HInstruction input = check.checkedInput; | |
| 537 // We only need a new var if [input] is generated at use site | |
| 538 // but is not a trivial code motion invariant instruction like | |
| 539 // for parameters or this. | |
| 540 // | |
| 541 // For example: | |
| 542 // Foo a = this; | |
| 543 // print(a); | |
| 544 // print(a); | |
| 545 // | |
| 546 // In checked mode no new variable is needed. | |
| 547 // FooTypeCheck(this); | |
| 548 // print(this); | |
| 549 // print(this); | |
| 550 // | |
| 551 // But for this example: | |
| 552 // Foo a = foo(); | |
| 553 // print(a); | |
| 554 // print(a); | |
| 555 // | |
| 556 // We need a new variable: | |
| 557 // var a = FooTypeCheck(foo()); | |
| 558 // print(a); | |
| 559 // print(a); | |
| 560 needsVar = isGenerateAtUseSite(input) && !input.isCodeMotionInvariant(); | |
| 561 } | |
| 562 return needsVar; | |
| 563 } | 473 } |
| 564 | 474 |
| 565 void define(HInstruction instruction) { | 475 void define(HInstruction instruction) { |
| 566 if (needsNewVariable(instruction)) { | 476 if (instruction is !HCheck && variableNames.hasName(instruction)) { |
| 567 declareInstruction(instruction); | 477 declareInstruction(instruction); |
| 568 buffer.add(" = "); | 478 buffer.add(" = "); |
| 569 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 479 visit(instruction, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 570 } else { | 480 } else { |
| 571 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); | 481 visit(instruction, JSPrecedence.STATEMENT_PRECEDENCE); |
| 572 } | 482 } |
| 573 } | 483 } |
| 574 | 484 |
| 575 void use(HInstruction argument, int expectedPrecedenceForArgument) { | 485 void use(HInstruction argument, int expectedPrecedenceForArgument) { |
| 576 if (argument is HCheck) { | 486 if (isGenerateAtUseSite(argument)) { |
| 577 HCheck instruction = argument; | |
| 578 HInstruction input = instruction.checkedInput; | |
| 579 if (isGenerateAtUseSite(argument) && isGenerateAtUseSite(input)) { | |
| 580 // If both instructions can be generated at use site, we can | |
| 581 // just visit [argument]. | |
| 582 // | |
| 583 // For example: | |
| 584 // Foo a = foo(); | |
| 585 // print(a); | |
| 586 // | |
| 587 // In checked mode will turn into: | |
| 588 // print(FooTypeCheck(foo())); | |
| 589 visit(argument, expectedPrecedenceForArgument); | |
| 590 } else if (isGenerateAtUseSite(input)) { | |
| 591 // Get the real input of that checked instruction. | |
| 592 while (input is HCheck) { | |
| 593 HCheck check = input; | |
| 594 input = check.checkedInput; | |
| 595 } | |
| 596 | |
| 597 // If [argument] cannot be generated at use site, but [input] | |
| 598 // can, use the temporary of [argument]. A code motion | |
| 599 // invariant instruction does not have a temporary, so we just | |
| 600 // | |
| 601 // For example: | |
| 602 // Foo a = foo(); | |
| 603 // print(a); | |
| 604 // print(a); | |
| 605 // | |
| 606 // In checked mode will turn into: | |
| 607 // var a = FooTypeCheck(foo()); | |
| 608 // print(a); | |
| 609 // print(a); | |
| 610 // | |
| 611 // Note that in case the input is code motion invariant, like | |
| 612 // for parameters or this, we just need to visit it, since | |
| 613 // there is no temporary for such instruction. | |
| 614 if (input.isCodeMotionInvariant()) { | |
| 615 visit(input, expectedPrecedenceForArgument); | |
| 616 } else { | |
| 617 buffer.add(temporary(argument)); | |
| 618 } | |
| 619 } else { | |
| 620 // Otherwise we just use [input]. [argument] has already been | |
| 621 // emitted, and we just need the temporary of [input]. | |
| 622 // | |
| 623 // For example: | |
| 624 // var a = foo(); | |
| 625 // print(a); | |
| 626 // Foo b = a; | |
| 627 // print(b); | |
| 628 // | |
| 629 // In checked mode will turn into: | |
| 630 // var a = foo(); | |
| 631 // print(a); | |
| 632 // FooTypeCheck(a); | |
| 633 // print(a); | |
| 634 use(input, expectedPrecedenceForArgument); | |
| 635 } | |
| 636 } else if (isGenerateAtUseSite(argument)) { | |
| 637 visit(argument, expectedPrecedenceForArgument); | 487 visit(argument, expectedPrecedenceForArgument); |
| 488 } else if (argument is HCheck) { | |
| 489 HCheck check = argument; | |
| 490 use(argument.checkedInput, expectedPrecedenceForArgument); | |
| 638 } else { | 491 } else { |
| 639 buffer.add(temporary(argument)); | 492 buffer.add(variableNames.getName(argument)); |
| 640 } | 493 } |
| 641 } | 494 } |
| 642 | 495 |
| 643 visit(HInstruction node, int expectedPrecedenceForNode) { | 496 visit(HInstruction node, int expectedPrecedenceForNode) { |
| 644 int oldPrecedence = this.expectedPrecedence; | 497 int oldPrecedence = this.expectedPrecedence; |
| 645 this.expectedPrecedence = expectedPrecedenceForNode; | 498 this.expectedPrecedence = expectedPrecedenceForNode; |
| 646 node.accept(this); | 499 node.accept(this); |
| 647 this.expectedPrecedence = oldPrecedence; | 500 this.expectedPrecedence = oldPrecedence; |
| 648 } | 501 } |
| 649 | 502 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 717 | 570 |
| 718 bool visitTryInfo(HTryBlockInformation info) { | 571 bool visitTryInfo(HTryBlockInformation info) { |
| 719 addIndented("try {\n"); | 572 addIndented("try {\n"); |
| 720 indent++; | 573 indent++; |
| 721 generateStatements(info.body); | 574 generateStatements(info.body); |
| 722 indent--; | 575 indent--; |
| 723 addIndented("}"); | 576 addIndented("}"); |
| 724 if (info.catchBlock !== null) { | 577 if (info.catchBlock !== null) { |
| 725 // Printing the catch part. | 578 // Printing the catch part. |
| 726 HParameterValue exception = info.catchVariable; | 579 HParameterValue exception = info.catchVariable; |
| 727 String name = temporary(exception); | 580 String name = variableNames.getName(exception); |
| 728 parameterNames[exception.element] = name; | 581 parameterNames[exception.element] = name; |
| 729 buffer.add(' catch ($name) {\n'); | 582 buffer.add(' catch ($name) {\n'); |
| 730 indent++; | 583 indent++; |
| 731 generateStatements(info.catchBlock); | 584 generateStatements(info.catchBlock); |
| 732 parameterNames.remove(exception.element); | 585 parameterNames.remove(exception.element); |
| 733 indent--; | 586 indent--; |
| 734 addIndented('}'); | 587 addIndented('}'); |
| 735 } | 588 } |
| 736 if (info.finallyBlock != null) { | 589 if (info.finallyBlock != null) { |
| 737 buffer.add(" finally {\n"); | 590 buffer.add(" finally {\n"); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1018 return; | 871 return; |
| 1019 } | 872 } |
| 1020 // Flow based traversal. | 873 // Flow based traversal. |
| 1021 if (node.isLoopHeader() && | 874 if (node.isLoopHeader() && |
| 1022 node.loopInformation.loopBlockInformation !== currentBlockInformation) { | 875 node.loopInformation.loopBlockInformation !== currentBlockInformation) { |
| 1023 beginLoop(node); | 876 beginLoop(node); |
| 1024 } | 877 } |
| 1025 iterateBasicBlock(node); | 878 iterateBasicBlock(node); |
| 1026 } | 879 } |
| 1027 | 880 |
| 1028 /** Generates the assignments for all phis of successors blocks. */ | 881 void emitAssignment(String source, String destination) { |
| 1029 void assignPhisOfAllSuccessors(HBasicBlock node) { | 882 if (isGeneratingExpression()) { |
| 1030 Map<HInstruction, String> temporaryNamesOfPhis = null; | 883 addExpressionSeparator(); |
| 884 } else { | |
| 885 addIndentation(); | |
| 886 } | |
| 887 declareVariable(destination); | |
| 888 buffer.add(' = $source'); | |
| 889 if (!isGeneratingExpression()) { | |
| 890 buffer.add(';\n'); | |
| 891 } | |
| 892 } | |
| 1031 | 893 |
| 1032 /** | 894 /** |
| 1033 * Generates the assignment [canonicalPhi] = [value]. | 895 * Sequentialize a list of parallel copies. |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
Describe which criteria are being used to do the o
ngeoffray
2012/05/31 08:48:22
Added the 'conceptually'. As discussed, kept the '
| |
| 1034 * | 896 */ |
| 1035 * If the [canonicalPhi] has a temporary name (in [temporaryNamesOfPhis]) | 897 void sequentializeCopies(List<Copy> copies) { |
| 1036 * then the temporary is assigned instead of the [canonicalPhi]. However, | 898 // Map to keep track of the current location of a variable. |
| 1037 * when the left and right-hand side are equal ([:canonicalPhi === value:]) | 899 Map<String, String> currentLocation = new Map<String, String>(); |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
What is a "location" here?
ngeoffray
2012/05/31 08:48:22
It is a variable. It really is "the variable that
| |
| 1038 * then the [canonicalPhi] is assigned with the temporary. | 900 |
| 1039 */ | 901 // Map to keep track of the initial value of a variable. |
| 1040 void generateAssignment(HPhi canonicalPhi, HInstruction value) { | 902 Map<String, String> initialValue = new Map<String, String>(); |
| 903 | |
| 904 // List of variables to assign a value. | |
| 905 List<String> todo = <String>[]; | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
"todo" -> "worklist".
ngeoffray
2012/05/31 08:48:22
Done.
| |
| 906 | |
| 907 // List of variables that we can assign a value to (ie are not | |
|
Lasse Reichstein Nielsen
2012/05/31 08:24:56
Describe which criteria are being used to do the o
ngeoffray
2012/05/31 08:48:22
Done.
| |
| 908 // being used anymore). | |
| 909 List<String> ready = <String>[]; | |
| 910 | |
| 911 // Prune [copies] by removing self-copies. | |
| 912 List<Copy> prunedCopies = <Copy>[]; | |
| 913 for (Copy copy in copies) { | |
| 914 String sourceName = variableNames.getName(copy.source); | |
| 915 String destinationName = variableNames.getName(copy.destination); | |
| 916 if (sourceName != destinationName) { | |
| 917 prunedCopies.add(new Copy(sourceName, destinationName)); | |
| 918 } | |
| 919 } | |
| 920 copies = prunedCopies; | |
| 921 | |
| 922 | |
| 923 // For each copy, set the current location of the source to | |
| 924 // itself, and the initial value of the destination to the source. | |
| 925 // Add the destination to the list of copies to make. | |
| 926 for (Copy copy in copies) { | |
| 927 currentLocation[copy.source] = copy.source; | |
| 928 initialValue[copy.destination] = copy.source; | |
| 929 todo.add(copy.destination); | |
| 930 } | |
| 931 | |
| 932 // For each copy, if the destination does not have a current | |
| 933 // location, then we can safely assign to it. | |
| 934 for (Copy copy in copies) { | |
| 935 if (currentLocation[copy.destination] === null) { | |
| 936 ready.add(copy.destination); | |
| 937 } | |
| 938 } | |
| 939 | |
| 940 while (!todo.isEmpty()) { | |
| 941 while (!ready.isEmpty()) { | |
| 942 String destination = ready.removeLast(); | |
| 943 String source = initialValue[destination]; | |
| 944 // Since [source] might have been updated, use the current | |
| 945 // location of [source] | |
| 946 String copy = currentLocation[source]; | |
| 947 emitAssignment(copy, destination); | |
|
floitsch
2012/05/30 18:45:03
I find it easier to read if the arguments are inve
ngeoffray
2012/05/31 08:12:46
Done.
| |
| 948 // Now [destination] is the current location of [source]. | |
| 949 currentLocation[source] = destination; | |
| 950 // If [source] hasn't been updated and needs to have a value, | |
| 951 // add it to the list of variables that can be updated. Copies | |
| 952 // of [source] will now use [destination]. | |
| 953 if (source == copy && initialValue[source] !== null) { | |
| 954 ready.add(source); | |
| 955 } | |
| 956 } | |
| 957 | |
| 958 // Check if we have a cycle. | |
| 959 String current = todo.removeLast(); | |
| 960 // If [current] is the source of a copy, and the current | |
| 961 // location of its initial value is not itself, then there is a | |
| 962 // cycle that we break by using a temporary name. | |
| 963 if (currentLocation[current] !== null | |
|
floitsch
2012/05/30 18:45:03
Is this test necessary?
Clearly: current == curre
ngeoffray
2012/05/31 08:12:46
Yes, it is. Because I don't remove a variable that
| |
| 964 && current != currentLocation[initialValue[current]]) { | |
| 965 String tempName = VariableNames.SWAP_TEMP; | |
| 966 emitAssignment(current, tempName); | |
| 967 currentLocation[current] = tempName; | |
| 968 // [current] can now be safely updated. Copies of [current] | |
| 969 // will now use [tempName]. | |
| 970 ready.add(current); | |
| 971 } | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 void assignPhisOfSuccessors(HBasicBlock node) { | |
| 976 CopyHandler handler = variableNames.getCopies(node); | |
| 977 if (handler == null) return; | |
| 978 | |
| 979 sequentializeCopies(handler.copies); | |
| 980 | |
| 981 for (Copy copy in handler.assignments) { | |
| 1041 if (isGeneratingExpression()) { | 982 if (isGeneratingExpression()) { |
| 1042 addExpressionSeparator(); | 983 addExpressionSeparator(); |
| 1043 } else { | 984 } else { |
| 1044 addIndentation(); | 985 addIndentation(); |
| 1045 } | 986 } |
| 1046 if (temporaryNamesOfPhis !== null && | 987 declareVariable(variableNames.getName(copy.destination)); |
| 1047 canonicalPhi !== value && | 988 buffer.add(' = '); |
| 1048 temporaryNamesOfPhis.containsKey(canonicalPhi)) { | 989 use(copy.source, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1049 // This is the assignment to the temporary. | |
| 1050 declareVariable(temporaryNamesOfPhis[canonicalPhi]); | |
| 1051 } else if (!declaredInstructions.contains(canonicalPhi)) { | |
| 1052 declareInstruction(canonicalPhi); | |
| 1053 } else { | |
| 1054 buffer.add(temporary(canonicalPhi)); | |
| 1055 } | |
| 1056 buffer.add(" = "); | |
| 1057 bool isLogicalOperation = logicalOperations.containsKey(canonicalPhi); | |
| 1058 if (isLogicalOperation) { | |
| 1059 emitLogicalOperation(canonicalPhi, logicalOperations[canonicalPhi]); | |
| 1060 } else if (canonicalPhi === value) { | |
| 1061 buffer.add(temporaryNamesOfPhis[value]); | |
| 1062 } else { | |
| 1063 use(value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | |
| 1064 } | |
| 1065 if (!isGeneratingExpression()) { | 990 if (!isGeneratingExpression()) { |
| 1066 buffer.add(';\n'); | 991 buffer.add(';\n'); |
| 1067 } | 992 } |
| 1068 } | 993 } |
| 1069 | |
| 1070 // Assignments are delayed so that we don't overwrite phis that might | |
| 1071 // be used as inputs. | |
| 1072 // TODO(floitsch): improve phi assignments. Currently we introduce | |
| 1073 // way too many temporary variables. | |
| 1074 Map<HPhi, HInstruction> phiAssignments = new Map<HPhi, HInstruction>(); | |
| 1075 | |
| 1076 for (HBasicBlock successor in node.successors) { | |
| 1077 int index = successor.predecessors.indexOf(node); | |
| 1078 successor.forEachPhi((HPhi phi) { | |
| 1079 bool isLogicalOperation = logicalOperations.containsKey(phi); | |
| 1080 // In case the phi is being generated by another | |
| 1081 // instruction. | |
| 1082 if (isLogicalOperation && isGenerateAtUseSite(phi)) return; | |
| 1083 HPhi canonicalPhi = phiEquivalence.getRepresentative(phi); | |
| 1084 assert(!isLogicalOperation || canonicalPhi === phi); | |
| 1085 HInstruction input = phi.inputs[index]; | |
| 1086 if (input is HPhi) { | |
| 1087 input = phiEquivalence.getRepresentative(input); | |
| 1088 // If we use the same variable, we don't need to create an | |
| 1089 // assignment. | |
| 1090 if (input === canonicalPhi) { | |
| 1091 assert(!isLogicalOperation); | |
| 1092 return; | |
| 1093 } | |
| 1094 } | |
| 1095 phiAssignments[canonicalPhi] = input; | |
| 1096 }); | |
| 1097 } | |
| 1098 | |
| 1099 Set<HPhi> inputPhis = new Set<HPhi>(); | |
| 1100 List<HPhi> phis = <HPhi>[]; | |
| 1101 | |
| 1102 /** | |
| 1103 * Transitively collects the phis that are used when emitting the [input] | |
| 1104 * and adds them to [inputPhis]. Does not add phis that are equal to the | |
| 1105 * [targetPhi] or are not in the [phiAssignments] map. | |
| 1106 */ | |
| 1107 void collectInputPhis(HInstruction input, HPhi targetPhi) { | |
| 1108 if (input is HPhi) { | |
| 1109 HPhi canonicalPhi = phiEquivalence.getRepresentative(input); | |
| 1110 // Self-updates are ok. | |
| 1111 if (canonicalPhi !== targetPhi && | |
| 1112 phiAssignments.containsKey(canonicalPhi)) { | |
| 1113 inputPhis.add(canonicalPhi); | |
| 1114 } | |
| 1115 } else if (isGenerateAtUseSite(input)) { | |
| 1116 for (HInstruction inputOfInput in input.inputs) { | |
| 1117 collectInputPhis(inputOfInput, targetPhi); | |
| 1118 } | |
| 1119 } | |
| 1120 } | |
| 1121 | |
| 1122 phiAssignments.forEach((HPhi targetPhi, HInstruction input) { | |
| 1123 phis.add(targetPhi); | |
| 1124 collectInputPhis(input, targetPhi); | |
| 1125 }); | |
| 1126 | |
| 1127 if (inputPhis.isEmpty()) { | |
| 1128 phiAssignments.forEach(generateAssignment); | |
| 1129 } else { | |
| 1130 // Emit the phiX=phiY assignments, taking care to break cycles. | |
| 1131 // Example program: | |
| 1132 // var x = 499; | |
| 1133 // var y = 99; | |
| 1134 // while (x != 99) { | |
| 1135 // var tmp = x; // <=== The tmp variable is removed in Ssa-form. | |
| 1136 // x = y; | |
| 1137 // y = tmp; | |
| 1138 // } | |
| 1139 // | |
| 1140 temporaryNamesOfPhis = new HashMap<HInstruction, String>(); | |
| 1141 // For phis that are used as inputs simply *always* allocate a | |
| 1142 // temporary. | |
| 1143 for (HPhi phi in phis) { | |
| 1144 if (inputPhis.contains(phi)) { | |
| 1145 String temporaryPhi = freshTemporary(); | |
| 1146 temporaryNamesOfPhis[phi] = temporaryPhi; | |
| 1147 } | |
| 1148 // The assignPhi uses temporary variables for the left-hand side if | |
| 1149 // they exist. | |
| 1150 generateAssignment(phi, phiAssignments[phi]); | |
| 1151 } | |
| 1152 // Finally assign the input phis. | |
| 1153 for (HPhi phi in inputPhis) { | |
| 1154 // The assignPhi special-cases phi assignments to itself and recognizes | |
| 1155 // it as assignment from the temporary variable to the actual phi. | |
| 1156 generateAssignment(phi, phi); | |
| 1157 } | |
| 1158 } | |
| 1159 } | 994 } |
| 1160 | 995 |
| 1161 void iterateBasicBlock(HBasicBlock node) { | 996 void iterateBasicBlock(HBasicBlock node) { |
| 1162 HInstruction instruction = node.first; | 997 HInstruction instruction = node.first; |
| 1163 while (instruction != null) { | 998 while (instruction != null) { |
| 1164 if (instruction === node.last) { | 999 if (instruction === node.last) { |
| 1165 assignPhisOfAllSuccessors(node); | 1000 assignPhisOfSuccessors(node); |
| 1166 } | 1001 } |
| 1167 | 1002 |
| 1168 if (isGenerateAtUseSite(instruction)) { | 1003 if (isGenerateAtUseSite(instruction)) { |
| 1169 if (instruction is HIf) { | 1004 if (instruction is HIf) { |
| 1170 HIf hif = instruction; | 1005 HIf hif = instruction; |
| 1171 // The "if" is implementing part of a logical expression. | 1006 // The "if" is implementing part of a logical expression. |
| 1172 // Skip directly forward to to its latest successor, since everything | 1007 // Skip directly forward to to its latest successor, since everything |
| 1173 // in-between must also be generateAtUseSite. | 1008 // in-between must also be generateAtUseSite. |
| 1174 assert(hif.trueBranch.id < hif.falseBranch.id); | 1009 assert(hif.trueBranch.id < hif.falseBranch.id); |
| 1175 visitBasicBlock(hif.falseBranch); | 1010 visitBasicBlock(hif.falseBranch); |
| (...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1584 visitFieldSet(HFieldSet node) { | 1419 visitFieldSet(HFieldSet node) { |
| 1585 String name; | 1420 String name; |
| 1586 if (!node.isFromActivation()) { | 1421 if (!node.isFromActivation()) { |
| 1587 name = | 1422 name = |
| 1588 compiler.namer.instanceFieldName(currentLibrary, node.name); | 1423 compiler.namer.instanceFieldName(currentLibrary, node.name); |
| 1589 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1424 beginExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1590 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); | 1425 use(node.receiver, JSPrecedence.MEMBER_PRECEDENCE); |
| 1591 buffer.add('.'); | 1426 buffer.add('.'); |
| 1592 buffer.add(name); | 1427 buffer.add(name); |
| 1593 } else { | 1428 } else { |
| 1594 // TODO(ngeoffray): Remove the 'var' once we don't globally box | |
| 1595 // variables used in a try/catch. | |
| 1596 if (!isGeneratingExpression()) { | |
| 1597 buffer.add('var '); | |
| 1598 } | |
| 1599 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); | 1429 use(node.receiver, JSPrecedence.EXPRESSION_PRECEDENCE); |
| 1600 } | 1430 } |
| 1601 buffer.add(' = '); | 1431 buffer.add(' = '); |
| 1602 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1432 use(node.value, JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1603 if (node.receiver !== null) { | 1433 if (node.receiver !== null) { |
| 1604 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); | 1434 endExpression(JSPrecedence.ASSIGNMENT_PRECEDENCE); |
| 1605 } | 1435 } |
| 1606 } | 1436 } |
| 1607 | 1437 |
| 1608 visitForeign(HForeign node) { | 1438 visitForeign(HForeign node) { |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1737 } else { | 1567 } else { |
| 1738 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); | 1568 beginExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 1739 buffer.add('!'); | 1569 buffer.add('!'); |
| 1740 use(input, JSPrecedence.PREFIX_PRECEDENCE); | 1570 use(input, JSPrecedence.PREFIX_PRECEDENCE); |
| 1741 endExpression(JSPrecedence.PREFIX_PRECEDENCE); | 1571 endExpression(JSPrecedence.PREFIX_PRECEDENCE); |
| 1742 } | 1572 } |
| 1743 } | 1573 } |
| 1744 | 1574 |
| 1745 visitParameterValue(HParameterValue node) { | 1575 visitParameterValue(HParameterValue node) { |
| 1746 assert(isGenerateAtUseSite(node)); | 1576 assert(isGenerateAtUseSite(node)); |
| 1747 if (parameterNames[node.element] == null) { | 1577 buffer.add(variableNames.getName(node)); |
| 1748 buffer.add(temporary(node)); | |
| 1749 } else { | |
| 1750 buffer.add(parameterNames[node.element]); | |
| 1751 } | |
| 1752 } | 1578 } |
| 1753 | 1579 |
| 1754 visitPhi(HPhi node) { | 1580 visitPhi(HPhi node) { |
| 1755 String operation = logicalOperations[node]; | 1581 String operation = logicalOperations[node]; |
| 1756 if (operation !== null) { | 1582 if (operation !== null) { |
| 1757 emitLogicalOperation(node, operation); | 1583 emitLogicalOperation(node, operation); |
| 1758 } else { | 1584 } else { |
| 1759 HPhi canonicalPhi = phiEquivalence.getRepresentative(node); | 1585 buffer.add('${variableNames.getName(node)}'); |
| 1760 buffer.add('${temporary(canonicalPhi)}'); | |
| 1761 } | 1586 } |
| 1762 } | 1587 } |
| 1763 | 1588 |
| 1764 visitReturn(HReturn node) { | 1589 visitReturn(HReturn node) { |
| 1765 addIndentation(); | 1590 addIndentation(); |
| 1766 assert(node.inputs.length == 1); | 1591 assert(node.inputs.length == 1); |
| 1767 HInstruction input = node.inputs[0]; | 1592 HInstruction input = node.inputs[0]; |
| 1768 if (input.isConstantNull()) { | 1593 if (input.isConstantNull()) { |
| 1769 buffer.add('return;\n'); | 1594 buffer.add('return;\n'); |
| 1770 } else { | 1595 } else { |
| (...skipping 702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2473 void visitTypeGuard(HTypeGuard node) { | 2298 void visitTypeGuard(HTypeGuard node) { |
| 2474 indent--; | 2299 indent--; |
| 2475 addIndented('case ${node.state}:\n'); | 2300 addIndented('case ${node.state}:\n'); |
| 2476 indent++; | 2301 indent++; |
| 2477 addIndented('state = 0;\n'); | 2302 addIndented('state = 0;\n'); |
| 2478 | 2303 |
| 2479 setup.add(' case ${node.state}:\n'); | 2304 setup.add(' case ${node.state}:\n'); |
| 2480 int i = 0; | 2305 int i = 0; |
| 2481 for (HInstruction input in node.inputs) { | 2306 for (HInstruction input in node.inputs) { |
| 2482 HInstruction instruction = unwrap(input); | 2307 HInstruction instruction = unwrap(input); |
| 2483 setup.add(' ${temporary(instruction)} = env$i;\n'); | 2308 setup.add(' ${variableNames.getName(instruction)} = env$i;\n'); |
| 2484 i++; | 2309 i++; |
| 2485 } | 2310 } |
| 2486 if (i > maxBailoutParameters) maxBailoutParameters = i; | 2311 if (i > maxBailoutParameters) maxBailoutParameters = i; |
| 2487 setup.add(' break;\n'); | 2312 setup.add(' break;\n'); |
| 2488 } | 2313 } |
| 2489 | 2314 |
| 2490 void startBailoutCase(List<HTypeGuard> bailouts1, | 2315 void startBailoutCase(List<HTypeGuard> bailouts1, |
| 2491 List<HTypeGuard> bailouts2) { | 2316 List<HTypeGuard> bailouts2) { |
| 2492 indent--; | 2317 indent--; |
| 2493 handleBailoutCase(bailouts1); | 2318 handleBailoutCase(bailouts1); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2632 startBailoutSwitch(); | 2457 startBailoutSwitch(); |
| 2633 } | 2458 } |
| 2634 } | 2459 } |
| 2635 | 2460 |
| 2636 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2461 void endLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2637 if (labeledBlockInfo.body.start.hasGuards()) { | 2462 if (labeledBlockInfo.body.start.hasGuards()) { |
| 2638 endBailoutSwitch(); | 2463 endBailoutSwitch(); |
| 2639 } | 2464 } |
| 2640 } | 2465 } |
| 2641 } | 2466 } |
| OLD | NEW |