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

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

Issue 2479323003: Adding check or trust type checks to builder_kernel.dart. (Closed)
Patch Set: . Created 4 years, 1 month 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
Index: pkg/compiler/lib/src/ssa/type_builder.dart
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
new file mode 100644
index 0000000000000000000000000000000000000000..605678bf87046c6e5dfb45e6518843d8f4b449ae
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -0,0 +1,252 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'graph_builder.dart';
+import 'nodes.dart';
+import '../closure.dart';
+import '../common.dart';
+import '../dart_types.dart';
+import '../types/types.dart';
+import '../elements/elements.dart';
+import '../io/source_information.dart';
+import '../universe/selector.dart' show Selector;
+import '../universe/use.dart' show TypeUse;
+
+/// Functions to insert type checking, coercion, and instruction insertion
+/// depending on the environment for dart code.
+class TypeBuilder {
+ final GraphBuilder builder;
+ TypeBuilder(this.builder);
+
+ /// Create an instruction to simply trust the provided type.
+ HInstruction _trustType(HInstruction original, DartType type) {
+ assert(builder.compiler.options.trustTypeAnnotations);
+ assert(type != null);
+ type = builder.localsHandler.substInContext(type);
+ type = type.unaliased;
+ if (type.isDynamic) return original;
+ if (!type.isInterfaceType) return original;
+ if (type.isObject) return original;
+ // The type element is either a class or the void element.
+ Element element = type.element;
+ TypeMask mask = new TypeMask.subtype(element, builder.compiler.closedWorld);
+ return new HTypeKnown.pinned(mask, original);
+ }
+
+ /// Produces code that checks the runtime type is actually the type specified
+ /// by attempting a type conversion.
+ HInstruction _checkType(HInstruction original, DartType type, int kind) {
+ assert(builder.compiler.options.enableTypeAssertions);
+ assert(type != null);
+ type = builder.localsHandler.substInContext(type);
+ HInstruction other = buildTypeConversion(original, type, kind);
+ // TODO(johnniwinther): This operation on `registry` may be inconsistent.
+ // If it is needed then it seems likely that similar invocations of
+ // `buildTypeConversion` in `SsaBuilder.visitAs` should also be followed by
+ // a similar operation on `registry`; otherwise, this one might not be
+ // needed.
+ builder.registry?.registerTypeUse(new TypeUse.isCheck(type));
+ return other;
+ }
+
+ /// Depending on the context and the mode, wrap the given type in an
+ /// instruction that checks the type is what we expect or automatically
+ /// trusts the written type.
+ HInstruction potentiallyCheckOrTrustType(HInstruction original, DartType type,
Harry Terkelsen 2016/11/14 18:37:06 there are a few places in the code where you do "i
Emily Fortuna 2016/11/14 19:03:39 I saw that too, when I was porting the original co
+ {int kind: HTypeConversion.CHECKED_MODE_CHECK}) {
+ if (type == null) return original;
+ HInstruction checkedOrTrusted = original;
+ if (builder.compiler.options.trustTypeAnnotations) {
+ checkedOrTrusted = _trustType(original, type);
+ } else if (builder.compiler.options.enableTypeAssertions) {
+ checkedOrTrusted = _checkType(original, type, kind);
+ }
+ if (checkedOrTrusted == original) return original;
+ builder.add(checkedOrTrusted);
+ return checkedOrTrusted;
+ }
+
+ /// Helper to create an instruction that gets the value of a type variable.
+ HInstruction addTypeVariableReference(TypeVariableType type, Element member,
+ {SourceInformation sourceInformation}) {
+ assert(assertTypeInContext(type));
+ if (type is MethodTypeVariableType) {
+ return builder.graph.addConstantNull(builder.compiler);
+ }
+ bool isClosure = member.enclosingElement.isClosure;
+ if (isClosure) {
+ ClosureClassElement closureClass = member.enclosingElement;
+ member = closureClass.methodElement;
+ member = member.outermostEnclosingMemberOrTopLevel;
+ }
+ bool isInConstructorContext =
+ member.isConstructor || member.isGenerativeConstructorBody;
+ Local typeVariableLocal =
+ builder.localsHandler.getTypeVariableAsLocal(type);
+ if (isClosure) {
+ if (member.isFactoryConstructor ||
+ (isInConstructorContext &&
+ builder.hasDirectLocal(typeVariableLocal))) {
+ // The type variable is used from a closure in a factory constructor.
+ // The value of the type argument is stored as a local on the closure
+ // itself.
+ return builder.localsHandler
+ .readLocal(typeVariableLocal, sourceInformation: sourceInformation);
+ } else if (member.isFunction ||
+ member.isGetter ||
+ member.isSetter ||
+ isInConstructorContext) {
+ // The type variable is stored on the "enclosing object" and needs to be
+ // accessed using the this-reference in the closure.
+ return readTypeVariable(type, member,
+ sourceInformation: sourceInformation);
+ } else {
+ assert(member.isField);
+ // The type variable is stored in a parameter of the method.
+ return builder.localsHandler.readLocal(typeVariableLocal);
+ }
+ } else if (isInConstructorContext ||
+ // When [member] is a field, we can be either
+ // generating a checked setter or inlining its
+ // initializer in a constructor. An initializer is
+ // never built standalone, so in that case [target] is not
+ // the [member] itself.
+ (member.isField && member != builder.targetElement)) {
+ // The type variable is stored in a parameter of the method.
+ return builder.localsHandler
+ .readLocal(typeVariableLocal, sourceInformation: sourceInformation);
+ } else if (member.isInstanceMember) {
+ // The type variable is stored on the object.
+ return readTypeVariable(type, member,
+ sourceInformation: sourceInformation);
+ } else {
+ builder.compiler.reporter.internalError(
+ type.element, 'Unexpected type variable in static context.');
+ return null;
+ }
+ }
+
+ /// Generate code to extract the type argument from the object.
+ HInstruction readTypeVariable(TypeVariableType variable, Element member,
+ {SourceInformation sourceInformation}) {
+ assert(member.isInstanceMember);
+ assert(variable is! MethodTypeVariableType);
+ HInstruction target = builder.localsHandler.readThis();
+ builder.push(
+ new HTypeInfoReadVariable(variable, target, builder.backend.dynamicType)
+ ..sourceInformation = sourceInformation);
+ return builder.pop();
+ }
+
+ HInstruction buildTypeArgumentRepresentations(
+ DartType type, Element sourceElement) {
+ assert(!type.isTypeVariable);
+ // Compute the representation of the type arguments, including access
+ // to the runtime type information for type variables as instructions.
+ assert(type.element.isClass);
+ InterfaceType interface = type;
+ List<HInstruction> inputs = <HInstruction>[];
+ for (DartType argument in interface.typeArguments) {
+ inputs.add(analyzeTypeArgument(argument, sourceElement));
+ }
+ HInstruction representation = new HTypeInfoExpression(
+ TypeInfoExpressionKind.INSTANCE,
+ interface.element.thisType,
+ inputs,
+ builder.backend.dynamicType);
+ return representation;
+ }
+
+ /// Check that [type] is valid in the context of `localsHandler.contextClass`.
+ /// This should only be called in assertions.
+ bool assertTypeInContext(DartType type, [Spannable spannable]) {
+ return invariant(spannable == null ? CURRENT_ELEMENT_SPANNABLE : spannable,
+ () {
+ ClassElement contextClass = Types.getClassContext(type);
+ return contextClass == null ||
+ contextClass == builder.localsHandler.contextClass;
+ },
+ message: "Type '$type' is not valid context of "
+ "${builder.localsHandler.contextClass}.");
+ }
+
+ HInstruction analyzeTypeArgument(DartType argument, Element sourceElement,
+ {SourceInformation sourceInformation}) {
+ assert(assertTypeInContext(argument));
+ argument = argument.unaliased;
+ if (argument.treatAsDynamic) {
+ // Represent [dynamic] as [null].
+ return builder.graph.addConstantNull(builder.compiler);
+ }
+
+ if (argument.isTypeVariable) {
+ return addTypeVariableReference(argument, sourceElement,
+ sourceInformation: sourceInformation);
+ }
+
+ List<HInstruction> inputs = <HInstruction>[];
+ argument.forEachTypeVariable((variable) {
+ if (variable is! MethodTypeVariableType) {
+ inputs.add(analyzeTypeArgument(variable, sourceElement));
+ }
+ });
+ HInstruction result = new HTypeInfoExpression(
+ TypeInfoExpressionKind.COMPLETE,
+ argument,
+ inputs,
+ builder.backend.dynamicType)..sourceInformation = sourceInformation;
+ builder.add(result);
+ return result;
+ }
+
+ /// In checked mode, generate type tests for the parameters of the inlined
+ /// function.
+ void potentiallyCheckInlinedParameterTypes(FunctionElement function) {
+ if (!checkOrTrustTypes) return;
+
+ FunctionSignature signature = function.functionSignature;
+ signature.orderedForEachParameter((ParameterElement parameter) {
+ HInstruction argument = builder.localsHandler.readLocal(parameter);
+ potentiallyCheckOrTrustType(argument, parameter.type);
+ });
+ }
+
+ bool get checkOrTrustTypes =>
+ builder.compiler.options.enableTypeAssertions ||
+ builder.compiler.options.trustTypeAnnotations;
+
+ /// Build a [HTypeConversion] for converting [original] to type [type].
+ ///
+ /// Invariant: [type] must be valid in the context.
+ /// See [LocalsHandler.substInContext].
+ HInstruction buildTypeConversion(
+ HInstruction original, DartType type, int kind) {
+ if (type == null) return original;
+ // GENERIC_METHODS: The following statement was added for parsing and
+ // ignoring method type variables; must be generalized for full support of
+ // generic methods.
+ type = type.dynamifyMethodTypeVariableType;
+ type = type.unaliased;
+ assert(assertTypeInContext(type, original));
+ if (type.isInterfaceType && !type.treatAsRaw) {
+ TypeMask subtype =
+ new TypeMask.subtype(type.element, builder.compiler.closedWorld);
+ HInstruction representations =
+ buildTypeArgumentRepresentations(type, builder.sourceElement);
+ builder.add(representations);
+ return new HTypeConversion.withTypeRepresentation(
+ type, kind, subtype, original, representations);
+ } else if (type.isTypeVariable) {
+ TypeMask subtype = original.instructionType;
+ HInstruction typeVariable =
+ addTypeVariableReference(type, builder.sourceElement);
+ return new HTypeConversion.withTypeRepresentation(
+ type, kind, subtype, original, typeVariable);
+ } else if (type.isFunctionType) {
+ return builder.buildFunctionTypeConversion(original, type, kind);
+ } else {
+ return original.convertType(builder.compiler, type, kind);
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698