| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 | 10 |
| (...skipping 2388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2399 if (negative) { | 2399 if (negative) { |
| 2400 checkNonNull(input); | 2400 checkNonNull(input); |
| 2401 push(new js.Binary('&&', pop(), pop()), node); | 2401 push(new js.Binary('&&', pop(), pop()), node); |
| 2402 } else { | 2402 } else { |
| 2403 checkNull(input); | 2403 checkNull(input); |
| 2404 push(new js.Binary('||', pop(), pop()), node); | 2404 push(new js.Binary('||', pop(), pop()), node); |
| 2405 } | 2405 } |
| 2406 } | 2406 } |
| 2407 } | 2407 } |
| 2408 | 2408 |
| 2409 js.Expression generateTest(HCheck node) { |
| 2410 HInstruction input = node.checkedInput; |
| 2411 DartType indexingBehavior = |
| 2412 backend.jsIndexingBehaviorInterface.computeType(compiler); |
| 2413 js.Expression test; |
| 2414 if (node.isInteger()) { |
| 2415 // input is !int |
| 2416 checkInt(input, '!=='); |
| 2417 test = pop(); |
| 2418 } else if (node.isNumber()) { |
| 2419 // input is !num |
| 2420 checkNum(input, '!=='); |
| 2421 test = pop(); |
| 2422 } else if (node.isBoolean()) { |
| 2423 // input is !bool |
| 2424 checkBool(input, '!=='); |
| 2425 test = pop(); |
| 2426 } else if (node.isString()) { |
| 2427 // input is !string |
| 2428 checkString(input, '!=='); |
| 2429 test = pop(); |
| 2430 } else if (node.isExtendableArray()) { |
| 2431 // input is !Object || input is !Array || input.isFixed |
| 2432 checkObject(input, '!=='); |
| 2433 js.Expression objectTest = pop(); |
| 2434 checkArray(input, '!=='); |
| 2435 js.Expression arrayTest = pop(); |
| 2436 checkFixedArray(input); |
| 2437 test = new js.Binary('||', objectTest, arrayTest); |
| 2438 test = new js.Binary('||', test, pop()); |
| 2439 } else if (node.isMutableArray()) { |
| 2440 // input is !Object |
| 2441 // || ((input is !Array || input.isImmutable) |
| 2442 // && input is !JsIndexingBehavior) |
| 2443 checkObject(input, '!=='); |
| 2444 js.Expression objectTest = pop(); |
| 2445 checkArray(input, '!=='); |
| 2446 js.Expression arrayTest = pop(); |
| 2447 checkImmutableArray(input); |
| 2448 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); |
| 2449 checkType(input, indexingBehavior, negative: true); |
| 2450 js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop()); |
| 2451 test = new js.Binary('||', objectTest, notIndexing); |
| 2452 } else if (node.isReadableArray()) { |
| 2453 // input is !Object |
| 2454 // || (input is !Array && input is !JsIndexingBehavior) |
| 2455 checkObject(input, '!=='); |
| 2456 js.Expression objectTest = pop(); |
| 2457 checkArray(input, '!=='); |
| 2458 js.Expression arrayTest = pop(); |
| 2459 checkType(input, indexingBehavior, negative: true); |
| 2460 js.Expression notIndexing = new js.Binary('&&', arrayTest, pop()); |
| 2461 test = new js.Binary('||', objectTest, notIndexing); |
| 2462 } else if (node.isIndexablePrimitive()) { |
| 2463 // input is !String |
| 2464 // && (input is !Object |
| 2465 // || (input is !Array && input is !JsIndexingBehavior)) |
| 2466 checkString(input, '!=='); |
| 2467 js.Expression stringTest = pop(); |
| 2468 checkObject(input, '!=='); |
| 2469 js.Expression objectTest = pop(); |
| 2470 checkArray(input, '!=='); |
| 2471 js.Expression arrayTest = pop(); |
| 2472 checkType(input, indexingBehavior, negative: true); |
| 2473 js.Binary notIndexingTest = new js.Binary('&&', arrayTest, pop()); |
| 2474 js.Binary notObjectOrIndexingTest = |
| 2475 new js.Binary('||', objectTest, notIndexingTest); |
| 2476 test = new js.Binary('&&', stringTest, notObjectOrIndexingTest); |
| 2477 } else { |
| 2478 compiler.internalError('Unexpected type guard', instruction: input); |
| 2479 } |
| 2480 return test; |
| 2481 } |
| 2482 |
| 2409 void visitTypeConversion(HTypeConversion node) { | 2483 void visitTypeConversion(HTypeConversion node) { |
| 2410 if (node.isChecked) { | 2484 if (node.isChecked) { |
| 2411 if (node.isArgumentTypeCheck) { | 2485 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
| 2412 if (node.isInteger()) { | 2486 js.Expression test = generateTest(node); |
| 2413 checkInt(node.checkedInput, '!=='); | |
| 2414 } else { | |
| 2415 assert(node.isNumber()); | |
| 2416 checkNum(node.checkedInput, '!=='); | |
| 2417 } | |
| 2418 js.Expression test = pop(); | |
| 2419 js.Block oldContainer = currentContainer; | 2487 js.Block oldContainer = currentContainer; |
| 2420 js.Statement body = new js.Block.empty(); | 2488 js.Statement body = new js.Block.empty(); |
| 2421 currentContainer = body; | 2489 currentContainer = body; |
| 2422 generateThrowWithHelper('iae', node.checkedInput); | 2490 if (node.isArgumentTypeCheck) { |
| 2491 generateThrowWithHelper('iae', node.checkedInput); |
| 2492 } else if (node.isReceiverTypeCheck) { |
| 2493 use(node.checkedInput); |
| 2494 String methodName = |
| 2495 backend.namer.invocationName(node.receiverTypeCheckSelector); |
| 2496 js.Expression call = jsPropertyCall(pop(), methodName, []); |
| 2497 pushStatement(new js.Throw(call)); |
| 2498 } |
| 2423 currentContainer = oldContainer; | 2499 currentContainer = oldContainer; |
| 2424 body = unwrapStatement(body); | 2500 body = unwrapStatement(body); |
| 2425 pushStatement(new js.If.noElse(test, body), node); | 2501 pushStatement(new js.If.noElse(test, body), node); |
| 2426 return; | 2502 return; |
| 2427 } | 2503 } |
| 2428 | 2504 |
| 2429 assert(node.isCheckedModeCheck || node.isCastTypeCheck); | 2505 assert(node.isCheckedModeCheck || node.isCastTypeCheck); |
| 2430 DartType type = node.typeExpression; | 2506 DartType type = node.typeExpression; |
| 2431 world.registerIsCheck(type, work.resolutionTree); | 2507 world.registerIsCheck(type, work.resolutionTree); |
| 2432 | 2508 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2481 SsaOptimizedCodeGenerator(backend, work) : super(backend, work); | 2557 SsaOptimizedCodeGenerator(backend, work) : super(backend, work); |
| 2482 | 2558 |
| 2483 HBasicBlock beginGraph(HGraph graph) { | 2559 HBasicBlock beginGraph(HGraph graph) { |
| 2484 return graph.entry; | 2560 return graph.entry; |
| 2485 } | 2561 } |
| 2486 | 2562 |
| 2487 void endGraph(HGraph graph) {} | 2563 void endGraph(HGraph graph) {} |
| 2488 | 2564 |
| 2489 // Called by visitTypeGuard to generate the actual bailout call, something | 2565 // Called by visitTypeGuard to generate the actual bailout call, something |
| 2490 // like "return $.foo$bailout(t0, t1);" | 2566 // like "return $.foo$bailout(t0, t1);" |
| 2491 js.Statement bailout(HTypeGuard guard, String reason) { | 2567 js.Statement bailout(HTypeGuard guard) { |
| 2492 HBailoutTarget target = guard.bailoutTarget; | 2568 HBailoutTarget target = guard.bailoutTarget; |
| 2493 List<js.Expression> arguments = <js.Expression>[]; | 2569 List<js.Expression> arguments = <js.Expression>[]; |
| 2494 arguments.add(new js.LiteralNumber("${guard.state}")); | 2570 arguments.add(new js.LiteralNumber("${guard.state}")); |
| 2495 | 2571 |
| 2496 for (int i = 0; i < target.inputs.length; i++) { | 2572 for (int i = 0; i < target.inputs.length; i++) { |
| 2497 HInstruction parameter = target.inputs[i]; | 2573 HInstruction parameter = target.inputs[i]; |
| 2498 for (int pad = target.padding[i]; pad != 0; pad--) { | 2574 for (int pad = target.padding[i]; pad != 0; pad--) { |
| 2499 // This argument will not be used by the bailout function, because | 2575 // This argument will not be used by the bailout function, because |
| 2500 // of the control flow (controlled by the state argument passed | 2576 // of the control flow (controlled by the state argument passed |
| 2501 // above). We need to pass it to get later arguments in the right | 2577 // above). We need to pass it to get later arguments in the right |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2522 bailoutTarget = new js.VariableUse(namer.isolateBailoutAccess(method)); | 2598 bailoutTarget = new js.VariableUse(namer.isolateBailoutAccess(method)); |
| 2523 } | 2599 } |
| 2524 js.Call call = new js.Call(bailoutTarget, arguments); | 2600 js.Call call = new js.Call(bailoutTarget, arguments); |
| 2525 attachLocation(call, guard); | 2601 attachLocation(call, guard); |
| 2526 return new js.Return(call); | 2602 return new js.Return(call); |
| 2527 } | 2603 } |
| 2528 | 2604 |
| 2529 // Generate a type guard, something like "if (typeof t0 == 'number')" and the | 2605 // Generate a type guard, something like "if (typeof t0 == 'number')" and the |
| 2530 // corresponding bailout call, something like "return $.foo$bailout(t0, t1);" | 2606 // corresponding bailout call, something like "return $.foo$bailout(t0, t1);" |
| 2531 void visitTypeGuard(HTypeGuard node) { | 2607 void visitTypeGuard(HTypeGuard node) { |
| 2532 HInstruction input = node.guarded; | 2608 js.Expression test = generateTest(node); |
| 2533 DartType indexingBehavior = | 2609 pushStatement(new js.If.noElse(test, bailout(node)), node); |
| 2534 backend.jsIndexingBehaviorInterface.computeType(compiler); | |
| 2535 String message; | |
| 2536 js.Expression test; | |
| 2537 if (node.isInteger()) { | |
| 2538 // if (input is !int) bailout | |
| 2539 checkInt(input, '!=='); | |
| 2540 test = pop(); | |
| 2541 message = 'Not an integer'; | |
| 2542 } else if (node.isNumber()) { | |
| 2543 // if (input is !num) bailout | |
| 2544 checkNum(input, '!=='); | |
| 2545 test = pop(); | |
| 2546 message = 'Not a number'; | |
| 2547 } else if (node.isBoolean()) { | |
| 2548 // if (input is !bool) bailout | |
| 2549 checkBool(input, '!=='); | |
| 2550 test = pop(); | |
| 2551 message = 'Not a boolean'; | |
| 2552 } else if (node.isString()) { | |
| 2553 // if (input is !string) bailout | |
| 2554 checkString(input, '!=='); | |
| 2555 test = pop(); | |
| 2556 message = 'Not a string'; | |
| 2557 } else if (node.isExtendableArray()) { | |
| 2558 // if (input is !Object || input is !Array || input.isFixed) bailout | |
| 2559 checkObject(input, '!=='); | |
| 2560 js.Expression objectTest = pop(); | |
| 2561 checkArray(input, '!=='); | |
| 2562 js.Expression arrayTest = pop(); | |
| 2563 checkFixedArray(input); | |
| 2564 test = new js.Binary('||', objectTest, arrayTest); | |
| 2565 test = new js.Binary('||', test, pop()); | |
| 2566 message = 'Not an extendable array'; | |
| 2567 } else if (node.isMutableArray()) { | |
| 2568 // if (input is !Object | |
| 2569 // || ((input is !Array || input.isImmutable) | |
| 2570 // && input is !JsIndexingBehavior)) bailout | |
| 2571 checkObject(input, '!=='); | |
| 2572 js.Expression objectTest = pop(); | |
| 2573 checkArray(input, '!=='); | |
| 2574 js.Expression arrayTest = pop(); | |
| 2575 checkImmutableArray(input); | |
| 2576 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); | |
| 2577 checkType(input, indexingBehavior, negative: true); | |
| 2578 js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop()); | |
| 2579 test = new js.Binary('||', objectTest, notIndexing); | |
| 2580 message = 'Not a mutable array'; | |
| 2581 } else if (node.isReadableArray()) { | |
| 2582 // if (input is !Object | |
| 2583 // || (input is !Array && input is !JsIndexingBehavior)) bailout | |
| 2584 checkObject(input, '!=='); | |
| 2585 js.Expression objectTest = pop(); | |
| 2586 checkArray(input, '!=='); | |
| 2587 js.Expression arrayTest = pop(); | |
| 2588 checkType(input, indexingBehavior, negative: true); | |
| 2589 js.Expression notIndexing = new js.Binary('&&', arrayTest, pop()); | |
| 2590 test = new js.Binary('||', objectTest, notIndexing); | |
| 2591 message = 'Not an array'; | |
| 2592 } else if (node.isIndexablePrimitive()) { | |
| 2593 // if (input is !String | |
| 2594 // && (input is !Object | |
| 2595 // || (input is !Array && input is !JsIndexingBehavior))) bailout | |
| 2596 checkString(input, '!=='); | |
| 2597 js.Expression stringTest = pop(); | |
| 2598 checkObject(input, '!=='); | |
| 2599 js.Expression objectTest = pop(); | |
| 2600 checkArray(input, '!=='); | |
| 2601 js.Expression arrayTest = pop(); | |
| 2602 checkType(input, indexingBehavior, negative: true); | |
| 2603 js.Binary notIndexingTest = new js.Binary('&&', arrayTest, pop()); | |
| 2604 js.Binary notObjectOrIndexingTest = | |
| 2605 new js.Binary('||', objectTest, notIndexingTest); | |
| 2606 test = new js.Binary('&&', stringTest, notObjectOrIndexingTest); | |
| 2607 message = 'Not a string or array'; | |
| 2608 } else { | |
| 2609 compiler.internalError('Unexpected type guard', instruction: input); | |
| 2610 } | |
| 2611 pushStatement(new js.If.noElse(test, bailout(node, message)), node); | |
| 2612 } | 2610 } |
| 2613 | 2611 |
| 2614 void visitBailoutTarget(HBailoutTarget target) { | 2612 void visitBailoutTarget(HBailoutTarget target) { |
| 2615 // Do nothing. Bailout targets are only used in the non-optimized version. | 2613 // Do nothing. Bailout targets are only used in the non-optimized version. |
| 2616 } | 2614 } |
| 2617 | 2615 |
| 2618 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2616 void preLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| 2619 } | 2617 } |
| 2620 | 2618 |
| 2621 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { | 2619 void startLabeledBlock(HLabeledBlockInformation labeledBlockInfo) { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2992 if (leftType.canBeNull() && rightType.canBeNull()) { | 2990 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2993 if (left.isConstantNull() || right.isConstantNull() || | 2991 if (left.isConstantNull() || right.isConstantNull() || |
| 2994 (leftType.isPrimitive() && leftType == rightType)) { | 2992 (leftType.isPrimitive() && leftType == rightType)) { |
| 2995 return '=='; | 2993 return '=='; |
| 2996 } | 2994 } |
| 2997 return null; | 2995 return null; |
| 2998 } else { | 2996 } else { |
| 2999 return '==='; | 2997 return '==='; |
| 3000 } | 2998 } |
| 3001 } | 2999 } |
| OLD | NEW |