| 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 2234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2245 void checkNull(HInstruction input) { | 2245 void checkNull(HInstruction input) { |
| 2246 use(input); | 2246 use(input); |
| 2247 push(new js.Binary('==', pop(), new js.LiteralNull())); | 2247 push(new js.Binary('==', pop(), new js.LiteralNull())); |
| 2248 } | 2248 } |
| 2249 | 2249 |
| 2250 void checkNonNull(HInstruction input) { | 2250 void checkNonNull(HInstruction input) { |
| 2251 use(input); | 2251 use(input); |
| 2252 push(new js.Binary('!=', pop(), new js.LiteralNull())); | 2252 push(new js.Binary('!=', pop(), new js.LiteralNull())); |
| 2253 } | 2253 } |
| 2254 | 2254 |
| 2255 bool checkIndexingBehavior(HInstruction input, {bool negative: false}) { | |
| 2256 if (!compiler.resolverWorld.isInstantiated( | |
| 2257 backend.jsIndexingBehaviorInterface)) { | |
| 2258 return false; | |
| 2259 } | |
| 2260 | |
| 2261 use(input); | |
| 2262 js.Expression object1 = pop(); | |
| 2263 use(input); | |
| 2264 js.Expression object2 = pop(); | |
| 2265 push(backend.generateIsJsIndexableCall(object1, object2)); | |
| 2266 if (negative) push(new js.Prefix('!', pop())); | |
| 2267 return true; | |
| 2268 } | |
| 2269 | |
| 2270 void checkType(HInstruction input, HInstruction interceptor, | 2255 void checkType(HInstruction input, HInstruction interceptor, |
| 2271 DartType type, {bool negative: false}) { | 2256 DartType type, {bool negative: false}) { |
| 2272 Element element = type.element; | 2257 Element element = type.element; |
| 2273 if (element == backend.jsArrayClass) { | 2258 if (element == backend.jsArrayClass) { |
| 2274 checkArray(input, negative ? '!==': '==='); | 2259 checkArray(input, negative ? '!==': '==='); |
| 2275 return; | 2260 return; |
| 2276 } else if (element == backend.jsMutableArrayClass) { | 2261 } else if (element == backend.jsMutableArrayClass) { |
| 2277 if (negative) { | 2262 if (negative) { |
| 2278 checkImmutableArray(input); | 2263 checkImmutableArray(input); |
| 2279 } else { | 2264 } else { |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2460 attachLocationToLast(node); | 2445 attachLocationToLast(node); |
| 2461 } | 2446 } |
| 2462 } | 2447 } |
| 2463 } | 2448 } |
| 2464 | 2449 |
| 2465 void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) { | 2450 void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) { |
| 2466 checkTypeViaProperty(node.interceptor, node.typeExpression, negative); | 2451 checkTypeViaProperty(node.interceptor, node.typeExpression, negative); |
| 2467 attachLocationToLast(node); | 2452 attachLocationToLast(node); |
| 2468 } | 2453 } |
| 2469 | 2454 |
| 2470 js.Expression generateTest(HInstruction input, TypeMask checkedType) { | 2455 js.Expression generateReceiverOrArgumentTypeTest( |
| 2456 HInstruction input, TypeMask checkedType) { |
| 2471 ClassWorld classWorld = compiler.world; | 2457 ClassWorld classWorld = compiler.world; |
| 2472 TypeMask receiver = input.instructionType; | 2458 TypeMask inputType = input.instructionType; |
| 2473 // Figure out if it is beneficial to turn this into a null check. | 2459 // Figure out if it is beneficial to turn this into a null check. |
| 2474 // V8 generally prefers 'typeof' checks, but for integers and | 2460 // V8 generally prefers 'typeof' checks, but for integers and |
| 2475 // indexable primitives we cannot compile this test into a single | 2461 // indexable primitives we cannot compile this test into a single |
| 2476 // typeof check so the null check is cheaper. | 2462 // typeof check so the null check is cheaper. |
| 2477 bool turnIntoNumCheck = input.isIntegerOrNull(compiler) | 2463 bool isIntCheck = checkedType.containsOnlyInt(classWorld); |
| 2478 && checkedType.containsOnlyInt(classWorld); | 2464 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); |
| 2479 bool turnIntoNullCheck = !turnIntoNumCheck | 2465 bool turnIntoNullCheck = !turnIntoNumCheck |
| 2480 && (checkedType.nullable() == receiver) | 2466 && (checkedType.nullable() == inputType) |
| 2481 && (checkedType.containsOnlyInt(classWorld) | 2467 && (isIntCheck |
| 2482 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); | 2468 || checkedType.satisfies(backend.jsIndexableClass, classWorld)); |
| 2483 js.Expression test; | 2469 |
| 2484 if (turnIntoNullCheck) { | 2470 if (turnIntoNullCheck) { |
| 2485 use(input); | 2471 use(input); |
| 2486 test = new js.Binary("==", pop(), new js.LiteralNull()); | 2472 return new js.Binary("==", pop(), new js.LiteralNull()); |
| 2487 } else if (checkedType.containsOnlyInt(classWorld) && !turnIntoNumCheck) { | 2473 } else if (isIntCheck && !turnIntoNumCheck) { |
| 2488 // input is !int | 2474 // input is !int |
| 2489 checkInt(input, '!=='); | 2475 checkBigInt(input, '!=='); |
| 2490 test = pop(); | 2476 return pop(); |
| 2491 } else if (checkedType.containsOnlyNum(classWorld) || turnIntoNumCheck) { | 2477 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { |
| 2492 // input is !num | 2478 // input is !num |
| 2493 checkNum(input, '!=='); | 2479 checkNum(input, '!=='); |
| 2494 test = pop(); | 2480 return pop(); |
| 2495 } else if (checkedType.containsOnlyBool(classWorld)) { | 2481 } else if (checkedType.containsOnlyBool(classWorld)) { |
| 2496 // input is !bool | 2482 // input is !bool |
| 2497 checkBool(input, '!=='); | 2483 checkBool(input, '!=='); |
| 2498 test = pop(); | 2484 return pop(); |
| 2499 } else if (checkedType.containsOnlyString(classWorld)) { | 2485 } else if (checkedType.containsOnlyString(classWorld)) { |
| 2500 // input is !string | 2486 // input is !string |
| 2501 checkString(input, '!=='); | 2487 checkString(input, '!=='); |
| 2502 test = pop(); | 2488 return pop(); |
| 2503 } else if (checkedType.satisfies(backend.jsExtendableArrayClass, | |
| 2504 classWorld)) { | |
| 2505 // input is !Object || input is !Array || input.isFixed | |
| 2506 checkObject(input, '!=='); | |
| 2507 js.Expression objectTest = pop(); | |
| 2508 checkArray(input, '!=='); | |
| 2509 js.Expression arrayTest = pop(); | |
| 2510 checkFixedArray(input); | |
| 2511 test = new js.Binary('||', objectTest, arrayTest); | |
| 2512 test = new js.Binary('||', test, pop()); | |
| 2513 } else if (checkedType.satisfies(backend.jsMutableArrayClass, classWorld)) { | |
| 2514 // input is !Object | |
| 2515 // || ((input is !Array || input.isImmutable) | |
| 2516 // && input is !JsIndexingBehavior) | |
| 2517 checkObject(input, '!=='); | |
| 2518 js.Expression objectTest = pop(); | |
| 2519 checkArray(input, '!=='); | |
| 2520 js.Expression arrayTest = pop(); | |
| 2521 checkImmutableArray(input); | |
| 2522 js.Binary notArrayOrImmutable = new js.Binary('||', arrayTest, pop()); | |
| 2523 | |
| 2524 js.Binary notIndexing = checkIndexingBehavior(input, negative: true) | |
| 2525 ? new js.Binary('&&', notArrayOrImmutable, pop()) | |
| 2526 : notArrayOrImmutable; | |
| 2527 test = new js.Binary('||', objectTest, notIndexing); | |
| 2528 } else if (checkedType.satisfies(backend.jsArrayClass, classWorld)) { | |
| 2529 // input is !Object | |
| 2530 // || (input is !Array && input is !JsIndexingBehavior) | |
| 2531 checkObject(input, '!=='); | |
| 2532 js.Expression objectTest = pop(); | |
| 2533 checkArray(input, '!=='); | |
| 2534 js.Expression arrayTest = pop(); | |
| 2535 | |
| 2536 js.Expression notIndexing = checkIndexingBehavior(input, negative: true) | |
| 2537 ? new js.Binary('&&', arrayTest, pop()) | |
| 2538 : arrayTest; | |
| 2539 test = new js.Binary('||', objectTest, notIndexing); | |
| 2540 } else if (checkedType.satisfies(backend.jsIndexableClass, classWorld)) { | |
| 2541 // input is !String | |
| 2542 // && (input is !Object | |
| 2543 // || (input is !Array && input is !JsIndexingBehavior)) | |
| 2544 checkString(input, '!=='); | |
| 2545 js.Expression stringTest = pop(); | |
| 2546 checkObject(input, '!=='); | |
| 2547 js.Expression objectTest = pop(); | |
| 2548 checkArray(input, '!=='); | |
| 2549 js.Expression arrayTest = pop(); | |
| 2550 | |
| 2551 js.Binary notIndexingTest = checkIndexingBehavior(input, negative: true) | |
| 2552 ? new js.Binary('&&', arrayTest, pop()) | |
| 2553 : arrayTest; | |
| 2554 js.Binary notObjectOrIndexingTest = | |
| 2555 new js.Binary('||', objectTest, notIndexingTest); | |
| 2556 test = new js.Binary('&&', stringTest, notObjectOrIndexingTest); | |
| 2557 } else { | |
| 2558 compiler.internalError(input, 'Unexpected check.'); | |
| 2559 } | 2489 } |
| 2560 return test; | 2490 compiler.internalError(input, 'Unexpected check.'); |
| 2491 return null; |
| 2561 } | 2492 } |
| 2562 | 2493 |
| 2563 void visitTypeConversion(HTypeConversion node) { | 2494 void visitTypeConversion(HTypeConversion node) { |
| 2564 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { | 2495 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { |
| 2565 ClassWorld classWorld = compiler.world; | 2496 ClassWorld classWorld = compiler.world; |
| 2566 // An int check if the input is not int or null, is not | 2497 // An int check if the input is not int or null, is not |
| 2567 // sufficient for doing an argument or receiver check. | 2498 // sufficient for doing an argument or receiver check. |
| 2568 assert(compiler.trustTypeAnnotations || | 2499 assert(compiler.trustTypeAnnotations || |
| 2569 !node.checkedType.containsOnlyInt(classWorld) || | 2500 !node.checkedType.containsOnlyInt(classWorld) || |
| 2570 node.checkedInput.isIntegerOrNull(compiler)); | 2501 node.checkedInput.isIntegerOrNull(compiler)); |
| 2571 js.Expression test = generateTest(node.checkedInput, node.checkedType); | 2502 js.Expression test = generateReceiverOrArgumentTypeTest( |
| 2503 node.checkedInput, node.checkedType); |
| 2572 js.Block oldContainer = currentContainer; | 2504 js.Block oldContainer = currentContainer; |
| 2573 js.Statement body = new js.Block.empty(); | 2505 js.Statement body = new js.Block.empty(); |
| 2574 currentContainer = body; | 2506 currentContainer = body; |
| 2575 if (node.isArgumentTypeCheck) { | 2507 if (node.isArgumentTypeCheck) { |
| 2576 generateThrowWithHelper('iae', node.checkedInput); | 2508 generateThrowWithHelper('iae', node.checkedInput); |
| 2577 } else if (node.isReceiverTypeCheck) { | 2509 } else if (node.isReceiverTypeCheck) { |
| 2578 use(node.checkedInput); | 2510 use(node.checkedInput); |
| 2579 String methodName = | 2511 String methodName = |
| 2580 backend.namer.invocationName(node.receiverTypeCheckSelector); | 2512 backend.namer.invocationName(node.receiverTypeCheckSelector); |
| 2581 js.Expression call = js.propertyCall(pop(), methodName, []); | 2513 js.Expression call = js.propertyCall(pop(), methodName, []); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2715 js.PropertyAccess accessHelper(String name) { | 2647 js.PropertyAccess accessHelper(String name) { |
| 2716 Element helper = backend.findHelper(name); | 2648 Element helper = backend.findHelper(name); |
| 2717 if (helper == null) { | 2649 if (helper == null) { |
| 2718 // For mocked-up tests. | 2650 // For mocked-up tests. |
| 2719 return js.js('(void 0).$name'); | 2651 return js.js('(void 0).$name'); |
| 2720 } | 2652 } |
| 2721 registry.registerStaticUse(helper); | 2653 registry.registerStaticUse(helper); |
| 2722 return backend.namer.elementAccess(helper); | 2654 return backend.namer.elementAccess(helper); |
| 2723 } | 2655 } |
| 2724 } | 2656 } |
| OLD | NEW |