Index: pkg/compiler/lib/src/native/behavior.dart |
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart |
index 7dbab30fe5e6f1e7f29b4a3b0715474e6abca661..7b2313f01f8c13133f747ad8d7a87d46161161ec 100644 |
--- a/pkg/compiler/lib/src/native/behavior.dart |
+++ b/pkg/compiler/lib/src/native/behavior.dart |
@@ -645,12 +645,26 @@ class NativeBehavior { |
static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { |
FunctionType type = method.computeType(compiler.resolution); |
var behavior = new NativeBehavior(); |
- behavior.typesReturned.add(type.returnType); |
+ var returnType = type.returnType; |
+ bool isInterop = compiler.backend.isJsInterop(method); |
+ // Note: For dart:html and other internal libraries we maintain, we can |
+ // trust the return type and use it to limit what we enqueue. We have to |
+ // be more conservative about JS interop types and assume they can return |
+ // anything (unless the user provides the experimental flag to trust the |
+ // type of js-interop APIs). We do restrict the allocation effects and say |
+ // that interop calls create only interop types (which may be unsound if |
+ // an interop call returns a DOM type and declares a dynamic return type, |
+ // but otherwise we would include a lot of code by default). |
+ // TODO(sigmund,sra): consider doing something better for numeric types. |
+ behavior.typesReturned.add( |
+ !isInterop || compiler.trustJSInteropTypeAnnotations ? returnType |
+ : const DynamicType()); |
if (!type.returnType.isVoid) { |
// Declared types are nullable. |
behavior.typesReturned.add(compiler.coreTypes.nullType); |
} |
- behavior._capture(type, compiler.resolution); |
+ behavior._capture(type, compiler.resolution, isInterop: isInterop, |
sra1
2015/12/01 00:38:07
break before isInterop
Siggi Cherem (dart-lang)
2015/12/01 00:43:54
Done.
|
+ compiler: compiler); |
// TODO(sra): Optional arguments are currently missing from the |
// DartType. This should be fixed so the following work-around can be |
@@ -668,10 +682,15 @@ class NativeBehavior { |
Resolution resolution = compiler.resolution; |
DartType type = field.computeType(resolution); |
var behavior = new NativeBehavior(); |
- behavior.typesReturned.add(type); |
+ bool isInterop = compiler.backend.isJsInterop(field); |
+ // TODO(sigmund,sra): consider doing something better for numeric types. |
+ behavior.typesReturned.add( |
+ !isInterop || compiler.trustJSInteropTypeAnnotations ? type |
+ : const DynamicType()); |
// Declared types are nullable. |
behavior.typesReturned.add(resolution.coreTypes.nullType); |
- behavior._capture(type, resolution); |
+ behavior._capture(type, resolution, |
+ isInterop: isInterop, compiler: compiler); |
behavior._overrideWithAnnotations(field, compiler); |
return behavior; |
} |
@@ -765,17 +784,49 @@ class NativeBehavior { |
/// Models the behavior of Dart code receiving instances and methods of [type] |
/// from native code. We usually start the analysis by capturing a native |
/// method that has been used. |
- void _capture(DartType type, Resolution resolution) { |
+ /// |
+ /// We assume that JS-interop APIs cannot instantiate Dart types or |
+ /// non-JSInterop native types. |
+ void _capture(DartType type, Resolution resolution, |
+ {bool isInterop: false, Compiler compiler}) { |
type.computeUnaliased(resolution); |
type = type.unaliased; |
if (type is FunctionType) { |
FunctionType functionType = type; |
- _capture(functionType.returnType, resolution); |
+ _capture(functionType.returnType, resolution, |
+ isInterop: isInterop, compiler: compiler); |
for (DartType parameter in functionType.parameterTypes) { |
_escape(parameter, resolution); |
} |
} else { |
- typesInstantiated.add(type); |
+ DartType instantiated = null; |
+ JavaScriptBackend backend = compiler?.backend; |
+ if (!isInterop) { |
+ typesInstantiated.add(type); |
+ } else { |
+ if (type.element != null && backend.isNative(type.element)) { |
+ // Any declared native or interop type (isNative implies isJsInterop) |
+ // is assumed to be allocated. |
+ typesInstantiated.add(type); |
+ } |
+ |
+ if (!compiler.trustJSInteropTypeAnnotations || |
+ type.isDynamic || type.isObject) { |
+ // By saying that only JS-interop types can be created, we prevent |
+ // pulling in every other native type (e.g. all of dart:html) when a |
+ // JS interop API returns dynamic or when we don't trust the type |
+ // annotations. This means that to some degree we still use the return |
+ // type to decide whether to include native types, even if we don't |
+ // trust the type annotation. |
+ typesInstantiated.add( |
+ backend.helpers.jsJavaScriptObjectClass.thisType); |
+ } else { |
+ // Otherwise, when the declared type is a Dart type, we do not |
+ // register an allocation because we assume it cannot be instantiated |
+ // from within the JS-interop code. It must have escaped from another |
+ // API. |
+ } |
+ } |
} |
} |