| 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 2416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2427 js.Expression objectTest = pop(); | 2427 js.Expression objectTest = pop(); |
| 2428 checkType(input, interceptor, type, negative: negative); | 2428 checkType(input, interceptor, type, negative: negative); |
| 2429 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); | 2429 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); |
| 2430 } else { | 2430 } else { |
| 2431 checkType(input, interceptor, type, negative: negative); | 2431 checkType(input, interceptor, type, negative: negative); |
| 2432 attachLocationToLast(node); | 2432 attachLocationToLast(node); |
| 2433 } | 2433 } |
| 2434 } | 2434 } |
| 2435 } | 2435 } |
| 2436 | 2436 |
| 2437 js.Expression generateTest(HInstruction input, HType checkedType) { | 2437 js.Expression generateTest(HCheck node) { |
| 2438 HInstruction input = node.checkedInput; |
| 2438 TypeMask receiver = input.instructionType.computeMask(compiler); | 2439 TypeMask receiver = input.instructionType.computeMask(compiler); |
| 2439 TypeMask mask = checkedType.computeMask(compiler); | 2440 TypeMask mask = node.instructionType.computeMask(compiler); |
| 2440 // Figure out if it is beneficial to turn this into a null check. | 2441 // Figure out if it is beneficial to turn this into a null check. |
| 2441 // V8 generally prefers 'typeof' checks, but for integers and | 2442 // V8 generally prefers 'typeof' checks, but for integers and |
| 2442 // indexable primitives we cannot compile this test into a single | 2443 // indexable primitives we cannot compile this test into a single |
| 2443 // typeof check so the null check is cheaper. | 2444 // typeof check so the null check is cheaper. |
| 2444 bool turnIntoNumCheck = input.isIntegerOrNull() && checkedType.isInteger(); | 2445 bool turnIntoNumCheck = input.isIntegerOrNull() && node.isInteger(); |
| 2445 bool turnIntoNullCheck = !turnIntoNumCheck | 2446 bool turnIntoNullCheck = !turnIntoNumCheck |
| 2446 && (mask.nullable() == receiver) | 2447 && (mask.nullable() == receiver) |
| 2447 && (checkedType.isInteger() | 2448 && (node.isInteger() || node.isIndexablePrimitive(compiler)); |
| 2448 || checkedType.isIndexablePrimitive(compiler)); | |
| 2449 js.Expression test; | 2449 js.Expression test; |
| 2450 if (turnIntoNullCheck) { | 2450 if (turnIntoNullCheck) { |
| 2451 use(input); | 2451 use(input); |
| 2452 test = new js.Binary("==", pop(), new js.LiteralNull()); | 2452 test = new js.Binary("==", pop(), new js.LiteralNull()); |
| 2453 } else if (checkedType.isInteger() && !turnIntoNumCheck) { | 2453 } else if (node.isInteger() && !turnIntoNumCheck) { |
| 2454 // input is !int | 2454 // input is !int |
| 2455 checkInt(input, '!=='); | 2455 checkInt(input, '!=='); |
| 2456 test = pop(); | 2456 test = pop(); |
| 2457 } else if (checkedType.isNumber() || turnIntoNumCheck) { | 2457 } else if (node.isNumber() || turnIntoNumCheck) { |
| 2458 // input is !num | 2458 // input is !num |
| 2459 checkNum(input, '!=='); | 2459 checkNum(input, '!=='); |
| 2460 test = pop(); | 2460 test = pop(); |
| 2461 } else if (checkedType.isBoolean()) { | 2461 } else if (node.isBoolean()) { |
| 2462 // input is !bool | 2462 // input is !bool |
| 2463 checkBool(input, '!=='); | 2463 checkBool(input, '!=='); |
| 2464 test = pop(); | 2464 test = pop(); |
| 2465 } else if (checkedType.isString(compiler)) { | 2465 } else if (node.isString(compiler)) { |
| 2466 // input is !string | 2466 // input is !string |
| 2467 checkString(input, '!=='); | 2467 checkString(input, '!=='); |
| 2468 test = pop(); | 2468 test = pop(); |
| 2469 } else if (checkedType.isExtendableArray(compiler)) { | 2469 } else if (node.isExtendableArray(compiler)) { |
| 2470 // input is !Object || input is !Array || input.isFixed | 2470 // input is !Object || input is !Array || input.isFixed |
| 2471 checkObject(input, '!=='); | 2471 checkObject(input, '!=='); |
| 2472 js.Expression objectTest = pop(); | 2472 js.Expression objectTest = pop(); |
| 2473 checkArray(input, '!=='); | 2473 checkArray(input, '!=='); |
| 2474 js.Expression arrayTest = pop(); | 2474 js.Expression arrayTest = pop(); |
| 2475 checkFixedArray(input); | 2475 checkFixedArray(input); |
| 2476 test = new js.Binary('||', objectTest, arrayTest); | 2476 test = new js.Binary('||', objectTest, arrayTest); |
| 2477 test = new js.Binary('||', test, pop()); | 2477 test = new js.Binary('||', test, pop()); |
| 2478 } else if (checkedType.isMutableArray(compiler)) { | 2478 } else if (node.isMutableArray(compiler)) { |
| 2479 // input is !Object | 2479 // input is !Object |
| 2480 // || ((input is !Array || input.isImmutable) | 2480 // || ((input is !Array || input.isImmutable) |
| 2481 // && input is !JsIndexingBehavior) | 2481 // && input is !JsIndexingBehavior) |
| 2482 checkObject(input, '!=='); | 2482 checkObject(input, '!=='); |
| 2483 js.Expression objectTest = pop(); | 2483 js.Expression objectTest = pop(); |
| 2484 checkArray(input, '!=='); | 2484 checkArray(input, '!=='); |
| 2485 js.Expression arrayTest = pop(); | 2485 js.Expression arrayTest = pop(); |
| 2486 checkImmutableArray(input); | 2486 checkImmutableArray(input); |
| 2487 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); | 2487 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); |
| 2488 | 2488 |
| 2489 js.Binary notIndexing = checkIndexingBehavior(input, negative: true) | 2489 js.Binary notIndexing = checkIndexingBehavior(input, negative: true) |
| 2490 ? new js.Binary('&&', notArrayOrImmutable, pop()) | 2490 ? new js.Binary('&&', notArrayOrImmutable, pop()) |
| 2491 : notArrayOrImmutable; | 2491 : notArrayOrImmutable; |
| 2492 test = new js.Binary('||', objectTest, notIndexing); | 2492 test = new js.Binary('||', objectTest, notIndexing); |
| 2493 } else if (checkedType.isReadableArray(compiler)) { | 2493 } else if (node.isReadableArray(compiler)) { |
| 2494 // input is !Object | 2494 // input is !Object |
| 2495 // || (input is !Array && input is !JsIndexingBehavior) | 2495 // || (input is !Array && input is !JsIndexingBehavior) |
| 2496 checkObject(input, '!=='); | 2496 checkObject(input, '!=='); |
| 2497 js.Expression objectTest = pop(); | 2497 js.Expression objectTest = pop(); |
| 2498 checkArray(input, '!=='); | 2498 checkArray(input, '!=='); |
| 2499 js.Expression arrayTest = pop(); | 2499 js.Expression arrayTest = pop(); |
| 2500 | 2500 |
| 2501 js.Expression notIndexing = checkIndexingBehavior(input, negative: true) | 2501 js.Expression notIndexing = checkIndexingBehavior(input, negative: true) |
| 2502 ? new js.Binary('&&', arrayTest, pop()) | 2502 ? new js.Binary('&&', arrayTest, pop()) |
| 2503 : arrayTest; | 2503 : arrayTest; |
| 2504 test = new js.Binary('||', objectTest, notIndexing); | 2504 test = new js.Binary('||', objectTest, notIndexing); |
| 2505 } else if (checkedType.isIndexablePrimitive(compiler)) { | 2505 } else if (node.isIndexablePrimitive(compiler)) { |
| 2506 // input is !String | 2506 // input is !String |
| 2507 // && (input is !Object | 2507 // && (input is !Object |
| 2508 // || (input is !Array && input is !JsIndexingBehavior)) | 2508 // || (input is !Array && input is !JsIndexingBehavior)) |
| 2509 checkString(input, '!=='); | 2509 checkString(input, '!=='); |
| 2510 js.Expression stringTest = pop(); | 2510 js.Expression stringTest = pop(); |
| 2511 checkObject(input, '!=='); | 2511 checkObject(input, '!=='); |
| 2512 js.Expression objectTest = pop(); | 2512 js.Expression objectTest = pop(); |
| 2513 checkArray(input, '!=='); | 2513 checkArray(input, '!=='); |
| 2514 js.Expression arrayTest = pop(); | 2514 js.Expression arrayTest = pop(); |
| 2515 | 2515 |
| 2516 js.Binary notIndexingTest = checkIndexingBehavior(input, negative: true) | 2516 js.Binary notIndexingTest = checkIndexingBehavior(input, negative: true) |
| 2517 ? new js.Binary('&&', arrayTest, pop()) | 2517 ? new js.Binary('&&', arrayTest, pop()) |
| 2518 : arrayTest; | 2518 : arrayTest; |
| 2519 js.Binary notObjectOrIndexingTest = | 2519 js.Binary notObjectOrIndexingTest = |
| 2520 new js.Binary('||', objectTest, notIndexingTest); | 2520 new js.Binary('||', objectTest, notIndexingTest); |
| 2521 test = new js.Binary('&&', stringTest, notObjectOrIndexingTest); | 2521 test = new js.Binary('&&', stringTest, notObjectOrIndexingTest); |
| 2522 } else { | 2522 } else { |
| 2523 compiler.internalError('Unexpected check', instruction: input); | 2523 compiler.internalError('Unexpected check', instruction: input); |
| 2524 } | 2524 } |
| 2525 return test; | 2525 return test; |
| 2526 } | 2526 } |
| 2527 | 2527 |
| 2528 void visitTypeConversion(HTypeConversion node) { | 2528 void visitTypeConversion(HTypeConversion node) { |
| 2529 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { | 2529 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
| 2530 // An int check if the input is not int or null, is not | 2530 // An int check if the input is not int or null, is not |
| 2531 // sufficient for doing a argument or receiver check. | 2531 // sufficient for doing a argument or receiver check. |
| 2532 assert(!node.checkedType.isInteger() || | 2532 assert(!node.isInteger() || node.checkedInput.isIntegerOrNull()); |
| 2533 node.checkedInput.isIntegerOrNull()); | 2533 js.Expression test = generateTest(node); |
| 2534 js.Expression test = generateTest(node.checkedInput, node.checkedType); | |
| 2535 js.Block oldContainer = currentContainer; | 2534 js.Block oldContainer = currentContainer; |
| 2536 js.Statement body = new js.Block.empty(); | 2535 js.Statement body = new js.Block.empty(); |
| 2537 currentContainer = body; | 2536 currentContainer = body; |
| 2538 if (node.isArgumentTypeCheck) { | 2537 if (node.isArgumentTypeCheck) { |
| 2539 generateThrowWithHelper('iae', node.checkedInput); | 2538 generateThrowWithHelper('iae', node.checkedInput); |
| 2540 } else if (node.isReceiverTypeCheck) { | 2539 } else if (node.isReceiverTypeCheck) { |
| 2541 use(node.checkedInput); | 2540 use(node.checkedInput); |
| 2542 String methodName = | 2541 String methodName = |
| 2543 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2542 backend.namer.invocationName(node.receiverTypeCheckSelector); |
| 2544 js.Expression call = jsPropertyCall(pop(), methodName, []); | 2543 js.Expression call = jsPropertyCall(pop(), methodName, []); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2591 if (leftType.canBeNull() && rightType.canBeNull()) { | 2590 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2592 if (left.isConstantNull() || right.isConstantNull() || | 2591 if (left.isConstantNull() || right.isConstantNull() || |
| 2593 (leftType.isPrimitive(compiler) && leftType == rightType)) { | 2592 (leftType.isPrimitive(compiler) && leftType == rightType)) { |
| 2594 return '=='; | 2593 return '=='; |
| 2595 } | 2594 } |
| 2596 return null; | 2595 return null; |
| 2597 } else { | 2596 } else { |
| 2598 return '==='; | 2597 return '==='; |
| 2599 } | 2598 } |
| 2600 } | 2599 } |
| OLD | NEW |