Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Unified Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2984183002: dart2js-kernel: Recognize some List constructors. (Closed)
Patch Set: Use elementEnvironement to build type Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/ssa/builder_kernel.dart
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index d97fe22aaa4c95a60c2667a3c3d337f01869ed55..40220c234176dbb9f21281066b017c1503ec3ab6 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2016,8 +2016,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
element.accept(this);
elements.add(pop());
}
- listInstruction =
- new HLiteralList(elements, commonMasks.extendableArrayType);
+ listInstruction = buildLiteralList(elements);
add(listInstruction);
InterfaceType type = localsHandler.substInContext(_commonElements
.listType(_elementMap.getDartType(listLiteral.typeArgument)));
@@ -2055,8 +2054,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
constructor = _commonElements.mapLiteralConstructorEmpty;
} else {
constructor = _commonElements.mapLiteralConstructor;
- HLiteralList argList =
- new HLiteralList(constructorArgs, commonMasks.extendableArrayType);
+ HLiteralList argList = buildLiteralList(constructorArgs);
add(argList);
inputs.add(argList);
}
@@ -2404,52 +2402,144 @@ class KernelSsaGraphBuilder extends ir.Visitor
List<HInstruction> arguments =
_visitArgumentsForStaticTarget(target.function, invocation.arguments);
- // TODO(johnniwinther): Move factory calls to a helper function?
if (function is ConstructorEntity && function.isFactoryConstructor) {
- if (function.isExternal && function.isFromEnvironmentConstructor) {
- if (invocation.isConst) {
- // Just like all const constructors (see visitConstructorInvocation).
- stack.add(graph.addConstant(
- _elementMap.getConstantValue(invocation), closedWorld));
- } else {
- generateUnsupportedError(
- invocation,
- '${function.enclosingClass.name}.${function.name} '
- 'can only be used as a const constructor');
- }
- return;
- }
+ handleInvokeFactoryConstructor(invocation, function, typeMask, arguments);
+ return;
+ }
- // Factory constructors take type parameters; other static methods ignore
- // them.
+ // Static methods currently ignore the type parameters.
+ _pushStaticInvocation(function, arguments, typeMask);
+ }
- if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) {
- _addTypeArguments(arguments, invocation.arguments);
+ void handleInvokeFactoryConstructor(
+ ir.StaticInvocation invocation,
+ ConstructorEntity function,
+ TypeMask typeMask,
+ List<HInstruction> arguments) {
+ if (function.isExternal && function.isFromEnvironmentConstructor) {
+ if (invocation.isConst) {
+ // Just like all const constructors (see visitConstructorInvocation).
+ stack.add(graph.addConstant(
+ _elementMap.getConstantValue(invocation), closedWorld));
+ } else {
+ generateUnsupportedError(
+ invocation,
+ '${function.enclosingClass.name}.${function.name} '
+ 'can only be used as a const constructor');
}
+ return;
+ }
- _pushStaticInvocation(function, arguments, typeMask);
+ bool isFixedList = false; // Any fixed list, e.g. new List(10), UInt8List.
+
+ // Recognize `new List()` and `new List(n)`.
+ bool isFixedListConstructorCall = false;
+ bool isGrowableListConstructorCall = false;
+ if (commonElements.isUnnamedListConstructor(function) &&
+ invocation.arguments.named.isEmpty) {
+ int argumentCount = invocation.arguments.positional.length;
+ isFixedListConstructorCall = argumentCount == 1;
+ isGrowableListConstructorCall = argumentCount == 0;
+ isFixedList = isFixedListConstructorCall;
+ }
+
+ TypeMask resultType = typeMask;
- bool isFixedListConstructorCall = false;
- bool isGrowableListConstructorCall = false;
- if (commonElements.isUnnamedListConstructor(function) &&
- invocation.arguments.named.isEmpty) {
- isFixedListConstructorCall =
- invocation.arguments.positional.length == 1;
- isGrowableListConstructorCall = invocation.arguments.positional.isEmpty;
+ bool isJSArrayTypedConstructor =
+ function == commonElements.jsArrayTypedConstructor;
+
+ if (isFixedListConstructorCall) {
+ assert(arguments.length == 1);
+ HInstruction lengthInput = arguments.first;
+ if (!lengthInput.isNumber(closedWorld)) {
+ HTypeConversion conversion = new HTypeConversion(
+ null,
+ HTypeConversion.ARGUMENT_TYPE_CHECK,
+ commonMasks.numType,
+ lengthInput);
+ add(conversion);
+ lengthInput = conversion;
+ }
+ js.Template code = js.js.parseForeignJS('new Array(#)');
+ var behavior = new native.NativeBehavior();
+ // TODO(redemption): Find the full type being created here,
+ // e.g. JSArray<Set<T>>, via 'computeEffectiveTargetType'.
+ var expectedType = closedWorld.elementEnvironment
+ .getRawType(_commonElements.jsArrayClass);
+ behavior.typesInstantiated.add(expectedType);
+ behavior.typesReturned.add(expectedType);
+
+ // The allocation can throw only if the given length is a double or
+ // outside the unsigned 32 bit range.
+ // TODO(sra): Array allocation should be an instruction so that canThrow
+ // can depend on a length type discovered in optimization.
+ bool canThrow = true;
+ if (lengthInput.isUInt32(closedWorld)) {
+ canThrow = false;
+ }
+
+ // TODO(redemption): Pick up site-specific type inference type, which
+ // might be more precise, e.g. a container type.
+ resultType = commonMasks.fixedListType;
+ HForeignCode foreign = new HForeignCode(code, resultType, arguments,
+ nativeBehavior: behavior,
+ throwBehavior: canThrow
+ ? native.NativeThrowBehavior.MAY
+ : native.NativeThrowBehavior.NEVER);
+ push(foreign);
+ // TODO(redemption): Global type analysis tracing may have determined that
+ // the fixed-length property is never checked. If so, we can avoid marking
+ // the array.
+ {
+ js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array');
+ // We set the instruction as [canThrow] to avoid it being dead code.
+ // We need a finer grained side effect.
+ add(new HForeignCode(code, commonMasks.nullType, [stack.last],
+ throwBehavior: native.NativeThrowBehavior.MAY));
}
- bool isJSArrayTypedConstructor =
- function == commonElements.jsArrayTypedConstructor;
- if (rtiNeed.classNeedsRti(commonElements.listClass) &&
- (isFixedListConstructorCall ||
- isGrowableListConstructorCall ||
- isJSArrayTypedConstructor)) {
- InterfaceType type = _elementMap.createInterfaceType(
- target.enclosingClass, invocation.arguments.types);
- stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type));
+ } else if (isGrowableListConstructorCall) {
+ push(buildLiteralList(<HInstruction>[]));
+ // TODO(sra): Pick up type inference type, which might be more precise,
+ // e.g. a container type.
+ resultType = commonMasks.growableListType;
+ stack.last.instructionType = resultType;
+ } else if (isJSArrayTypedConstructor) {
+ // TODO(sra): Instead of calling the identity-like factory constructor,
+ // simply select the single argument.
+ // Factory constructors take type parameters.
+ if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) {
+ _addTypeArguments(arguments, invocation.arguments);
}
+ _pushStaticInvocation(function, arguments, typeMask);
} else {
+ // Factory constructors take type parameters.
+ if (closedWorld.rtiNeed.classNeedsRti(function.enclosingClass)) {
+ _addTypeArguments(arguments, invocation.arguments);
+ }
_pushStaticInvocation(function, arguments, typeMask);
}
+
+ HInstruction newInstance = stack.last;
+
+ if (isFixedList) {
+ // If we inlined a constructor the call-site-specific type from type
+ // inference (e.g. a container type) will not be on the node. Store the
+ // more specialized type on the allocation.
+ newInstance.instructionType = resultType;
+ graph.allocatedFixedLists.add(newInstance);
+ }
+
+ if (rtiNeed.classNeedsRti(commonElements.listClass) &&
+ (isFixedListConstructorCall ||
+ isGrowableListConstructorCall ||
+ isJSArrayTypedConstructor)) {
+ InterfaceType type = _elementMap.createInterfaceType(
+ invocation.target.enclosingClass, invocation.arguments.types);
+ stack.add(_setListRuntimeTypeInfoIfNeeded(pop(), type));
+ }
+
+ // TODO(redemption): For redirecting factory constructors, check or trust
+ // the type.
}
void handleInvokeStaticForeign(
@@ -3024,8 +3114,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
js.Name internalName = namer.invocationName(selector);
- var argumentsInstruction =
- new HLiteralList(arguments, commonMasks.extendableArrayType);
+ var argumentsInstruction = buildLiteralList(arguments);
add(argumentsInstruction);
var argumentNames = new List<HInstruction>();
@@ -3034,8 +3123,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
constantSystem.createString(argumentName);
argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld));
}
- var argumentNamesInstruction =
- new HLiteralList(argumentNames, commonMasks.extendableArrayType);
+ var argumentNamesInstruction = buildLiteralList(argumentNames);
add(argumentNamesInstruction);
ConstantValue kindConstant =
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698