| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/codegen.dart' show CodegenRegistry; | 9 import '../common/codegen.dart' show CodegenRegistry; |
| 10 import '../common/names.dart'; | 10 import '../common/names.dart'; |
| (...skipping 1998 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2009 HInstruction listInstruction; | 2009 HInstruction listInstruction; |
| 2010 if (listLiteral.isConst) { | 2010 if (listLiteral.isConst) { |
| 2011 listInstruction = graph.addConstant( | 2011 listInstruction = graph.addConstant( |
| 2012 _elementMap.getConstantValue(listLiteral), closedWorld); | 2012 _elementMap.getConstantValue(listLiteral), closedWorld); |
| 2013 } else { | 2013 } else { |
| 2014 List<HInstruction> elements = <HInstruction>[]; | 2014 List<HInstruction> elements = <HInstruction>[]; |
| 2015 for (ir.Expression element in listLiteral.expressions) { | 2015 for (ir.Expression element in listLiteral.expressions) { |
| 2016 element.accept(this); | 2016 element.accept(this); |
| 2017 elements.add(pop()); | 2017 elements.add(pop()); |
| 2018 } | 2018 } |
| 2019 listInstruction = | 2019 listInstruction = buildLiteralList(elements); |
| 2020 new HLiteralList(elements, commonMasks.extendableArrayType); | |
| 2021 add(listInstruction); | 2020 add(listInstruction); |
| 2022 InterfaceType type = localsHandler.substInContext(_commonElements | 2021 InterfaceType type = localsHandler.substInContext(_commonElements |
| 2023 .listType(_elementMap.getDartType(listLiteral.typeArgument))); | 2022 .listType(_elementMap.getDartType(listLiteral.typeArgument))); |
| 2024 listInstruction = _setListRuntimeTypeInfoIfNeeded(listInstruction, type); | 2023 listInstruction = _setListRuntimeTypeInfoIfNeeded(listInstruction, type); |
| 2025 } | 2024 } |
| 2026 | 2025 |
| 2027 TypeMask type = _typeInferenceMap.typeOfListLiteral( | 2026 TypeMask type = _typeInferenceMap.typeOfListLiteral( |
| 2028 targetElement, listLiteral, closedWorld); | 2027 targetElement, listLiteral, closedWorld); |
| 2029 if (!type.containsAll(closedWorld)) { | 2028 if (!type.containsAll(closedWorld)) { |
| 2030 listInstruction.instructionType = type; | 2029 listInstruction.instructionType = type; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2048 constructorArgs.add(pop()); | 2047 constructorArgs.add(pop()); |
| 2049 } | 2048 } |
| 2050 | 2049 |
| 2051 // The constructor is a procedure because it's a factory. | 2050 // The constructor is a procedure because it's a factory. |
| 2052 FunctionEntity constructor; | 2051 FunctionEntity constructor; |
| 2053 List<HInstruction> inputs = <HInstruction>[]; | 2052 List<HInstruction> inputs = <HInstruction>[]; |
| 2054 if (constructorArgs.isEmpty) { | 2053 if (constructorArgs.isEmpty) { |
| 2055 constructor = _commonElements.mapLiteralConstructorEmpty; | 2054 constructor = _commonElements.mapLiteralConstructorEmpty; |
| 2056 } else { | 2055 } else { |
| 2057 constructor = _commonElements.mapLiteralConstructor; | 2056 constructor = _commonElements.mapLiteralConstructor; |
| 2058 HLiteralList argList = | 2057 HLiteralList argList = buildLiteralList(constructorArgs); |
| 2059 new HLiteralList(constructorArgs, commonMasks.extendableArrayType); | |
| 2060 add(argList); | 2058 add(argList); |
| 2061 inputs.add(argList); | 2059 inputs.add(argList); |
| 2062 } | 2060 } |
| 2063 | 2061 |
| 2064 assert( | 2062 assert( |
| 2065 constructor is ConstructorEntity && constructor.isFactoryConstructor); | 2063 constructor is ConstructorEntity && constructor.isFactoryConstructor); |
| 2066 | 2064 |
| 2067 InterfaceType type = localsHandler.substInContext(_commonElements.mapType( | 2065 InterfaceType type = localsHandler.substInContext(_commonElements.mapType( |
| 2068 _elementMap.getDartType(mapLiteral.keyType), | 2066 _elementMap.getDartType(mapLiteral.keyType), |
| 2069 _elementMap.getDartType(mapLiteral.valueType))); | 2067 _elementMap.getDartType(mapLiteral.valueType))); |
| (...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2397 return; | 2395 return; |
| 2398 } | 2396 } |
| 2399 FunctionEntity function = _elementMap.getMember(target); | 2397 FunctionEntity function = _elementMap.getMember(target); |
| 2400 TypeMask typeMask = _typeInferenceMap.getReturnTypeOf(function); | 2398 TypeMask typeMask = _typeInferenceMap.getReturnTypeOf(function); |
| 2401 | 2399 |
| 2402 // TODO(sra): For JS interop external functions, use a different function to | 2400 // TODO(sra): For JS interop external functions, use a different function to |
| 2403 // build arguments. | 2401 // build arguments. |
| 2404 List<HInstruction> arguments = | 2402 List<HInstruction> arguments = |
| 2405 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 2403 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 2406 | 2404 |
| 2407 // TODO(johnniwinther): Move factory calls to a helper function? | |
| 2408 if (function is ConstructorEntity && function.isFactoryConstructor) { | 2405 if (function is ConstructorEntity && function.isFactoryConstructor) { |
| 2409 if (function.isExternal && function.isFromEnvironmentConstructor) { | 2406 handleInvokeFactoryConstructor(invocation, function, typeMask, arguments); |
| 2410 if (invocation.isConst) { | 2407 return; |
| 2411 // Just like all const constructors (see visitConstructorInvocation). | 2408 } |
| 2412 stack.add(graph.addConstant( | 2409 |
| 2413 _elementMap.getConstantValue(invocation), closedWorld)); | 2410 // Static methods currently ignore the type parameters. |
| 2414 } else { | 2411 _pushStaticInvocation(function, arguments, typeMask); |
| 2415 generateUnsupportedError( | 2412 } |
| 2416 invocation, | 2413 |
| 2417 '${function.enclosingClass.name}.${function.name} ' | 2414 void handleInvokeFactoryConstructor( |
| 2418 'can only be used as a const constructor'); | 2415 ir.StaticInvocation invocation, |
| 2419 } | 2416 ConstructorEntity function, |
| 2420 return; | 2417 TypeMask typeMask, |
| 2418 List<HInstruction> arguments) { |
| 2419 if (function.isExternal && function.isFromEnvironmentConstructor) { |
| 2420 if (invocation.isConst) { |
| 2421 // Just like all const constructors (see visitConstructorInvocation). |
| 2422 stack.add(graph.addConstant( |
| 2423 _elementMap.getConstantValue(invocation), closedWorld)); |
| 2424 } else { |
| 2425 generateUnsupportedError( |
| 2426 invocation, |
| 2427 '${function.enclosingClass.name}.${function.name} ' |
| 2428 'can only be used as a const constructor'); |
| 2429 } |
| 2430 return; |
| 2431 } |
| 2432 |
| 2433 bool isFixedList = false; // Any fixed list, e.g. new List(10), UInt8List. |
| 2434 |
| 2435 // Recognize `new List()` and `new List(n)`. |
| 2436 bool isFixedListConstructorCall = false; |
| 2437 bool isGrowableListConstructorCall = false; |
| 2438 if (commonElements.isUnnamedListConstructor(function) && |
| 2439 invocation.arguments.named.isEmpty) { |
| 2440 int argumentCount = invocation.arguments.positional.length; |
| 2441 isFixedListConstructorCall = argumentCount == 1; |
| 2442 isGrowableListConstructorCall = argumentCount == 0; |
| 2443 isFixedList = isFixedListConstructorCall; |
| 2444 } |
| 2445 |
| 2446 TypeMask resultType = typeMask; |
| 2447 |
| 2448 bool isJSArrayTypedConstructor = |
| 2449 function == commonElements.jsArrayTypedConstructor; |
| 2450 |
| 2451 if (isFixedListConstructorCall) { |
| 2452 assert(arguments.length == 1); |
| 2453 HInstruction lengthInput = arguments.first; |
| 2454 if (!lengthInput.isNumber(closedWorld)) { |
| 2455 HTypeConversion conversion = new HTypeConversion( |
| 2456 null, |
| 2457 HTypeConversion.ARGUMENT_TYPE_CHECK, |
| 2458 commonMasks.numType, |
| 2459 lengthInput); |
| 2460 add(conversion); |
| 2461 lengthInput = conversion; |
| 2462 } |
| 2463 js.Template code = js.js.parseForeignJS('new Array(#)'); |
| 2464 var behavior = new native.NativeBehavior(); |
| 2465 // TODO(redemption): Find the full type being created here, |
| 2466 // e.g. JSArray<Set<T>>, via 'computeEffectiveTargetType'. |
| 2467 var expectedType = closedWorld.elementEnvironment |
| 2468 .getRawType(_commonElements.jsArrayClass); |
| 2469 behavior.typesInstantiated.add(expectedType); |
| 2470 behavior.typesReturned.add(expectedType); |
| 2471 |
| 2472 // The allocation can throw only if the given length is a double or |
| 2473 // outside the unsigned 32 bit range. |
| 2474 // TODO(sra): Array allocation should be an instruction so that canThrow |
| 2475 // can depend on a length type discovered in optimization. |
| 2476 bool canThrow = true; |
| 2477 if (lengthInput.isUInt32(closedWorld)) { |
| 2478 canThrow = false; |
| 2421 } | 2479 } |
| 2422 | 2480 |
| 2423 // Factory constructors take type parameters; other static methods ignore | 2481 // TODO(redemption): Pick up site-specific type inference type, which |
| 2424 // them. | 2482 // might be more precise, e.g. a container type. |
| 2425 | 2483 resultType = commonMasks.fixedListType; |
| 2484 HForeignCode foreign = new HForeignCode(code, resultType, arguments, |
| 2485 nativeBehavior: behavior, |
| 2486 throwBehavior: canThrow |
| 2487 ? native.NativeThrowBehavior.MAY |
| 2488 : native.NativeThrowBehavior.NEVER); |
| 2489 push(foreign); |
| 2490 // TODO(redemption): Global type analysis tracing may have determined that |
| 2491 // the fixed-length property is never checked. If so, we can avoid marking |
| 2492 // the array. |
| 2493 { |
| 2494 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); |
| 2495 // We set the instruction as [canThrow] to avoid it being dead code. |
| 2496 // We need a finer grained side effect. |
| 2497 add(new HForeignCode(code, commonMasks.nullType, [stack.last], |
| 2498 throwBehavior: native.NativeThrowBehavior.MAY)); |
| 2499 } |
| 2500 } else if (isGrowableListConstructorCall) { |
| 2501 push(buildLiteralList(<HInstruction>[])); |
| 2502 // TODO(sra): Pick up type inference type, which might be more precise, |
| 2503 // e.g. a container type. |
| 2504 resultType = commonMasks.growableListType; |
| 2505 stack.last.instructionType = resultType; |
| 2506 } else if (isJSArrayTypedConstructor) { |
| 2507 // TODO(sra): Instead of calling the identity-like factory constructor, |
| 2508 // simply select the single argument. |
| 2509 // Factory constructors take type parameters. |
| 2426 if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) { | 2510 if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) { |
| 2427 _addTypeArguments(arguments, invocation.arguments); | 2511 _addTypeArguments(arguments, invocation.arguments); |
| 2428 } | 2512 } |
| 2429 | |
| 2430 _pushStaticInvocation(function, arguments, typeMask); | 2513 _pushStaticInvocation(function, arguments, typeMask); |
| 2431 | 2514 } else { |
| 2432 bool isFixedListConstructorCall = false; | 2515 // Factory constructors take type parameters. |
| 2433 bool isGrowableListConstructorCall = false; | 2516 if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) { |
| 2434 if (commonElements.isUnnamedListConstructor(function) && | 2517 _addTypeArguments(arguments, invocation.arguments); |
| 2435 invocation.arguments.named.isEmpty) { | |
| 2436 isFixedListConstructorCall = | |
| 2437 invocation.arguments.positional.length == 1; | |
| 2438 isGrowableListConstructorCall = invocation.arguments.positional.isEmpty; | |
| 2439 } | 2518 } |
| 2440 bool isJSArrayTypedConstructor = | |
| 2441 function == commonElements.jsArrayTypedConstructor; | |
| 2442 if (rtiNeed.classNeedsRti(commonElements.listClass) && | |
| 2443 (isFixedListConstructorCall || | |
| 2444 isGrowableListConstructorCall || | |
| 2445 isJSArrayTypedConstructor)) { | |
| 2446 InterfaceType type = _elementMap.createInterfaceType( | |
| 2447 target.enclosingClass, invocation.arguments.types); | |
| 2448 stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type)); | |
| 2449 } | |
| 2450 } else { | |
| 2451 _pushStaticInvocation(function, arguments, typeMask); | 2519 _pushStaticInvocation(function, arguments, typeMask); |
| 2452 } | 2520 } |
| 2521 |
| 2522 HInstruction newInstance = stack.last; |
| 2523 |
| 2524 if (isFixedList) { |
| 2525 // If we inlined a constructor the call-site-specific type from type |
| 2526 // inference (e.g. a container type) will not be on the node. Store the |
| 2527 // more specialized type on the allocation. |
| 2528 newInstance.instructionType = resultType; |
| 2529 graph.allocatedFixedLists.add(newInstance); |
| 2530 } |
| 2531 |
| 2532 if (rtiNeed.classNeedsRti(commonElements.listClass) && |
| 2533 (isFixedListConstructorCall || |
| 2534 isGrowableListConstructorCall || |
| 2535 isJSArrayTypedConstructor)) { |
| 2536 InterfaceType type = _elementMap.createInterfaceType( |
| 2537 invocation.target.enclosingClass, invocation.arguments.types); |
| 2538 stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type)); |
| 2539 } |
| 2540 |
| 2541 // TODO(redemption): For redirecting factory constructors, check or trust |
| 2542 // the type. |
| 2453 } | 2543 } |
| 2454 | 2544 |
| 2455 void handleInvokeStaticForeign( | 2545 void handleInvokeStaticForeign( |
| 2456 ir.StaticInvocation invocation, ir.Procedure target) { | 2546 ir.StaticInvocation invocation, ir.Procedure target) { |
| 2457 String name = target.name.name; | 2547 String name = target.name.name; |
| 2458 if (name == 'JS') { | 2548 if (name == 'JS') { |
| 2459 handleForeignJs(invocation); | 2549 handleForeignJs(invocation); |
| 2460 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { | 2550 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { |
| 2461 handleForeignJsCurrentIsolateContext(invocation); | 2551 handleForeignJsCurrentIsolateContext(invocation); |
| 2462 } else if (name == 'JS_CALL_IN_ISOLATE') { | 2552 } else if (name == 'JS_CALL_IN_ISOLATE') { |
| (...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3017 // arguments), in case the [noSuchMethod] implementation calls | 3107 // arguments), in case the [noSuchMethod] implementation calls |
| 3018 // [JSInvocationMirror._invokeOn]. | 3108 // [JSInvocationMirror._invokeOn]. |
| 3019 // TODO(johnniwinther): Register this more precisely. | 3109 // TODO(johnniwinther): Register this more precisely. |
| 3020 registry?.registerDynamicUse(new DynamicUse(selector, null)); | 3110 registry?.registerDynamicUse(new DynamicUse(selector, null)); |
| 3021 } | 3111 } |
| 3022 | 3112 |
| 3023 ConstantValue nameConstant = constantSystem.createString(publicName); | 3113 ConstantValue nameConstant = constantSystem.createString(publicName); |
| 3024 | 3114 |
| 3025 js.Name internalName = namer.invocationName(selector); | 3115 js.Name internalName = namer.invocationName(selector); |
| 3026 | 3116 |
| 3027 var argumentsInstruction = | 3117 var argumentsInstruction = buildLiteralList(arguments); |
| 3028 new HLiteralList(arguments, commonMasks.extendableArrayType); | |
| 3029 add(argumentsInstruction); | 3118 add(argumentsInstruction); |
| 3030 | 3119 |
| 3031 var argumentNames = new List<HInstruction>(); | 3120 var argumentNames = new List<HInstruction>(); |
| 3032 for (String argumentName in selector.namedArguments) { | 3121 for (String argumentName in selector.namedArguments) { |
| 3033 ConstantValue argumentNameConstant = | 3122 ConstantValue argumentNameConstant = |
| 3034 constantSystem.createString(argumentName); | 3123 constantSystem.createString(argumentName); |
| 3035 argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld)); | 3124 argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld)); |
| 3036 } | 3125 } |
| 3037 var argumentNamesInstruction = | 3126 var argumentNamesInstruction = buildLiteralList(argumentNames); |
| 3038 new HLiteralList(argumentNames, commonMasks.extendableArrayType); | |
| 3039 add(argumentNamesInstruction); | 3127 add(argumentNamesInstruction); |
| 3040 | 3128 |
| 3041 ConstantValue kindConstant = | 3129 ConstantValue kindConstant = |
| 3042 constantSystem.createInt(selector.invocationMirrorKind); | 3130 constantSystem.createInt(selector.invocationMirrorKind); |
| 3043 | 3131 |
| 3044 _pushStaticInvocation( | 3132 _pushStaticInvocation( |
| 3045 _commonElements.createInvocationMirror, | 3133 _commonElements.createInvocationMirror, |
| 3046 [ | 3134 [ |
| 3047 graph.addConstant(nameConstant, closedWorld), | 3135 graph.addConstant(nameConstant, closedWorld), |
| 3048 graph.addConstantStringFromName(internalName, closedWorld), | 3136 graph.addConstantStringFromName(internalName, closedWorld), |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3563 enterBlock.setBlockFlow( | 3651 enterBlock.setBlockFlow( |
| 3564 new HTryBlockInformation( | 3652 new HTryBlockInformation( |
| 3565 kernelBuilder.wrapStatementGraph(bodyGraph), | 3653 kernelBuilder.wrapStatementGraph(bodyGraph), |
| 3566 exception, | 3654 exception, |
| 3567 kernelBuilder.wrapStatementGraph(catchGraph), | 3655 kernelBuilder.wrapStatementGraph(catchGraph), |
| 3568 kernelBuilder.wrapStatementGraph(finallyGraph)), | 3656 kernelBuilder.wrapStatementGraph(finallyGraph)), |
| 3569 exitBlock); | 3657 exitBlock); |
| 3570 kernelBuilder.inTryStatement = previouslyInTryStatement; | 3658 kernelBuilder.inTryStatement = previouslyInTryStatement; |
| 3571 } | 3659 } |
| 3572 } | 3660 } |
| OLD | NEW |