Version 2.13.0-9.0.dev
Merge commit '531a3a4ffdd9fde2dcc01f155c5d143d77636410' into 'dev'
diff --git a/pkg/compiler/lib/src/backend_strategy.dart b/pkg/compiler/lib/src/backend_strategy.dart
index b5307e1..92966bc 100644
--- a/pkg/compiler/lib/src/backend_strategy.dart
+++ b/pkg/compiler/lib/src/backend_strategy.dart
@@ -16,6 +16,7 @@
import 'js_backend/enqueuer.dart';
import 'js_backend/inferred_data.dart';
import 'js_emitter/code_emitter_task.dart';
+import 'js_model/locals.dart';
import 'serialization/serialization.dart';
import 'ssa/ssa.dart';
import 'universe/codegen_world_builder.dart';
@@ -65,8 +66,8 @@
SourceSpan spanFromSpannable(Spannable spannable, Entity currentElement);
/// Creates the [TypesInferrer] used by this strategy.
- TypesInferrer createTypesInferrer(
- JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder);
+ TypesInferrer createTypesInferrer(JClosedWorld closedWorld,
+ GlobalLocalsMap globalLocalsMap, InferredDataBuilder inferredDataBuilder);
/// Calls [f] for every member that needs to be serialized for modular code
/// generation and returns an [EntityWriter] for encoding these members in
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 89edda7..6f26060 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -35,6 +35,14 @@
/// Accessor to the information about scopes that closures capture. Used by
/// the SSA builder.
CapturedScope getCapturedScope(MemberEntity entity);
+
+ /// If [entity] is a closure call method or closure signature method, the
+ /// original enclosing member is returned. Otherwise [entity] is returned.
+ ///
+ /// A member and its nested closure share the underlying AST, we need to
+ /// ensure that locals are shared between them. We therefore store the
+ /// locals in the global locals map using the enclosing member as key.
+ MemberEntity getEnclosingMember(MemberEntity entity);
}
/// Enum used for identifying [ScopeInfo] subclasses in serialization.
@@ -68,7 +76,7 @@
case ScopeInfoKind.capturedLoopScope:
return new JsCapturedLoopScope.readFromDataSource(source);
case ScopeInfoKind.closureRepresentationInfo:
- return new KernelClosureClassInfo.readFromDataSource(source);
+ return new JsClosureClassInfo.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
@@ -92,7 +100,8 @@
/// Also parameters to a `sync*` generator must be boxed, because of the way
/// we rewrite sync* functions. See also comments in
/// [ClosureClassMap.useLocal].
- bool localIsUsedInTryOrSync(Local variable) => false;
+ bool localIsUsedInTryOrSync(KernelToLocalsMap localsMap, Local variable) =>
+ false;
/// Loop through each variable that has been defined in this scope, modified
/// anywhere (this scope or another scope) and used in another scope. Because
@@ -104,10 +113,11 @@
/// In the case of loops, this is the set of iteration variables (or any
/// variables declared in the for loop expression (`for (...here...)`) that
/// need to be boxed to snapshot their value.
- void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
+ void forEachBoxedVariable(
+ KernelToLocalsMap localsMap, f(Local local, FieldEntity field)) {}
/// True if [variable] has been mutated and is also used in another scope.
- bool isBoxedVariable(Local variable) => false;
+ bool isBoxedVariable(KernelToLocalsMap localsMap, Local variable) => false;
}
/// Class representing the usage of a scope that has been captured in the
@@ -141,7 +151,7 @@
/// executed. This will encapsulate the value of any variables that have been
/// scoped into this context from outside. This is an accessor to the
/// contextBox that [requiresContextBox] is testing is required.
- Local get context => null;
+ Local get contextBox => null;
}
/// Class that describes the actual mechanics of how values of variables
@@ -195,7 +205,8 @@
///
/// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b
/// would only be a part of boxedVariables.
- List<Local> get boxedLoopVariables => const <Local>[];
+ List<Local> getBoxedLoopVariables(KernelToLocalsMap localsMap) =>
+ const <Local>[];
}
/// Class that describes the actual mechanics of how the converted, rewritten
@@ -239,7 +250,7 @@
throw new UnsupportedError(
'Unexpected ClosureRepresentationInfo kind $kind');
case ScopeInfoKind.closureRepresentationInfo:
- return new KernelClosureClassInfo.readFromDataSource(source);
+ return new JsClosureClassInfo.readFromDataSource(source);
}
throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
}
@@ -247,7 +258,7 @@
/// The original local function before any translation.
///
/// Will be null for methods.
- Local get closureEntity => null;
+ Local getClosureEntity(KernelToLocalsMap localsMap) => null;
/// The entity for the class used to represent the rewritten closure in the
/// emitted JavaScript.
@@ -266,13 +277,14 @@
/// List of locals that this closure class has created corresponding field
/// entities for.
@deprecated
- List<Local> get createdFieldEntities => const <Local>[];
+ List<Local> getCreatedFieldEntities(KernelToLocalsMap localsMap) =>
+ const <Local>[];
/// As shown in the example in the comments at the top of this class, we
/// create fields in the closure class for each captured variable. This is an
/// accessor the [local] for which [field] was created.
/// Returns the [local] for which [field] was created.
- Local getLocalForField(FieldEntity field) {
+ Local getLocalForField(KernelToLocalsMap localsMap, FieldEntity field) {
failedAt(field, "No local for $field.");
return null;
}
@@ -289,12 +301,14 @@
/// strictly variables defined in this closure, unlike the behavior in
/// the superclass ScopeInfo.
@override
- void forEachBoxedVariable(f(Local local, FieldEntity field)) {}
+ void forEachBoxedVariable(
+ KernelToLocalsMap localsMap, f(Local local, FieldEntity field)) {}
/// Loop through each free variable in this closure. Free variables are the
/// variables that have been captured *just* in this closure, not in nested
/// scopes.
- void forEachFreeVariable(f(Local variable, FieldEntity field)) {}
+ void forEachFreeVariable(
+ KernelToLocalsMap localsMap, f(Local variable, FieldEntity field)) {}
// TODO(efortuna): Remove this method. The old system was using
// ClosureClassMaps for situations other than closure class maps, and that's
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 6faa855..e921146 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -39,6 +39,7 @@
import 'js_backend/inferred_data.dart';
import 'js_model/js_strategy.dart';
import 'js_model/js_world.dart';
+import 'js_model/locals.dart';
import 'kernel/kernel_strategy.dart';
import 'kernel/loader.dart' show KernelLoaderTask, KernelResult;
import 'null_compiler_output.dart' show NullCompilerOutput;
@@ -401,10 +402,12 @@
JClosedWorld closedWorld) {
FunctionEntity mainFunction = closedWorld.elementEnvironment.mainFunction;
reporter.log('Performing global type inference');
+ GlobalLocalsMap globalLocalsMap =
+ new GlobalLocalsMap(closedWorld.closureDataLookup.getEnclosingMember);
InferredDataBuilder inferredDataBuilder =
new InferredDataBuilderImpl(closedWorld.annotationsData);
return globalInference.runGlobalTypeInference(
- mainFunction, closedWorld, inferredDataBuilder);
+ mainFunction, closedWorld, globalLocalsMap, inferredDataBuilder);
}
void runCodegenEnqueuer(CodegenResults codegenResults) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 691151c..882895c 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -271,7 +271,7 @@
List<String> inferredParameterTypes = <String>[];
closedWorld.elementEnvironment.forEachParameterAsLocal(
- closedWorld.globalLocalsMap, function, (parameter) {
+ _globalInferenceResults.globalLocalsMap, function, (parameter) {
inferredParameterTypes.add('${_resultOfParameter(parameter)}');
});
int parameterIndex = 0;
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 9793cc5..337c547 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -218,7 +218,7 @@
// each update, and reading them yields the type that was found in a
// previous analysis of [outermostElement].
ScopeInfo scopeInfo = _closureDataLookup.getScopeInfo(_analyzedMember);
- scopeInfo.forEachBoxedVariable((variable, field) {
+ scopeInfo.forEachBoxedVariable(_localsMap, (variable, field) {
_capturedAndBoxed[variable] = field;
});
@@ -1722,8 +1722,8 @@
// Record the types of captured non-boxed variables. Types of
// these variables may already be there, because of an analysis of
// a previous closure.
- info.forEachFreeVariable((Local variable, FieldEntity field) {
- if (!info.isBoxedVariable(variable)) {
+ info.forEachFreeVariable(_localsMap, (Local variable, FieldEntity field) {
+ if (!info.isBoxedVariable(_localsMap, variable)) {
if (variable == info.thisLocal) {
_inferrer.recordTypeOfField(field, thisType);
}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 129b30b..39c1a06 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -64,6 +64,7 @@
final TypeSystem types;
final Map<ir.TreeNode, TypeInformation> concreteTypes = {};
+ final GlobalLocalsMap globalLocalsMap;
final InferredDataBuilder inferredDataBuilder;
final FunctionEntity mainElement;
@@ -114,9 +115,10 @@
this._compilerOutput,
this.closedWorld,
this.mainElement,
+ this.globalLocalsMap,
this.inferredDataBuilder)
- : this.types = new TypeSystem(
- closedWorld, new KernelTypeSystemStrategy(closedWorld));
+ : this.types = new TypeSystem(closedWorld,
+ new KernelTypeSystemStrategy(closedWorld, globalLocalsMap));
/// Applies [f] to all elements in the universe that match [selector] and
/// [mask]. If [f] returns false, aborts the iteration.
@@ -634,7 +636,7 @@
this,
member,
body,
- closedWorld.globalLocalsMap.getLocalsMap(member),
+ globalLocalsMap.getLocalsMap(member),
closedWorld.elementMap.getStaticTypeProvider(member));
return visitor.run();
}
@@ -1224,8 +1226,9 @@
class KernelTypeSystemStrategy implements TypeSystemStrategy {
final JsClosedWorld _closedWorld;
+ final GlobalLocalsMap _globalLocalsMap;
- KernelTypeSystemStrategy(this._closedWorld);
+ KernelTypeSystemStrategy(this._closedWorld, this._globalLocalsMap);
JElementEnvironment get _elementEnvironment =>
_closedWorld.elementEnvironment;
@@ -1252,8 +1255,8 @@
@override
void forEachParameter(FunctionEntity function, void f(Local parameter)) {
forEachOrderedParameterAsLocal(
- _closedWorld.globalLocalsMap, _closedWorld.elementMap, function,
- (Local parameter, {bool isElided}) {
+ _globalLocalsMap, _closedWorld.elementMap, function, (Local parameter,
+ {bool isElided}) {
f(parameter);
});
}
@@ -1264,8 +1267,7 @@
covariant JLocal parameter,
TypeSystem types) {
MemberEntity context = parameter.memberContext;
- KernelToLocalsMap localsMap =
- _closedWorld.globalLocalsMap.getLocalsMap(context);
+ KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(context);
ir.FunctionNode functionNode =
localsMap.getFunctionNodeForParameter(parameter);
DartType type = localsMap.getLocalType(_closedWorld.elementMap, parameter);
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index d1e4239..f770d9b 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -13,6 +13,7 @@
import '../elements/entities.dart';
import '../js_backend/inferred_data.dart';
import '../js_model/elements.dart' show JClosureCallMethod;
+import '../js_model/locals.dart';
import '../world.dart';
import 'abstract_value_domain.dart';
import 'inferrer_engine.dart';
@@ -53,11 +54,12 @@
final JClosedWorld closedWorld;
final Compiler _compiler;
+ final GlobalLocalsMap _globalLocalsMap;
final InferredDataBuilder _inferredDataBuilder;
Metrics /*?*/ _metrics;
- TypeGraphInferrer(
- this._compiler, this.closedWorld, this._inferredDataBuilder);
+ TypeGraphInferrer(this._compiler, this.closedWorld, this._globalLocalsMap,
+ this._inferredDataBuilder);
String get name => 'Graph inferrer';
@@ -82,6 +84,7 @@
_compiler.outputProvider,
closedWorld,
main,
+ _globalLocalsMap,
_inferredDataBuilder);
}
@@ -134,7 +137,8 @@
if (member is JClosureCallMethod) {
ClosureRepresentationInfo info =
closedWorld.closureDataLookup.getScopeInfo(member);
- info.forEachFreeVariable((Local from, FieldEntity to) {
+ info.forEachFreeVariable(_globalLocalsMap.getLocalsMap(member),
+ (Local from, FieldEntity to) {
freeVariables.add(to);
});
}
@@ -167,6 +171,7 @@
GlobalTypeInferenceResults results = new GlobalTypeInferenceResultsImpl(
closedWorld,
+ _globalLocalsMap,
_inferredDataBuilder.close(closedWorld),
memberResults,
parameterResults,
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index 66d551c..2345d53 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -13,6 +13,8 @@
import '../elements/entities.dart';
import '../js_backend/inferred_data.dart';
import '../js_model/element_map.dart';
+import '../js_model/js_world.dart';
+import '../js_model/locals.dart';
import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
import '../serialization/serialization.dart';
import '../universe/selector.dart' show Selector;
@@ -111,13 +113,15 @@
DataSource source,
JsToElementMap elementMap,
JClosedWorld closedWorld,
+ GlobalLocalsMap globalLocalsMap,
InferredData inferredData) {
bool isTrivial = source.readBool();
if (isTrivial) {
- return new TrivialGlobalTypeInferenceResults(closedWorld);
+ return new TrivialGlobalTypeInferenceResults(
+ closedWorld, globalLocalsMap);
}
return new GlobalTypeInferenceResultsImpl.readFromDataSource(
- source, elementMap, closedWorld, inferredData);
+ source, elementMap, closedWorld, globalLocalsMap, inferredData);
}
/// Serializes this [GlobalTypeInferenceResults] to [sink].
@@ -125,6 +129,8 @@
JClosedWorld get closedWorld;
+ GlobalLocalsMap get globalLocalsMap;
+
InferredData get inferredData;
GlobalTypeInferenceMemberResult resultOfMember(MemberEntity member);
@@ -171,16 +177,20 @@
Metrics get metrics => _metrics;
/// Runs the global type-inference algorithm once.
- GlobalTypeInferenceResults runGlobalTypeInference(FunctionEntity mainElement,
- JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder) {
+ GlobalTypeInferenceResults runGlobalTypeInference(
+ FunctionEntity mainElement,
+ JClosedWorld closedWorld,
+ GlobalLocalsMap globalLocalsMap,
+ InferredDataBuilder inferredDataBuilder) {
return measure(() {
GlobalTypeInferenceResults results;
if (compiler.disableTypeInference) {
- results = new TrivialGlobalTypeInferenceResults(closedWorld);
+ results =
+ new TrivialGlobalTypeInferenceResults(closedWorld, globalLocalsMap);
_metrics = Metrics.none();
} else {
- typesInferrerInternal ??= compiler.backendStrategy
- .createTypesInferrer(closedWorld, inferredDataBuilder);
+ typesInferrerInternal ??= compiler.backendStrategy.createTypesInferrer(
+ closedWorld, globalLocalsMap, inferredDataBuilder);
results = typesInferrerInternal.analyzeMain(mainElement);
_metrics = typesInferrerInternal.metrics;
}
@@ -201,6 +211,8 @@
@override
final JClosedWorld closedWorld;
@override
+ final GlobalLocalsMap globalLocalsMap;
+ @override
final InferredData inferredData;
final GlobalTypeInferenceMemberResult _deadFieldResult;
final GlobalTypeInferenceMemberResult _deadMethodResult;
@@ -214,6 +226,7 @@
GlobalTypeInferenceResultsImpl(
this.closedWorld,
+ this.globalLocalsMap,
this.inferredData,
this.memberResults,
this.parameterResults,
@@ -230,7 +243,10 @@
DataSource source,
JsToElementMap elementMap,
JClosedWorld closedWorld,
+ GlobalLocalsMap globalLocalsMap,
InferredData inferredData) {
+ source.registerLocalLookup(new LocalLookupImpl(globalLocalsMap));
+
source.begin(tag);
Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults =
source.readMemberMap((MemberEntity member) =>
@@ -250,6 +266,7 @@
source.end(tag);
return new GlobalTypeInferenceResultsImpl(
closedWorld,
+ globalLocalsMap,
inferredData,
memberResults,
parameterResults,
@@ -472,8 +489,10 @@
final AbstractValue _trivialParameterResult;
@override
final InferredData inferredData = new TrivialInferredData();
+ @override
+ final GlobalLocalsMap globalLocalsMap;
- TrivialGlobalTypeInferenceResults(this.closedWorld)
+ TrivialGlobalTypeInferenceResults(this.closedWorld, this.globalLocalsMap)
: _trivialMemberResult = new TrivialGlobalTypeInferenceMemberResult(
closedWorld.abstractValueDomain.dynamicType),
_trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
diff --git a/pkg/compiler/lib/src/ir/closure.dart b/pkg/compiler/lib/src/ir/closure.dart
index 8d0c0c1..a9d5604 100644
--- a/pkg/compiler/lib/src/ir/closure.dart
+++ b/pkg/compiler/lib/src/ir/closure.dart
@@ -343,7 +343,7 @@
/// A fake ir.Node that holds the TypeParameterType as well as the context in
/// which it occurs.
class TypeVariableTypeWithContext implements ir.Node {
- final ir.Node context;
+ final ir.TreeNode context;
final ir.TypeParameterType type;
final TypeVariableKind kind;
final ir.TreeNode typeDeclaration;
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 570da8a..cfdee0b 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -21,7 +21,6 @@
import '../universe/selector.dart';
import 'elements.dart';
import 'js_world_builder.dart' show JsClosedWorldBuilder;
-import 'locals.dart';
class ClosureDataImpl implements ClosureData {
/// Tag used for identifying serialized [ClosureData] objects in a
@@ -40,8 +39,15 @@
final Map<ir.LocalFunction, ClosureRepresentationInfo>
_localClosureRepresentationMap;
- ClosureDataImpl(this._elementMap, this._scopeMap, this._capturedScopesMap,
- this._capturedScopeForSignatureMap, this._localClosureRepresentationMap);
+ final Map<MemberEntity, MemberEntity> _enclosingMembers;
+
+ ClosureDataImpl(
+ this._elementMap,
+ this._scopeMap,
+ this._capturedScopesMap,
+ this._capturedScopeForSignatureMap,
+ this._localClosureRepresentationMap,
+ this._enclosingMembers);
/// Deserializes a [ClosureData] object from [source].
factory ClosureDataImpl.readFromDataSource(
@@ -58,9 +64,16 @@
Map<ir.LocalFunction, ClosureRepresentationInfo>
localClosureRepresentationMap = source.readTreeNodeMap(
() => new ClosureRepresentationInfo.readFromDataSource(source));
+ Map<MemberEntity, MemberEntity> enclosingMembers =
+ source.readMemberMap((member) => source.readMember());
source.end(tag);
- return new ClosureDataImpl(elementMap, scopeMap, capturedScopesMap,
- capturedScopeForSignatureMap, localClosureRepresentationMap);
+ return new ClosureDataImpl(
+ elementMap,
+ scopeMap,
+ capturedScopesMap,
+ capturedScopeForSignatureMap,
+ localClosureRepresentationMap,
+ enclosingMembers);
}
/// Serializes this [ClosureData] to [sink].
@@ -80,6 +93,10 @@
(ClosureRepresentationInfo info) {
info.writeToDataSink(sink);
});
+ sink.writeMemberMap(_enclosingMembers,
+ (MemberEntity member, MemberEntity value) {
+ sink.writeMember(value);
+ });
sink.end(tag);
}
@@ -132,6 +149,11 @@
"Closures found for ${_localClosureRepresentationMap.keys}");
return closure;
}
+
+ @override
+ MemberEntity getEnclosingMember(MemberEntity member) {
+ return _enclosingMembers[member] ?? member;
+ }
}
/// Closure conversion code using our new Entity model. Closure conversion is
@@ -149,7 +171,6 @@
class ClosureDataBuilder {
final JsToElementMap _elementMap;
- final GlobalLocalsMap _globalLocalsMap;
final AnnotationsData _annotationsData;
/// Map of the scoping information that corresponds to a particular entity.
@@ -162,8 +183,9 @@
Map<ir.LocalFunction, ClosureRepresentationInfo>
_localClosureRepresentationMap = {};
- ClosureDataBuilder(
- this._elementMap, this._globalLocalsMap, this._annotationsData);
+ Map<MemberEntity, MemberEntity> _enclosingMembers = {};
+
+ ClosureDataBuilder(this._elementMap, this._annotationsData);
void _updateScopeBasedOnRtiNeed(KernelScopeInfo scope, ClosureRtiNeed rtiNeed,
MemberEntity outermostEntity) {
@@ -302,24 +324,23 @@
ClosureRtiNeed rtiNeed,
List<FunctionEntity> callMethods) {
closureModels.forEach((MemberEntity member, ClosureScopeModel model) {
- KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
- Map<Local, JRecordField> allBoxedVariables =
- _elementMap.makeRecordContainer(model.scopeInfo, member, localsMap);
+ Map<ir.VariableDeclaration, JRecordField> allBoxedVariables =
+ _elementMap.makeRecordContainer(model.scopeInfo, member);
_scopeMap[member] = new JsScopeInfo.from(
- allBoxedVariables, model.scopeInfo, localsMap, _elementMap);
+ allBoxedVariables, model.scopeInfo, member.enclosingClass);
model.capturedScopesMap
.forEach((ir.Node node, KernelCapturedScope scope) {
- Map<Local, JRecordField> boxedVariables =
- _elementMap.makeRecordContainer(scope, member, localsMap);
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables =
+ _elementMap.makeRecordContainer(scope, member);
_updateScopeBasedOnRtiNeed(scope, rtiNeed, member);
if (scope is KernelCapturedLoopScope) {
_capturedScopesMap[node] = new JsCapturedLoopScope.from(
- boxedVariables, scope, localsMap, _elementMap);
+ boxedVariables, scope, member.enclosingClass);
} else {
_capturedScopesMap[node] = new JsCapturedScope.from(
- boxedVariables, scope, localsMap, _elementMap);
+ boxedVariables, scope, member.enclosingClass);
}
allBoxedVariables.addAll(boxedVariables);
});
@@ -328,7 +349,7 @@
model.closuresToGenerate;
for (ir.LocalFunction node in closuresToGenerate.keys) {
ir.FunctionNode functionNode = node.function;
- KernelClosureClassInfo closureClassInfo = _produceSyntheticElements(
+ JsClosureClassInfo closureClassInfo = _produceSyntheticElements(
closedWorldBuilder,
member,
functionNode,
@@ -355,14 +376,19 @@
_updateScopeBasedOnRtiNeed(signatureCapturedScope, rtiNeed, member);
_capturedScopeForSignatureMap[closureClassInfo.signatureMethod] =
new JsCapturedScope.from(
- {}, signatureCapturedScope, localsMap, _elementMap);
+ {}, signatureCapturedScope, member.enclosingClass);
}
}
callMethods.add(closureClassInfo.callMethod);
}
});
- return new ClosureDataImpl(_elementMap, _scopeMap, _capturedScopesMap,
- _capturedScopeForSignatureMap, _localClosureRepresentationMap);
+ return new ClosureDataImpl(
+ _elementMap,
+ _scopeMap,
+ _capturedScopesMap,
+ _capturedScopeForSignatureMap,
+ _localClosureRepresentationMap,
+ _enclosingMembers);
}
/// Given what variables are captured at each point, construct closure classes
@@ -371,27 +397,24 @@
/// the closure accesses a variable that gets accessed at some point), then
/// boxForCapturedVariables stores the local context for those variables.
/// If no variables are captured, this parameter is null.
- KernelClosureClassInfo _produceSyntheticElements(
+ JsClosureClassInfo _produceSyntheticElements(
JsClosedWorldBuilder closedWorldBuilder,
MemberEntity member,
ir.FunctionNode node,
KernelScopeInfo info,
- Map<Local, JRecordField> boxedVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
ClosureRtiNeed rtiNeed,
{bool createSignatureMethod}) {
_updateScopeBasedOnRtiNeed(info, rtiNeed, member);
- KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
- KernelClosureClassInfo closureClassInfo =
- closedWorldBuilder.buildClosureClass(
- member, node, member.library, boxedVariables, info, localsMap,
- createSignatureMethod: createSignatureMethod);
+ JsClosureClassInfo closureClassInfo = closedWorldBuilder.buildClosureClass(
+ member, node, member.library, boxedVariables, info,
+ createSignatureMethod: createSignatureMethod);
// We want the original declaration where that function is used to point
// to the correct closure class.
- _globalLocalsMap.setLocalsMap(closureClassInfo.callMethod, localsMap);
+ _enclosingMembers[closureClassInfo.callMethod] = member;
if (closureClassInfo.signatureMethod != null) {
- _globalLocalsMap.setLocalsMap(
- closureClassInfo.signatureMethod, localsMap);
+ _enclosingMembers[closureClassInfo.signatureMethod] = member;
}
if (node.parent is ir.Member) {
assert(_elementMap.getMember(node.parent) == member);
@@ -403,98 +426,102 @@
}
}
-/// Helper method to get or create a Local variable out of a variable
-/// declaration or type parameter.
-Local _getLocal(
- ir.Node variable, KernelToLocalsMap localsMap, JsToElementMap elementMap) {
- assert(variable is ir.VariableDeclaration ||
- variable is TypeVariableTypeWithContext);
- if (variable is ir.VariableDeclaration) {
- return localsMap.getLocalVariable(variable);
- } else if (variable is TypeVariableTypeWithContext) {
- return localsMap.getLocalTypeVariable(variable.type, elementMap);
- }
- throw new ArgumentError('Only know how to get/create locals for '
- 'VariableDeclarations or TypeParameterTypeWithContext. Recieved '
- '${variable.runtimeType}');
-}
-
class JsScopeInfo extends ScopeInfo {
/// Tag used for identifying serialized [JsScopeInfo] objects in a
/// debugging data stream.
static const String tag = 'scope-info';
- final Iterable<Local> localsUsedInTryOrSync;
+ final Iterable<ir.VariableDeclaration> _localsUsedInTryOrSync;
+
+ Set<Local> _localsUsedInTryOrSyncCache;
+
@override
final Local thisLocal;
- final Map<Local, JRecordField> boxedVariables;
- /// The set of variables that were defined in another scope, but are used in
- /// this scope.
- final Set<Local> freeVariables;
+ final Map<ir.VariableDeclaration, JRecordField> _boxedVariables;
- JsScopeInfo.internal(this.localsUsedInTryOrSync, this.thisLocal,
- this.boxedVariables, this.freeVariables);
+ Map<Local, JRecordField> _boxedVariablesCache;
- JsScopeInfo.from(this.boxedVariables, KernelScopeInfo info,
- KernelToLocalsMap localsMap, JsToElementMap elementMap)
- : this.thisLocal = info.hasThisLocal
- ? new ThisLocal(localsMap.currentMember.enclosingClass)
- : null,
- this.localsUsedInTryOrSync =
- info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
- this.freeVariables = info.freeVariables
- .map((ir.Node node) => _getLocal(node, localsMap, elementMap))
- .toSet() {
- if (info.thisUsedAsFreeVariable) {
- this.freeVariables.add(this.thisLocal);
+ JsScopeInfo.internal(
+ this._localsUsedInTryOrSync, this.thisLocal, this._boxedVariables);
+
+ JsScopeInfo.from(
+ this._boxedVariables, KernelScopeInfo info, ClassEntity enclosingClass)
+ : this.thisLocal =
+ info.hasThisLocal ? new ThisLocal(enclosingClass) : null,
+ this._localsUsedInTryOrSync = info.localsUsedInTryOrSync;
+
+ void _ensureBoxedVariableCache(KernelToLocalsMap localsMap) {
+ if (_boxedVariablesCache == null) {
+ if (_boxedVariables.isEmpty) {
+ _boxedVariablesCache = const {};
+ } else {
+ _boxedVariablesCache = {};
+ _boxedVariables
+ .forEach((ir.VariableDeclaration node, JRecordField field) {
+ _boxedVariablesCache[localsMap.getLocalVariable(node)] = field;
+ });
+ }
}
}
@override
- void forEachBoxedVariable(f(Local local, FieldEntity field)) {
- boxedVariables.forEach((Local l, JRecordField box) {
- f(l, box);
- });
+ void forEachBoxedVariable(
+ KernelToLocalsMap localsMap, f(Local local, FieldEntity field)) {
+ _ensureBoxedVariableCache(localsMap);
+ _boxedVariablesCache.forEach(f);
}
@override
- bool localIsUsedInTryOrSync(Local variable) =>
- localsUsedInTryOrSync.contains(variable);
+ bool localIsUsedInTryOrSync(KernelToLocalsMap localsMap, Local variable) {
+ if (_localsUsedInTryOrSyncCache == null) {
+ if (_localsUsedInTryOrSync.isEmpty) {
+ _localsUsedInTryOrSyncCache = const {};
+ } else {
+ _localsUsedInTryOrSyncCache = {};
+ for (ir.VariableDeclaration node in _localsUsedInTryOrSync) {
+ _localsUsedInTryOrSyncCache.add(localsMap.getLocalVariable(node));
+ }
+ }
+ }
+ return _localsUsedInTryOrSyncCache.contains(variable);
+ }
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('this=$thisLocal,');
- sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
+ sb.write('localsUsedInTryOrSync={${_localsUsedInTryOrSync.join(', ')}}');
return sb.toString();
}
@override
- bool isBoxedVariable(Local variable) => boxedVariables.containsKey(variable);
+ bool isBoxedVariable(KernelToLocalsMap localsMap, Local variable) {
+ _ensureBoxedVariableCache(localsMap);
+ return _boxedVariablesCache.containsKey(variable);
+ }
factory JsScopeInfo.readFromDataSource(DataSource source) {
source.begin(tag);
- Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
+ source.readTreeNodes<ir.VariableDeclaration>();
Local thisLocal = source.readLocalOrNull();
- Map<Local, JRecordField> boxedVariables =
- source.readLocalMap<Local, JRecordField>(() => source.readMember());
- Set<Local> freeVariables = source.readLocals().toSet();
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables =
+ source.readTreeNodeMap<ir.VariableDeclaration, JRecordField>(
+ () => source.readMember());
source.end(tag);
if (boxedVariables.isEmpty) boxedVariables = const {};
- if (freeVariables.isEmpty) freeVariables = const {};
return JsScopeInfo.internal(
- localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
+ localsUsedInTryOrSync, thisLocal, boxedVariables);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.scopeInfo);
sink.begin(tag);
- sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeTreeNodes(_localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
- sink.writeLocalMap(boxedVariables, sink.writeMember);
- sink.writeLocals(freeVariables);
+ sink.writeTreeNodeMap(_boxedVariables, sink.writeMember);
sink.end(tag);
}
}
@@ -505,51 +532,46 @@
static const String tag = 'captured-scope';
@override
- final Local context;
+ final Local contextBox;
JsCapturedScope.internal(
- Iterable<Local> localsUsedInTryOrSync,
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync,
Local thisLocal,
- Map<Local, JRecordField> boxedVariables,
- Set<Local> freeVariables,
- this.context)
- : super.internal(
- localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
+ this.contextBox)
+ : super.internal(localsUsedInTryOrSync, thisLocal, boxedVariables);
- JsCapturedScope.from(
- Map<Local, JRecordField> boxedVariables,
- KernelCapturedScope capturedScope,
- KernelToLocalsMap localsMap,
- JsToElementMap elementMap)
- : this.context =
+ JsCapturedScope.from(Map<ir.VariableDeclaration, JRecordField> boxedVariables,
+ KernelCapturedScope capturedScope, ClassEntity enclosingClass)
+ : this.contextBox =
boxedVariables.isNotEmpty ? boxedVariables.values.first.box : null,
- super.from(boxedVariables, capturedScope, localsMap, elementMap);
+ super.from(boxedVariables, capturedScope, enclosingClass);
@override
- bool get requiresContextBox => boxedVariables.isNotEmpty;
+ bool get requiresContextBox => _boxedVariables.isNotEmpty;
factory JsCapturedScope.readFromDataSource(DataSource source) {
source.begin(tag);
- Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
+ source.readTreeNodes<ir.VariableDeclaration>();
Local thisLocal = source.readLocalOrNull();
- Map<Local, JRecordField> boxedVariables =
- source.readLocalMap<Local, JRecordField>(() => source.readMember());
- Set<Local> freeVariables = source.readLocals().toSet();
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables =
+ source.readTreeNodeMap<ir.VariableDeclaration, JRecordField>(
+ () => source.readMember());
Local context = source.readLocalOrNull();
source.end(tag);
- return new JsCapturedScope.internal(localsUsedInTryOrSync, thisLocal,
- boxedVariables, freeVariables, context);
+ return new JsCapturedScope.internal(
+ localsUsedInTryOrSync, thisLocal, boxedVariables, context);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.capturedScope);
sink.begin(tag);
- sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeTreeNodes(_localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
- sink.writeLocalMap(boxedVariables, sink.writeMember);
- sink.writeLocals(freeVariables);
- sink.writeLocalOrNull(context);
+ sink.writeTreeNodeMap(_boxedVariables, sink.writeMember);
+ sink.writeLocalOrNull(contextBox);
sink.end(tag);
}
}
@@ -559,65 +581,69 @@
/// debugging data stream.
static const String tag = 'captured-loop-scope';
- @override
- final List<Local> boxedLoopVariables;
+ final List<ir.VariableDeclaration> _boxedLoopVariables;
JsCapturedLoopScope.internal(
- Iterable<Local> localsUsedInTryOrSync,
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync,
Local thisLocal,
- Map<Local, JRecordField> boxedVariables,
- Set<Local> freeVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
Local context,
- this.boxedLoopVariables)
- : super.internal(localsUsedInTryOrSync, thisLocal, boxedVariables,
- freeVariables, context);
+ this._boxedLoopVariables)
+ : super.internal(
+ localsUsedInTryOrSync, thisLocal, boxedVariables, context);
JsCapturedLoopScope.from(
- Map<Local, JRecordField> boxedVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
KernelCapturedLoopScope capturedScope,
- KernelToLocalsMap localsMap,
- JsToElementMap elementMap)
- : this.boxedLoopVariables = capturedScope.boxedLoopVariables
- .map(localsMap.getLocalVariable)
- .toList(),
- super.from(boxedVariables, capturedScope, localsMap, elementMap);
+ ClassEntity enclosingClass)
+ : this._boxedLoopVariables = capturedScope.boxedLoopVariables,
+ super.from(boxedVariables, capturedScope, enclosingClass);
@override
- bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
+ bool get hasBoxedLoopVariables => _boxedLoopVariables.isNotEmpty;
factory JsCapturedLoopScope.readFromDataSource(DataSource source) {
source.begin(tag);
- Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
+ source.readTreeNodes<ir.VariableDeclaration>();
Local thisLocal = source.readLocalOrNull();
- Map<Local, JRecordField> boxedVariables =
- source.readLocalMap<Local, JRecordField>(() => source.readMember());
- Set<Local> freeVariables = source.readLocals().toSet();
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables =
+ source.readTreeNodeMap<ir.VariableDeclaration, JRecordField>(
+ () => source.readMember());
Local context = source.readLocalOrNull();
- List<Local> boxedLoopVariables = source.readLocals();
+ List<ir.VariableDeclaration> boxedLoopVariables =
+ source.readTreeNodes<ir.VariableDeclaration>();
source.end(tag);
return new JsCapturedLoopScope.internal(localsUsedInTryOrSync, thisLocal,
- boxedVariables, freeVariables, context, boxedLoopVariables);
+ boxedVariables, context, boxedLoopVariables);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.capturedLoopScope);
sink.begin(tag);
- sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeTreeNodes(_localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
- sink.writeLocalMap(boxedVariables, sink.writeMember);
- sink.writeLocals(freeVariables);
- sink.writeLocalOrNull(context);
- sink.writeLocals(boxedLoopVariables);
+ sink.writeTreeNodeMap(_boxedVariables, sink.writeMember);
+ sink.writeLocalOrNull(contextBox);
+ sink.writeTreeNodes(_boxedLoopVariables);
sink.end(tag);
}
+
+ @override
+ List<Local> getBoxedLoopVariables(KernelToLocalsMap localsMap) {
+ List<Local> locals = [];
+ for (ir.VariableDeclaration boxedLoopVariable in _boxedLoopVariables) {
+ locals.add(localsMap.getLocalVariable(boxedLoopVariable));
+ }
+ return locals;
+ }
}
-// TODO(johnniwinther): Rename this class.
// TODO(johnniwinther): Add unittest for the computed [ClosureClass].
-class KernelClosureClassInfo extends JsScopeInfo
+class JsClosureClassInfo extends JsScopeInfo
implements ClosureRepresentationInfo {
- /// Tag used for identifying serialized [KernelClosureClassInfo] objects in a
+ /// Tag used for identifying serialized [JsClosureClassInfo] objects in a
/// debugging data stream.
static const String tag = 'closure-representation-info';
@@ -625,110 +651,194 @@
JFunction callMethod;
@override
JSignatureMethod signatureMethod;
- @override
- final Local closureEntity;
+
+ /// The local used for this closure, if it is an anonymous closure, i.e.
+ /// an `ir.FunctionExpression`.
+ final Local _closureEntity;
+
+ /// The local variable that defines this closure, if it is a local function
+ /// declaration.
+ final ir.VariableDeclaration _closureEntityVariable;
+
@override
final Local thisLocal;
+
@override
final JClass closureClassEntity;
- final Map<Local, JField> localToFieldMap;
+ final Map<ir.VariableDeclaration, JField> _variableToFieldMap;
+ final Map<JTypeVariable, JField> _typeVariableToFieldMap;
+ final Map<Local, JField> _localToFieldMap;
+ Map<JField, Local> _fieldToLocalsMap;
- KernelClosureClassInfo.internal(
- Iterable<Local> localsUsedInTryOrSync,
+ JsClosureClassInfo.internal(
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync,
this.thisLocal,
- Map<Local, JRecordField> boxedVariables,
- Set<Local> freeVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
this.callMethod,
this.signatureMethod,
- this.closureEntity,
+ this._closureEntity,
+ this._closureEntityVariable,
this.closureClassEntity,
- this.localToFieldMap)
- : super.internal(
- localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
+ this._variableToFieldMap,
+ this._typeVariableToFieldMap,
+ this._localToFieldMap)
+ : super.internal(localsUsedInTryOrSync, thisLocal, boxedVariables);
- KernelClosureClassInfo.fromScopeInfo(
+ JsClosureClassInfo.fromScopeInfo(
this.closureClassEntity,
ir.FunctionNode closureSourceNode,
- Map<Local, JRecordField> boxedVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
KernelScopeInfo info,
- KernelToLocalsMap localsMap,
- this.closureEntity,
- this.thisLocal,
- JsToElementMap elementMap)
- : localToFieldMap = new Map<Local, JField>(),
- super.from(boxedVariables, info, localsMap, elementMap);
+ ClassEntity enclosingClass,
+ this._closureEntity,
+ this._closureEntityVariable,
+ this.thisLocal)
+ : _variableToFieldMap = {},
+ _typeVariableToFieldMap = {},
+ _localToFieldMap = {},
+ super.from(boxedVariables, info, enclosingClass);
- factory KernelClosureClassInfo.readFromDataSource(DataSource source) {
+ factory JsClosureClassInfo.readFromDataSource(DataSource source) {
source.begin(tag);
- Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Iterable<ir.VariableDeclaration> localsUsedInTryOrSync =
+ source.readTreeNodes<ir.VariableDeclaration>();
Local thisLocal = source.readLocalOrNull();
- Map<Local, JRecordField> boxedVariables =
- source.readLocalMap<Local, JRecordField>(() => source.readMember());
- Set<Local> freeVariables = source.readLocals().toSet();
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables =
+ source.readTreeNodeMap<ir.VariableDeclaration, JRecordField>(
+ () => source.readMember());
JFunction callMethod = source.readMember();
JSignatureMethod signatureMethod = source.readMemberOrNull();
Local closureEntity = source.readLocalOrNull();
+ ir.VariableDeclaration closureEntityVariable = source.readTreeNodeOrNull();
JClass closureClassEntity = source.readClass();
- Map<Local, JField> localToFieldMap =
+ Map<ir.VariableDeclaration, JField> localToFieldMap =
+ source.readTreeNodeMap<ir.VariableDeclaration, JField>(
+ () => source.readMember());
+ Map<JTypeVariable, JField> typeVariableToFieldMap = source
+ .readTypeVariableMap<JTypeVariable, JField>(() => source.readMember());
+ Map<Local, JField> thisLocalToFieldMap =
source.readLocalMap(() => source.readMember());
source.end(tag);
if (boxedVariables.isEmpty) boxedVariables = const {};
- if (freeVariables.isEmpty) freeVariables = const {};
if (localToFieldMap.isEmpty) localToFieldMap = const {};
- return KernelClosureClassInfo.internal(
+ return JsClosureClassInfo.internal(
localsUsedInTryOrSync,
thisLocal,
boxedVariables,
- freeVariables,
callMethod,
signatureMethod,
closureEntity,
+ closureEntityVariable,
closureClassEntity,
- localToFieldMap);
+ localToFieldMap,
+ typeVariableToFieldMap,
+ thisLocalToFieldMap);
}
@override
void writeToDataSink(DataSink sink) {
sink.writeEnum(ScopeInfoKind.closureRepresentationInfo);
sink.begin(tag);
- sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeTreeNodes(_localsUsedInTryOrSync);
sink.writeLocalOrNull(thisLocal);
- sink.writeLocalMap(boxedVariables, sink.writeMember);
- sink.writeLocals(freeVariables);
+ sink.writeTreeNodeMap(_boxedVariables, sink.writeMember);
sink.writeMember(callMethod);
sink.writeMemberOrNull(signatureMethod);
- sink.writeLocalOrNull(closureEntity);
+ sink.writeLocalOrNull(_closureEntity);
+ sink.writeTreeNodeOrNull(_closureEntityVariable);
sink.writeClass(closureClassEntity);
- sink.writeLocalMap(localToFieldMap, sink.writeMember);
+ sink.writeTreeNodeMap(_variableToFieldMap, sink.writeMember);
+ sink.writeTypeVariableMap(_typeVariableToFieldMap, sink.writeMember);
+ sink.writeLocalMap(_localToFieldMap, sink.writeMember);
sink.end(tag);
}
- @override
- List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
+ bool hasFieldForLocal(Local local) => _localToFieldMap.containsKey(local);
- @override
- Local getLocalForField(FieldEntity field) {
- for (Local local in localToFieldMap.keys) {
- if (localToFieldMap[local] == field) {
- return local;
+ void registerFieldForLocal(Local local, JField field) {
+ assert(_fieldToLocalsMap == null);
+ _localToFieldMap[local] = field;
+ }
+
+ void registerFieldForVariable(ir.VariableDeclaration node, JField field) {
+ assert(_fieldToLocalsMap == null);
+ _variableToFieldMap[node] = field;
+ }
+
+ bool hasFieldForTypeVariable(JTypeVariable typeVariable) =>
+ _typeVariableToFieldMap.containsKey(typeVariable);
+
+ void registerFieldForTypeVariable(JTypeVariable typeVariable, JField field) {
+ assert(_fieldToLocalsMap == null);
+ _typeVariableToFieldMap[typeVariable] = field;
+ }
+
+ void registerFieldForBoxedVariable(
+ ir.VariableDeclaration node, JField field) {
+ assert(_boxedVariablesCache == null);
+ _boxedVariables[node] = field;
+ }
+
+ void _ensureFieldToLocalsMap(KernelToLocalsMap localsMap) {
+ if (_fieldToLocalsMap == null) {
+ _fieldToLocalsMap = {};
+ _variableToFieldMap.forEach((ir.VariableDeclaration node, JField field) {
+ _fieldToLocalsMap[field] = localsMap.getLocalVariable(node);
+ });
+ _typeVariableToFieldMap
+ .forEach((TypeVariableEntity typeVariable, JField field) {
+ _fieldToLocalsMap[field] =
+ localsMap.getLocalTypeVariableEntity(typeVariable);
+ });
+ _localToFieldMap.forEach((Local local, JField field) {
+ _fieldToLocalsMap[field] = local;
+ });
+ if (_fieldToLocalsMap.isEmpty) {
+ _fieldToLocalsMap = const {};
}
}
- failedAt(field, "No local for $field. Options: $localToFieldMap");
- return null;
}
@override
- FieldEntity get thisFieldEntity => localToFieldMap[thisLocal];
+ List<Local> getCreatedFieldEntities(KernelToLocalsMap localsMap) {
+ _ensureFieldToLocalsMap(localsMap);
+ return _fieldToLocalsMap.values.toList();
+ }
@override
- void forEachFreeVariable(f(Local variable, JField field)) {
- localToFieldMap.forEach(f);
- boxedVariables.forEach(f);
+ Local getLocalForField(KernelToLocalsMap localsMap, FieldEntity field) {
+ _ensureFieldToLocalsMap(localsMap);
+ Local local = _fieldToLocalsMap[field];
+ if (local == null) {
+ failedAt(field, "No local for $field. Options: $_fieldToLocalsMap");
+ }
+ return local;
+ }
+
+ @override
+ FieldEntity get thisFieldEntity => _localToFieldMap[thisLocal];
+
+ @override
+ void forEachFreeVariable(
+ KernelToLocalsMap localsMap, f(Local variable, JField field)) {
+ _ensureFieldToLocalsMap(localsMap);
+ _ensureBoxedVariableCache(localsMap);
+ _fieldToLocalsMap.forEach((JField field, Local local) {
+ f(local, field);
+ });
+ _boxedVariablesCache.forEach(f);
}
@override
bool get isClosure => true;
+
+ @override
+ Local getClosureEntity(KernelToLocalsMap localsMap) {
+ return _closureEntityVariable != null
+ ? localsMap.getLocalVariable(_closureEntityVariable)
+ : _closureEntity;
+ }
}
class JClosureClass extends JClass {
@@ -795,7 +905,7 @@
final String declaredName;
JClosureField(
- String name, KernelClosureClassInfo containingClass, String declaredName,
+ String name, JsClosureClassInfo containingClass, String declaredName,
{bool isConst, bool isAssignable})
: this.internal(
containingClass.closureClassEntity.library,
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 622ee68..4d6febd 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -150,8 +150,8 @@
/// Make a record to ensure variables that are are declared in one scope and
/// modified in another get their values updated correctly.
- Map<Local, JRecordField> makeRecordContainer(
- KernelScopeInfo info, MemberEntity member, KernelToLocalsMap localsMap);
+ Map<ir.VariableDeclaration, JRecordField> makeRecordContainer(
+ KernelScopeInfo info, MemberEntity member);
/// Returns a provider for static types for [member].
StaticTypeProvider getStaticTypeProvider(MemberEntity member);
@@ -217,8 +217,8 @@
/// Returns the [Local] for [node].
Local getLocalVariable(ir.VariableDeclaration node);
- Local getLocalTypeVariable(
- ir.TypeParameterType node, JsToElementMap elementMap);
+ /// Returns the [Local] for the [typeVariable].
+ Local getLocalTypeVariableEntity(TypeVariableEntity typeVariable);
/// Returns the [ir.FunctionNode] that declared [parameter].
ir.FunctionNode getFunctionNodeForParameter(Local parameter);
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index ec6d67f..1f4cd96 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -1725,11 +1725,9 @@
InterfaceType memberThisType,
ir.VariableDeclaration variable,
BoxLocal boxLocal,
- Map<String, MemberEntity> memberMap,
- KernelToLocalsMap localsMap) {
- Local local = localsMap.getLocalVariable(variable);
+ Map<String, MemberEntity> memberMap) {
JRecordField boxedField =
- new JRecordField(local.name, boxLocal, isConst: variable.isConst);
+ new JRecordField(variable.name, boxLocal, isConst: variable.isConst);
members.register(
boxedField,
new ClosureFieldData(
@@ -1745,9 +1743,9 @@
/// are accessed in different scopes. This function creates the container
/// and returns a map of locals to the corresponding records created.
@override
- Map<Local, JRecordField> makeRecordContainer(
- KernelScopeInfo info, MemberEntity member, KernelToLocalsMap localsMap) {
- Map<Local, JRecordField> boxedFields = {};
+ Map<ir.VariableDeclaration, JRecordField> makeRecordContainer(
+ KernelScopeInfo info, MemberEntity member) {
+ Map<ir.VariableDeclaration, JRecordField> boxedFields = {};
if (info.boxedVariables.isNotEmpty) {
NodeBox box = info.capturedVariablesAccessor;
@@ -1768,18 +1766,13 @@
? elementEnvironment.getThisType(member.enclosingClass)
: null;
for (ir.VariableDeclaration variable in info.boxedVariables) {
- boxedFields[localsMap.getLocalVariable(variable)] =
- _constructRecordFieldEntry(
- memberThisType, variable, boxLocal, memberMap, localsMap);
+ boxedFields[variable] = _constructRecordFieldEntry(
+ memberThisType, variable, boxLocal, memberMap);
}
}
return boxedFields;
}
- bool _isInRecord(
- Local local, Map<Local, JRecordField> recordFieldsVisibleInScope) =>
- recordFieldsVisibleInScope.containsKey(local);
-
ParameterStructure _getParameterStructureFromFunctionNode(
ir.FunctionNode node) {
int requiredPositionalParameters = node.requiredParameterCount;
@@ -1802,13 +1795,12 @@
typeParameters);
}
- KernelClosureClassInfo constructClosureClass(
+ JsClosureClassInfo constructClosureClass(
MemberEntity member,
ir.FunctionNode node,
JLibrary enclosingLibrary,
- Map<Local, JRecordField> recordFieldsVisibleInScope,
+ Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
KernelScopeInfo info,
- KernelToLocalsMap localsMap,
InterfaceType supertype,
{bool createSignatureMethod}) {
InterfaceType memberThisType = member.enclosingClass != null
@@ -1839,9 +1831,10 @@
classes.register(classEntity, closureData, new ClosureClassEnv(memberMap));
Local closureEntity;
+ ir.VariableDeclaration closureEntityNode;
if (node.parent is ir.FunctionDeclaration) {
ir.FunctionDeclaration parent = node.parent;
- closureEntity = localsMap.getLocalVariable(parent.variable);
+ closureEntityNode = parent.variable;
} else if (node.parent is ir.FunctionExpression) {
closureEntity = new AnonymousClosureLocal(classEntity);
}
@@ -1862,20 +1855,17 @@
index++;
}
- KernelClosureClassInfo closureClassInfo =
- new KernelClosureClassInfo.fromScopeInfo(
- classEntity,
- node,
- <Local, JRecordField>{},
- info,
- localsMap,
- closureEntity,
- info.hasThisLocal
- ? new ThisLocal(localsMap.currentMember.enclosingClass)
- : null,
- this);
+ JsClosureClassInfo closureClassInfo = new JsClosureClassInfo.fromScopeInfo(
+ classEntity,
+ node,
+ <ir.VariableDeclaration, JRecordField>{},
+ info,
+ member.enclosingClass,
+ closureEntity,
+ closureEntityNode,
+ info.hasThisLocal ? new ThisLocal(member.enclosingClass) : null);
_buildClosureClassFields(closureClassInfo, member, memberThisType, info,
- localsMap, recordFieldsVisibleInScope, memberMap);
+ recordFieldsVisibleInScope, memberMap);
if (createSignatureMethod) {
_constructSignatureMethod(closureClassInfo, memberMap, node,
@@ -1898,12 +1888,11 @@
}
void _buildClosureClassFields(
- KernelClosureClassInfo closureClassInfo,
+ JsClosureClassInfo closureClassInfo,
MemberEntity member,
InterfaceType memberThisType,
KernelScopeInfo info,
- KernelToLocalsMap localsMap,
- Map<Local, JRecordField> recordFieldsVisibleInScope,
+ Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
Map<String, MemberEntity> memberMap) {
// TODO(efortuna): Limit field number usage to when we need to distinguish
// between two variables with the same name from different scopes.
@@ -1917,10 +1906,9 @@
for (ir.Node variable in info.freeVariables) {
if (variable is ir.VariableDeclaration) {
- Local capturedLocal = localsMap.getLocalVariable(variable);
- if (_isInRecord(capturedLocal, recordFieldsVisibleInScope)) {
+ if (recordFieldsVisibleInScope.containsKey(variable)) {
bool constructedField = _constructClosureFieldForRecord(
- capturedLocal,
+ variable,
closureClassInfo,
memberThisType,
memberMap,
@@ -1934,15 +1922,17 @@
// Add a field for the captured 'this'.
if (info.thisUsedAsFreeVariable) {
- _constructClosureField(
+ closureClassInfo.registerFieldForLocal(
closureClassInfo.thisLocal,
- closureClassInfo,
- memberThisType,
- memberMap,
- getClassDefinition(member.enclosingClass).node,
- true,
- false,
- fieldNumber);
+ _constructClosureField(
+ closureClassInfo.thisLocal.name,
+ closureClassInfo,
+ memberThisType,
+ memberMap,
+ getClassDefinition(member.enclosingClass).node,
+ true,
+ false,
+ fieldNumber));
fieldNumber++;
}
@@ -1950,29 +1940,40 @@
// Make a corresponding field entity in this closure class for the
// free variables in the KernelScopeInfo.freeVariable.
if (variable is ir.VariableDeclaration) {
- Local capturedLocal = localsMap.getLocalVariable(variable);
- if (!_isInRecord(capturedLocal, recordFieldsVisibleInScope)) {
- _constructClosureField(
- capturedLocal,
- closureClassInfo,
- memberThisType,
- memberMap,
+ if (!recordFieldsVisibleInScope.containsKey(variable)) {
+ closureClassInfo.registerFieldForVariable(
variable,
- variable.isConst,
- false, // Closure field is never assigned (only box fields).
- fieldNumber);
+ _constructClosureField(
+ variable.name,
+ closureClassInfo,
+ memberThisType,
+ memberMap,
+ variable,
+ variable.isConst,
+ false, // Closure field is never assigned (only box fields).
+ fieldNumber));
fieldNumber++;
}
} else if (variable is TypeVariableTypeWithContext) {
- Local capturedLocal =
- localsMap.getLocalTypeVariable(variable.type, this);
+ TypeVariableEntity typeVariable =
+ getTypeVariable(variable.type.parameter);
// We can have distinct TypeVariableTypeWithContexts that have the same
// local variable but with different nullabilities. We only want to
// construct a closure field once for each local variable.
- if (closureClassInfo.localToFieldMap.containsKey(capturedLocal))
+ if (closureClassInfo.hasFieldForTypeVariable(typeVariable)) {
continue;
- _constructClosureField(capturedLocal, closureClassInfo, memberThisType,
- memberMap, variable.type.parameter, true, false, fieldNumber);
+ }
+ closureClassInfo.registerFieldForTypeVariable(
+ typeVariable,
+ _constructClosureField(
+ variable.type.parameter.name,
+ closureClassInfo,
+ memberThisType,
+ memberMap,
+ variable.type.parameter,
+ true,
+ false,
+ fieldNumber));
fieldNumber++;
} else {
throw new UnsupportedError("Unexpected field node type: $variable");
@@ -1988,19 +1989,20 @@
/// locals they contain may be). Returns `true` if we constructed a new field
/// in the closure class.
bool _constructClosureFieldForRecord(
- Local capturedLocal,
- KernelClosureClassInfo closureClassInfo,
+ ir.VariableDeclaration capturedLocal,
+ JsClosureClassInfo closureClassInfo,
InterfaceType memberThisType,
Map<String, MemberEntity> memberMap,
ir.TreeNode sourceNode,
- Map<Local, JRecordField> recordFieldsVisibleInScope,
+ Map<ir.VariableDeclaration, JRecordField> recordFieldsVisibleInScope,
int fieldNumber) {
JRecordField recordField = recordFieldsVisibleInScope[capturedLocal];
// Don't construct a new field if the box that holds this local already has
// a field in the closure class.
- if (closureClassInfo.localToFieldMap.containsKey(recordField.box)) {
- closureClassInfo.boxedVariables[capturedLocal] = recordField;
+ if (closureClassInfo.hasFieldForLocal(recordField.box)) {
+ closureClassInfo.registerFieldForBoxedVariable(
+ capturedLocal, recordField);
return false;
}
@@ -2017,13 +2019,13 @@
sourceNode),
memberThisType));
memberMap[closureField.name] = closureField;
- closureClassInfo.localToFieldMap[recordField.box] = closureField;
- closureClassInfo.boxedVariables[capturedLocal] = recordField;
+ closureClassInfo.registerFieldForLocal(recordField.box, closureField);
+ closureClassInfo.registerFieldForBoxedVariable(capturedLocal, recordField);
return true;
}
void _constructSignatureMethod(
- KernelClosureClassInfo closureClassInfo,
+ JsClosureClassInfo closureClassInfo,
Map<String, MemberEntity> memberMap,
ir.FunctionNode closureSourceNode,
InterfaceType memberThisType,
@@ -2043,21 +2045,18 @@
closureClassInfo.signatureMethod = signatureMethod;
}
- void _constructClosureField(
- Local capturedLocal,
- KernelClosureClassInfo closureClassInfo,
+ JField _constructClosureField(
+ String name,
+ JsClosureClassInfo closureClassInfo,
InterfaceType memberThisType,
Map<String, MemberEntity> memberMap,
ir.TreeNode sourceNode,
bool isConst,
bool isAssignable,
int fieldNumber) {
- FieldEntity closureField = new JClosureField(
- _getClosureVariableName(capturedLocal.name, fieldNumber),
- closureClassInfo,
- capturedLocal.name,
- isConst: isConst,
- isAssignable: isAssignable);
+ JField closureField = new JClosureField(
+ _getClosureVariableName(name, fieldNumber), closureClassInfo, name,
+ isConst: isConst, isAssignable: isAssignable);
members.register<IndexedField, JFieldData>(
closureField,
@@ -2068,7 +2067,7 @@
sourceNode),
memberThisType));
memberMap[closureField.name] = closureField;
- closureClassInfo.localToFieldMap[capturedLocal] = closureField;
+ return closureField;
}
// Returns a non-unique name for the given closure element.
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index bb9ed2b..d432e33 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -169,12 +169,10 @@
strategy.elementMap,
closedWorld.liveMemberUsage,
closedWorld.annotationsData);
- GlobalLocalsMap _globalLocalsMap = new GlobalLocalsMap();
- ClosureDataBuilder closureDataBuilder = new ClosureDataBuilder(
- _elementMap, _globalLocalsMap, closedWorld.annotationsData);
+ ClosureDataBuilder closureDataBuilder =
+ new ClosureDataBuilder(_elementMap, closedWorld.annotationsData);
JsClosedWorldBuilder closedWorldBuilder = new JsClosedWorldBuilder(
_elementMap,
- _globalLocalsMap,
closureDataBuilder,
_compiler.options,
_compiler.abstractValueStrategy);
@@ -383,8 +381,11 @@
@override
TypesInferrer createTypesInferrer(
- JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder) {
- return new TypeGraphInferrer(_compiler, closedWorld, inferredDataBuilder);
+ JClosedWorld closedWorld,
+ GlobalLocalsMap globalLocalsMap,
+ InferredDataBuilder inferredDataBuilder) {
+ return new TypeGraphInferrer(
+ _compiler, closedWorld, globalLocalsMap, inferredDataBuilder);
}
@override
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 2b5263a..868ef6f 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -90,8 +90,6 @@
@override
final AnnotationsData annotationsData;
@override
- final GlobalLocalsMap globalLocalsMap;
- @override
final ClosureData closureDataLookup;
@override
final OutputUnitData outputUnitData;
@@ -118,7 +116,6 @@
this.classHierarchy,
AbstractValueStrategy abstractValueStrategy,
this.annotationsData,
- this.globalLocalsMap,
this.closureDataLookup,
this.outputUnitData,
this.memberAccess) {
@@ -138,9 +135,6 @@
JsKernelToElementMap elementMap =
new JsKernelToElementMap.readFromDataSource(
options, reporter, environment, component, source);
- GlobalLocalsMap globalLocalsMap =
- new GlobalLocalsMap.readFromDataSource(source);
- source.registerLocalLookup(new LocalLookupImpl(globalLocalsMap));
ClassHierarchy classHierarchy = new ClassHierarchy.readFromDataSource(
source, elementMap.commonElements);
NativeData nativeData = new NativeData.readFromDataSource(
@@ -203,7 +197,6 @@
classHierarchy,
abstractValueStrategy,
annotationsData,
- globalLocalsMap,
closureData,
outputUnitData,
memberAccess);
@@ -213,8 +206,6 @@
void writeToDataSink(DataSink sink) {
sink.begin(tag);
elementMap.writeToDataSink(sink);
- globalLocalsMap.writeToDataSink(sink);
-
classHierarchy.writeToDataSink(sink);
nativeData.writeToDataSink(sink);
interceptorData.writeToDataSink(sink);
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index 07086db..f2fdbe6 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -34,23 +34,20 @@
import '../world.dart';
import 'closure.dart';
import 'elements.dart';
-import 'element_map.dart';
import 'element_map_impl.dart';
import 'js_world.dart';
-import 'locals.dart';
class JsClosedWorldBuilder {
final JsKernelToElementMap _elementMap;
final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes =
new ClassHierarchyNodesMap();
final Map<ClassEntity, ClassSet> _classSets = <ClassEntity, ClassSet>{};
- final GlobalLocalsMap _globalLocalsMap;
final ClosureDataBuilder _closureDataBuilder;
final CompilerOptions _options;
final AbstractValueStrategy _abstractValueStrategy;
- JsClosedWorldBuilder(this._elementMap, this._globalLocalsMap,
- this._closureDataBuilder, this._options, this._abstractValueStrategy);
+ JsClosedWorldBuilder(this._elementMap, this._closureDataBuilder,
+ this._options, this._abstractValueStrategy);
ElementEnvironment get _elementEnvironment => _elementMap.elementEnvironment;
CommonElements get _commonElements => _elementMap.commonElements;
@@ -236,7 +233,6 @@
_elementMap.commonElements, _classHierarchyNodes, _classSets),
_abstractValueStrategy,
annotationsData,
- _globalLocalsMap,
closureData,
outputUnitData,
memberAccess);
@@ -414,23 +410,21 @@
/// Construct a closure class and set up the necessary class inference
/// hierarchy.
- KernelClosureClassInfo buildClosureClass(
+ JsClosureClassInfo buildClosureClass(
MemberEntity member,
ir.FunctionNode originalClosureFunctionNode,
JLibrary enclosingLibrary,
- Map<Local, JRecordField> boxedVariables,
+ Map<ir.VariableDeclaration, JRecordField> boxedVariables,
KernelScopeInfo info,
- KernelToLocalsMap localsMap,
{bool createSignatureMethod}) {
ClassEntity superclass = _commonElements.closureClass;
- KernelClosureClassInfo closureClassInfo = _elementMap.constructClosureClass(
+ JsClosureClassInfo closureClassInfo = _elementMap.constructClosureClass(
member,
originalClosureFunctionNode,
enclosingLibrary,
boxedVariables,
info,
- localsMap,
_dartTypes.interfaceType(superclass, const []),
createSignatureMethod: createSignatureMethod);
diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart
index c783b25..1d5cd00 100644
--- a/pkg/compiler/lib/src/js_model/locals.dart
+++ b/pkg/compiler/lib/src/js_model/locals.dart
@@ -22,14 +22,23 @@
/// debugging data stream.
static const String tag = 'global-locals-map';
+ /// Lookup up the key used to store a LocalsMap for a member.
+ ///
+ /// While procedures are keyed by their own entity, closures use the
+ /// enclosing member as a key. This ensures that the member and all
+ /// nested closures share the same local map.
+ MemberEntity Function(MemberEntity) _localMapKeyLookup;
+
final Map<MemberEntity, KernelToLocalsMap> _localsMaps;
- GlobalLocalsMap() : _localsMaps = {};
+ GlobalLocalsMap(this._localMapKeyLookup) : _localsMaps = {};
- GlobalLocalsMap.internal(this._localsMaps);
+ GlobalLocalsMap.internal(this._localMapKeyLookup, this._localsMaps);
/// Deserializes a [GlobalLocalsMap] object from [source].
- factory GlobalLocalsMap.readFromDataSource(DataSource source) {
+ factory GlobalLocalsMap.readFromDataSource(
+ MemberEntity Function(MemberEntity) localMapKeyLookup,
+ DataSource source) {
source.begin(tag);
Map<MemberEntity, KernelToLocalsMap> _localsMaps = {};
int mapCount = source.readInt();
@@ -42,7 +51,7 @@
}
}
source.end(tag);
- return new GlobalLocalsMap.internal(_localsMaps);
+ return new GlobalLocalsMap.internal(localMapKeyLookup, _localsMaps);
}
/// Serializes this [GlobalLocalsMap] to [sink].
@@ -68,26 +77,19 @@
/// Returns the [KernelToLocalsMap] for [member].
KernelToLocalsMap getLocalsMap(MemberEntity member) {
- // If element is a ConstructorBodyEntity, its localsMap is the same as for
+ // If [member] is a closure call method or closure signature method, its
+ // localsMap is the same as for the enclosing member since the locals are
+ // derived from the same kernel AST.
+ MemberEntity key = _localMapKeyLookup(member);
+ // If [member] is a ConstructorBodyEntity, its localsMap is the same as for
// ConstructorEntity, because both of these entities came from the same
// constructor node. The entities are two separate parts because JS does not
// have the concept of an initializer list, so the constructor (initializer
// list) and the constructor body are implemented as two separate
// constructor steps.
- MemberEntity entity = member;
- if (entity is ConstructorBodyEntity) member = entity.constructor;
- return _localsMaps.putIfAbsent(
- member, () => new KernelToLocalsMapImpl(member));
- }
-
- /// Associates [localsMap] with [member].
- ///
- /// Use this for sharing maps between members that share IR nodes.
- void setLocalsMap(MemberEntity member, KernelToLocalsMap localsMap) {
- assert(member != null, "No member provided.");
- assert(!_localsMaps.containsKey(member),
- "Locals map already created for $member.");
- _localsMaps[member] = localsMap;
+ MemberEntity entity = key;
+ if (entity is ConstructorBodyEntity) key = entity.constructor;
+ return _localsMaps.putIfAbsent(key, () => new KernelToLocalsMapImpl(key));
}
}
@@ -272,12 +274,11 @@
}
@override
- Local getLocalTypeVariable(
- ir.TypeParameterType node, JsToElementMap elementMap) {
+ Local getLocalTypeVariableEntity(TypeVariableEntity typeVariable) {
// TODO(efortuna, johnniwinther): We're not registering the type variables
// like we are for the variable declarations. Is that okay or do we need to
// make TypeVariableLocal a JLocal?
- return TypeVariableLocal(elementMap.getTypeVariableType(node).element);
+ return TypeVariableLocal(typeVariable);
}
@override
diff --git a/pkg/compiler/lib/src/serialization/mixins.dart b/pkg/compiler/lib/src/serialization/mixins.dart
index d7d5d87..0b48464 100644
--- a/pkg/compiler/lib/src/serialization/mixins.dart
+++ b/pkg/compiler/lib/src/serialization/mixins.dart
@@ -185,6 +185,20 @@
}
@override
+ Map<K, V> readTypeVariableMap<K extends IndexedTypeVariable, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ IndexedTypeVariable node = readTypeVariable();
+ V value = f();
+ map[node] = value;
+ }
+ return map;
+ }
+
+ @override
List<E> readLocals<E extends Local>({bool emptyAsNull: false}) {
int count = readInt();
if (count == 0 && emptyAsNull) return null;
@@ -606,6 +620,21 @@
}
@override
+ void writeTypeVariableMap<V>(Map<IndexedTypeVariable, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((IndexedTypeVariable key, V value) {
+ writeTypeVariable(key);
+ f(value);
+ });
+ }
+ }
+
+ @override
void writeList<E>(Iterable<E> values, void f(E value),
{bool allowNull: false}) {
if (values == null) {
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 6cc9a51..14fb2f7 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -329,6 +329,15 @@
/// Writes a reference to the indexed type variable [value] to this data sink.
void writeTypeVariable(IndexedTypeVariable value);
+ /// Writes the [map] from references to indexed type variables to [V] values
+ /// to this data sink, calling [f] to write each value to the data sink. If
+ /// [allowNull] is `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readTypeVariableMap].
+ void writeTypeVariableMap<V>(Map<IndexedTypeVariable, V> map, void f(V value),
+ {bool allowNull: false});
+
/// Writes a reference to the local [value] to this data sink.
void writeLocal(Local local);
@@ -742,6 +751,15 @@
/// Reads a reference to an indexed type variable from this data source.
IndexedTypeVariable readTypeVariable();
+ /// Reads a map from indexed type variable to [V] values from this data
+ /// source, calling [f] to read each value from the data source. If
+ /// [emptyAsNull] is `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeTypeVariableMap].
+ Map<K, V> readTypeVariableMap<K extends IndexedTypeVariable, V>(V f(),
+ {bool emptyAsNull: false});
+
/// Reads a reference to a local from this data source.
Local readLocal();
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 707def0..3ac7e86 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -19,6 +19,7 @@
import '../js_backend/backend.dart';
import '../js_backend/inferred_data.dart';
import '../js_model/js_world.dart';
+import '../js_model/locals.dart';
import '../options.dart';
import '../util/sink_adapter.dart';
import '../world.dart';
@@ -27,8 +28,10 @@
void serializeGlobalTypeInferenceResultsToSink(
GlobalTypeInferenceResults results, DataSink sink) {
JsClosedWorld closedWorld = results.closedWorld;
+ GlobalLocalsMap globalLocalsMap = results.globalLocalsMap;
InferredData inferredData = results.inferredData;
closedWorld.writeToDataSink(sink);
+ globalLocalsMap.writeToDataSink(sink);
inferredData.writeToDataSink(sink);
results.writeToDataSink(sink, closedWorld.elementMap);
sink.close();
@@ -42,10 +45,16 @@
ir.Component component,
JsClosedWorld newClosedWorld,
DataSource source) {
+ GlobalLocalsMap newGlobalLocalsMap = GlobalLocalsMap.readFromDataSource(
+ newClosedWorld.closureDataLookup.getEnclosingMember, source);
InferredData newInferredData =
InferredData.readFromDataSource(source, newClosedWorld);
return GlobalTypeInferenceResults.readFromDataSource(
- source, newClosedWorld.elementMap, newClosedWorld, newInferredData);
+ source,
+ newClosedWorld.elementMap,
+ newClosedWorld,
+ newGlobalLocalsMap,
+ newInferredData);
}
GlobalTypeInferenceResults deserializeGlobalTypeInferenceResultsFromSource(
@@ -57,10 +66,16 @@
DataSource source) {
JsClosedWorld newClosedWorld = new JsClosedWorld.readFromDataSource(
options, reporter, environment, abstractValueStrategy, component, source);
+ GlobalLocalsMap newGlobalLocalsMap = GlobalLocalsMap.readFromDataSource(
+ newClosedWorld.closureDataLookup.getEnclosingMember, source);
InferredData newInferredData =
new InferredData.readFromDataSource(source, newClosedWorld);
return new GlobalTypeInferenceResults.readFromDataSource(
- source, newClosedWorld.elementMap, newClosedWorld, newInferredData);
+ source,
+ newClosedWorld.elementMap,
+ newClosedWorld,
+ newGlobalLocalsMap,
+ newInferredData);
}
void serializeClosedWorldToSink(JsClosedWorld closedWorld, DataSink sink) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 20e835b..4bd37c8 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -34,7 +34,7 @@
import '../js_backend/native_data.dart';
import '../js_backend/runtime_types_resolution.dart';
import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
-import '../js_model/locals.dart' show JumpVisitor;
+import '../js_model/locals.dart' show GlobalLocalsMap, JumpVisitor;
import '../js_model/elements.dart' show JGeneratorBody;
import '../js_model/element_map.dart';
import '../js_model/js_strategy.dart';
@@ -212,6 +212,9 @@
RuntimeTypesNeed get _rtiNeed => closedWorld.rtiNeed;
+ GlobalLocalsMap get _globalLocalsMap =>
+ globalInferenceResults.globalLocalsMap;
+
InferredData get _inferredData => globalInferenceResults.inferredData;
DartTypes get dartTypes => closedWorld.dartTypes;
@@ -408,7 +411,7 @@
_currentFrame,
member,
asyncMarker,
- closedWorld.globalLocalsMap.getLocalsMap(member),
+ _globalLocalsMap.getLocalsMap(member),
{},
new KernelToTypeInferenceMapImpl(member, globalInferenceResults),
_currentFrame != null
@@ -862,7 +865,7 @@
CapturedScope scopeData =
_closureDataLookup.getCapturedScope(constructorBody);
if (scopeData.requiresContextBox) {
- bodyCallInputs.add(localsHandler.readLocal(scopeData.context));
+ bodyCallInputs.add(localsHandler.readLocal(scopeData.contextBox));
}
// Pass type arguments.
@@ -1166,7 +1169,7 @@
var index = 0;
ConstructorEntity element = _elementMap.getConstructor(constructor);
- ScopeInfo oldScopeInfo = localsHandler.scopeInfo;
+ MemberEntity oldScopeMember = localsHandler.scopeMember;
_inlinedFrom(
element, _sourceInformationBuilder.buildCall(initializer, initializer),
@@ -1190,13 +1193,12 @@
constructorData, element.enclosingClass);
// Set the locals handler state as if we were inlining the constructor.
- ScopeInfo newScopeInfo = _closureDataLookup.getScopeInfo(element);
- localsHandler.scopeInfo = newScopeInfo;
+ localsHandler.setupScope(element);
localsHandler.enterScope(_closureDataLookup.getCapturedScope(element),
_sourceInformationBuilder.buildDeclaration(element));
_buildInitializers(constructor, constructorData);
});
- localsHandler.scopeInfo = oldScopeInfo;
+ localsHandler.setupScope(oldScopeMember);
}
/// Constructs a special signature function for a closure.
@@ -1391,7 +1393,7 @@
if (nodeIsConstructorBody &&
_closureDataLookup
.getCapturedScope(targetElement)
- .isBoxedVariable(local)) {
+ .isBoxedVariable(_localsMap, local)) {
// If local is boxed, then `variable` will be a field inside the box
// passed as the last parameter, so no need to update our locals
// handler or check types at this point.
@@ -1430,9 +1432,10 @@
closedWorld.annotationsData.getParameterCheckPolicy(method).isEmitted) {
ir.FunctionNode function = getFunctionNode(_elementMap, method);
for (ir.TypeParameter typeParameter in function.typeParameters) {
- Local local = _localsMap.getLocalTypeVariable(
- new ir.TypeParameterType(typeParameter, ir.Nullability.nonNullable),
- _elementMap);
+ Local local = _localsMap.getLocalTypeVariableEntity(_elementMap
+ .getTypeVariableType(new ir.TypeParameterType(
+ typeParameter, ir.Nullability.nonNullable))
+ .element);
HInstruction newParameter = localsHandler.directLocals[local];
DartType bound = _getDartTypeIfValid(typeParameter.bound);
if (!dartTypes.isTopType(bound)) {
@@ -1629,12 +1632,7 @@
close(new HGoto(_abstractValueDomain)).addSuccessor(block);
open(block);
- localsHandler.startFunction(
- targetElement,
- _closureDataLookup.getScopeInfo(targetElement),
- _closureDataLookup.getCapturedScope(targetElement),
- parameterMap,
- elidedParameterSet,
+ localsHandler.startFunction(targetElement, parameterMap, elidedParameterSet,
_sourceInformationBuilder.buildDeclaration(targetElement),
isGenerativeConstructorBody: targetElement is ConstructorBodyEntity);
@@ -5113,8 +5111,8 @@
_elementEnvironment.forEachInstanceField(closureClassEntity,
(_, FieldEntity field) {
if (_fieldAnalysis.getFieldData(field).isElided) return;
- capturedVariables
- .add(localsHandler.readLocal(closureInfo.getLocalForField(field)));
+ capturedVariables.add(localsHandler
+ .readLocal(closureInfo.getLocalForField(_localsMap, field)));
});
AbstractValue type =
@@ -6017,7 +6015,7 @@
instanceType ?? _elementMap.getMemberThisType(function),
_nativeData,
_interceptorData);
- localsHandler.scopeInfo = _closureDataLookup.getScopeInfo(function);
+ localsHandler.setupScope(function);
CapturedScope scopeData = _closureDataLookup.getCapturedScope(function);
bool forGenerativeConstructorBody = function is ConstructorBodyEntity;
@@ -6029,14 +6027,13 @@
int argumentIndex = 0;
if (function.isInstanceMember) {
- localsHandler.updateLocal(localsHandler.scopeInfo.thisLocal,
- compiledArguments[argumentIndex++]);
+ localsHandler.updateLocal(
+ localsHandler.thisLocal, compiledArguments[argumentIndex++]);
}
ir.Member memberContextNode = _elementMap.getMemberContextNode(function);
bool hasBox = false;
- KernelToLocalsMap localsMap =
- closedWorld.globalLocalsMap.getLocalsMap(function);
+ KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(function);
forEachOrderedParameter(_elementMap, function,
(ir.VariableDeclaration variable, {bool isElided}) {
Local local = localsMap.getLocalVariable(variable);
@@ -6045,7 +6042,8 @@
local, _defaultValueForParameter(memberContextNode, variable));
return;
}
- if (forGenerativeConstructorBody && scopeData.isBoxedVariable(local)) {
+ if (forGenerativeConstructorBody &&
+ scopeData.isBoxedVariable(_localsMap, local)) {
// The parameter will be a field in the box passed as the last
// parameter. So no need to have it.
hasBox = true;
@@ -6202,8 +6200,7 @@
_checkTypeVariableBounds(function);
}
- KernelToLocalsMap localsMap =
- closedWorld.globalLocalsMap.getLocalsMap(function);
+ KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(function);
forEachOrderedParameter(_elementMap, function,
(ir.VariableDeclaration variable, {bool isElided}) {
Local parameter = localsMap.getLocalVariable(variable);
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
index 3798e19..ea01915 100644
--- a/pkg/compiler/lib/src/ssa/locals_handler.dart
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -2,6 +2,8 @@
// 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 'package:compiler/src/js_model/element_map.dart';
+
import '../closure.dart';
import '../common.dart';
import '../elements/entities.dart';
@@ -12,7 +14,7 @@
import '../js_backend/native_data.dart';
import '../js_backend/interceptor_data.dart';
import '../js_model/closure.dart' show JRecordField, JClosureField;
-import '../js_model/locals.dart' show JLocal;
+import '../js_model/locals.dart' show GlobalLocalsMap, JLocal;
import '../world.dart' show JClosedWorld;
import 'builder_kernel.dart';
@@ -33,7 +35,11 @@
Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>();
Map<Local, FieldEntity> redirectionMapping = new Map<Local, FieldEntity>();
final KernelSsaGraphBuilder builder;
- ScopeInfo scopeInfo;
+
+ MemberEntity _scopeInfoMember;
+ ScopeInfo _scopeInfo;
+ KernelToLocalsMap _localsMap;
+
Map<TypeVariableEntity, TypeVariableLocal> typeVariableLocals =
new Map<TypeVariableEntity, TypeVariableLocal>();
final Entity executableContext;
@@ -73,6 +79,9 @@
GlobalTypeInferenceResults get _globalInferenceResults =>
builder.globalInferenceResults;
+ GlobalLocalsMap get _globalLocalsMap =>
+ _globalInferenceResults.globalLocalsMap;
+
/// Substituted type variables occurring in [type] into the context of
/// [contextClass].
DartType substInContext(DartType type) {
@@ -103,13 +112,33 @@
memberContext = other.memberContext,
instanceType = other.instanceType,
builder = other.builder,
- scopeInfo = other.scopeInfo,
+ _scopeInfo = other._scopeInfo,
+ _scopeInfoMember = other._scopeInfoMember,
+ _localsMap = other._localsMap,
_nativeData = other._nativeData,
_interceptorData = other._interceptorData,
activationVariables = other.activationVariables,
cachedTypeOfThis = other.cachedTypeOfThis,
cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables;
+ /// Sets up the scope to use the scope and locals from [member].
+ void setupScope(MemberEntity member) {
+ _scopeInfoMember = member;
+ if (member != null) {
+ _scopeInfo = _closedWorld.closureDataLookup.getScopeInfo(member);
+ _localsMap = _globalLocalsMap.getLocalsMap(member);
+ } else {
+ _scopeInfo = null;
+ _localsMap = null;
+ }
+ }
+
+ /// Returns the member that currently defines the scope as setup in
+ /// [setupScope].
+ MemberEntity get scopeMember => _scopeInfoMember;
+
+ Local get thisLocal => _scopeInfo.thisLocal;
+
/// Redirects accesses from element [from] to element [to]. The [to] element
/// must be a boxed variable or a variable that is stored in a closure-field.
void redirectElement(Local from, FieldEntity to) {
@@ -139,15 +168,15 @@
// The box is passed as a parameter to a generative constructor body.
box = inlinedBox ??
builder.addParameter(
- closureInfo.context, _abstractValueDomain.nonNullType);
+ closureInfo.contextBox, _abstractValueDomain.nonNullType);
} else {
box = createBox(sourceInformation);
}
// Add the box to the known locals.
- directLocals[closureInfo.context] = box;
+ directLocals[closureInfo.contextBox] = box;
// Make sure that accesses to the boxed locals go into the box. We also
// need to make sure that parameters are copied into the box if necessary.
- closureInfo.forEachBoxedVariable((Local from, FieldEntity to) {
+ closureInfo.forEachBoxedVariable(_localsMap, (Local from, FieldEntity to) {
// The [from] can only be a parameter for function-scopes and not
// loop scopes.
JLocal jFrom = from;
@@ -192,19 +221,17 @@
/// Documentation wanted -- johnniwinther
///
/// Invariant: [function] must be an implementation element.
- void startFunction(
- MemberEntity element,
- ScopeInfo scopeInfo,
- CapturedScope scopeData,
- Map<Local, AbstractValue> parameters,
- Set<Local> elidedParameters,
- SourceInformation sourceInformation,
+ void startFunction(MemberEntity element, Map<Local, AbstractValue> parameters,
+ Set<Local> elidedParameters, SourceInformation sourceInformation,
{bool isGenerativeConstructorBody}) {
- this.scopeInfo = scopeInfo;
+ setupScope(element);
+
+ CapturedScope scopeData =
+ _closedWorld.closureDataLookup.getCapturedScope(element);
parameters.forEach((Local local, AbstractValue typeMask) {
if (isGenerativeConstructorBody) {
- if (scopeData.isBoxedVariable(local)) {
+ if (scopeData.isBoxedVariable(_localsMap, local)) {
// The parameter will be a field in the box passed as the
// last parameter. So no need to have it.
return;
@@ -223,12 +250,13 @@
// When we remove the element model, we can just use the first check
// (because the underlying elements won't all be *both* ScopeInfos and
// ClosureRepresentationInfos).
+ ScopeInfo scopeInfo = _scopeInfo;
if (scopeInfo is ClosureRepresentationInfo && scopeInfo.isClosure) {
ClosureRepresentationInfo closureData = scopeInfo;
// If the freeVariableMapping is not empty, then this function was a
// nested closure that captures variables. Redirect the captured
// variables to fields in the closure.
- closureData.forEachFreeVariable((Local from, FieldEntity to) {
+ closureData.forEachFreeVariable(_localsMap, (Local from, FieldEntity to) {
redirectElement(from, to);
});
// Inside closure redirect references to itself to [:this:].
@@ -236,7 +264,7 @@
new HThis(closureData.thisLocal, _abstractValueDomain.nonNullType);
builder.graph.thisInstruction = thisInstruction;
builder.graph.entry.addAtEntry(thisInstruction);
- updateLocal(closureData.closureEntity, thisInstruction);
+ updateLocal(closureData.getClosureEntity(_localsMap), thisInstruction);
} else if (element.isInstanceMember) {
// Once closures have been mapped to classes their instance members might
// not have any thisElement if the closure was created inside a static
@@ -294,13 +322,13 @@
bool isAccessedDirectly(Local local) {
assert(local != null);
return !redirectionMapping.containsKey(local) &&
- !scopeInfo.localIsUsedInTryOrSync(local);
+ !_scopeInfo.localIsUsedInTryOrSync(_localsMap, local);
}
bool isStoredInClosureField(Local local) {
assert(local != null);
if (isAccessedDirectly(local)) return false;
- if (scopeInfo is! ClosureRepresentationInfo) return false;
+ if (_scopeInfo is! ClosureRepresentationInfo) return false;
FieldEntity redirectTarget = redirectionMapping[local];
if (redirectTarget == null) return false;
return redirectTarget is JClosureField;
@@ -313,7 +341,7 @@
}
bool _isUsedInTryOrGenerator(Local local) {
- return scopeInfo.localIsUsedInTryOrSync(local);
+ return _scopeInfo.localIsUsedInTryOrSync(_localsMap, local);
}
/// Returns an [HInstruction] for the given element. If the element is
@@ -341,9 +369,10 @@
}
return value;
} else if (isStoredInClosureField(local)) {
- ClosureRepresentationInfo closureData = scopeInfo;
+ ClosureRepresentationInfo closureData = _scopeInfo;
FieldEntity redirect = redirectionMapping[local];
- HInstruction receiver = readLocal(closureData.closureEntity);
+ HInstruction receiver =
+ readLocal(closureData.getClosureEntity(_localsMap));
AbstractValue type = local is BoxLocal
? _abstractValueDomain.nonNullType
: getTypeOfCapturedVariable(redirect);
@@ -381,7 +410,7 @@
HInstruction readThis({SourceInformation sourceInformation}) {
HInstruction res =
- readLocal(scopeInfo.thisLocal, sourceInformation: sourceInformation);
+ readLocal(_scopeInfo.thisLocal, sourceInformation: sourceInformation);
if (res.instructionType == null) {
res.instructionType = getTypeOfThis();
}
@@ -514,7 +543,7 @@
savedDirectLocals.forEach((Local local, HInstruction instruction) {
if (isAccessedDirectly(local)) {
// We know 'this' cannot be modified.
- if (local != scopeInfo.thisLocal) {
+ if (local != _scopeInfo.thisLocal) {
HPhi phi = new HPhi.singleInput(
local, instruction, _abstractValueDomain.dynamicType);
loopEntry.addPhi(phi);
@@ -543,8 +572,8 @@
// In all other cases a new box will be created when entering the body of
// the next iteration.
if (loopInfo.hasBoxedLoopVariables) {
- updateCaptureBox(
- loopInfo.context, loopInfo.boxedLoopVariables, sourceInformation);
+ updateCaptureBox(loopInfo.contextBox,
+ loopInfo.getBoxedLoopVariables(_localsMap), sourceInformation);
}
}
@@ -574,7 +603,7 @@
Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
// We know 'this' cannot be modified.
- if (local == scopeInfo.thisLocal) {
+ if (local == _scopeInfo.thisLocal) {
assert(directLocals[local] == instruction);
joinedLocals[local] = instruction;
} else {
@@ -607,7 +636,7 @@
Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
HInstruction thisValue = null;
directLocals.forEach((Local local, HInstruction instruction) {
- if (local != scopeInfo.thisLocal) {
+ if (local != _scopeInfo.thisLocal) {
HPhi phi = new HPhi.noInputs(local, _abstractValueDomain.dynamicType);
joinedLocals[local] = phi;
joinBlock.addPhi(phi);
@@ -628,13 +657,13 @@
}
if (thisValue != null) {
// If there was a "this" for the scope, add it to the new locals.
- joinedLocals[scopeInfo.thisLocal] = thisValue;
+ joinedLocals[_scopeInfo.thisLocal] = thisValue;
}
// Remove locals that are not in all handlers.
directLocals = new Map<Local, HInstruction>();
joinedLocals.forEach((Local local, HInstruction instruction) {
- if (local != scopeInfo.thisLocal &&
+ if (local != _scopeInfo.thisLocal &&
instruction.inputs.length != localsHandlers.length) {
joinBlock.removePhi(instruction);
} else {
@@ -649,7 +678,7 @@
AbstractValue getTypeOfThis() {
AbstractValue result = cachedTypeOfThis;
if (result == null) {
- ThisLocal local = scopeInfo.thisLocal;
+ ThisLocal local = _scopeInfo.thisLocal;
ClassEntity cls = local.enclosingClass;
if (_closedWorld.isUsedAsMixin(cls)) {
// If the enclosing class is used as a mixin, [:this:] can be
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index fc7f564..68effb3 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -26,7 +26,6 @@
import 'js_backend/native_data.dart' show NativeData;
import 'js_backend/no_such_method_registry.dart' show NoSuchMethodData;
import 'js_backend/runtime_types_resolution.dart' show RuntimeTypesNeed;
-import 'js_model/locals.dart';
import 'js_emitter/sorter.dart';
import 'universe/class_hierarchy.dart';
import 'universe/member_usage.dart';
@@ -78,7 +77,6 @@
AnnotationsData get annotationsData;
- GlobalLocalsMap get globalLocalsMap;
ClosureData get closureDataLookup;
OutputUnitData get outputUnitData;
diff --git a/pkg/compiler/test/closure/closure_test.dart b/pkg/compiler/test/closure/closure_test.dart
index 0701d19..231025d 100644
--- a/pkg/compiler/test/closure/closure_test.dart
+++ b/pkg/compiler/test/closure/closure_test.dart
@@ -38,7 +38,8 @@
{bool verbose: false}) {
JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
JsToElementMap elementMap = closedWorld.elementMap;
- GlobalLocalsMap localsMap = closedWorld.globalLocalsMap;
+ GlobalLocalsMap localsMap =
+ compiler.globalInference.resultsForTesting.globalLocalsMap;
ClosureData closureDataLookup = closedWorld.closureDataLookup;
MemberDefinition definition = elementMap.getMemberDefinition(member);
assert(
@@ -158,7 +159,7 @@
capturedScopeStack =
capturedScopeStack.prepend(closureDataLookup.getCapturedScope(member));
if (capturedScope.requiresContextBox) {
- boxNames[capturedScope.context] = 'box${boxNames.length}';
+ boxNames[capturedScope.contextBox] = 'box${boxNames.length}';
}
dump(member);
}
@@ -174,7 +175,7 @@
capturedScopeStack = capturedScopeStack
.prepend(closureDataLookup.getCapturedLoopScope(node));
if (capturedScope.requiresContextBox) {
- boxNames[capturedScope.context] = 'box${boxNames.length}';
+ boxNames[capturedScope.contextBox] = 'box${boxNames.length}';
}
dump(node);
}
@@ -199,37 +200,38 @@
print('object: $object');
if (object is MemberEntity) {
print(' capturedScope (${capturedScope.runtimeType})');
- capturedScope.forEachBoxedVariable((a, b) => print(' boxed: $a->$b'));
+ capturedScope.forEachBoxedVariable(
+ _localsMap, (a, b) => print(' boxed: $a->$b'));
}
print(
' closureRepresentationInfo (${closureRepresentationInfo.runtimeType})');
- closureRepresentationInfo
- ?.forEachFreeVariable((a, b) => print(' free: $a->$b'));
- closureRepresentationInfo
- ?.forEachBoxedVariable((a, b) => print(' boxed: $a->$b'));
+ closureRepresentationInfo?.forEachFreeVariable(
+ _localsMap, (a, b) => print(' free: $a->$b'));
+ closureRepresentationInfo?.forEachBoxedVariable(
+ _localsMap, (a, b) => print(' boxed: $a->$b'));
}
/// Compute a string representation of the data stored for [local] in [info].
String computeLocalValue(Local local) {
Features features = new Features();
- if (scopeInfo.localIsUsedInTryOrSync(local)) {
+ if (scopeInfo.localIsUsedInTryOrSync(_localsMap, local)) {
features.add('inTry');
// TODO(johnniwinther,efortuna): Should this be enabled and checked?
//Expect.isTrue(capturedScope.localIsUsedInTryOrSync(local));
} else {
//Expect.isFalse(capturedScope.localIsUsedInTryOrSync(local));
}
- if (capturedScope.isBoxedVariable(local)) {
+ if (capturedScope.isBoxedVariable(_localsMap, local)) {
features.add('boxed');
}
- if (capturedScope.context == local) {
+ if (capturedScope.contextBox == local) {
// TODO(johnniwinther): This shouldn't happen! Remove branch/throw error
// when we verify it can't happen.
features.add('error-box');
}
if (capturedScope is CapturedLoopScope) {
CapturedLoopScope loopScope = capturedScope;
- if (loopScope.boxedLoopVariables.contains(local)) {
+ if (loopScope.getBoxedLoopVariables(_localsMap).contains(local)) {
features.add('loop');
}
}
@@ -240,9 +242,10 @@
String computeObjectValue(MemberEntity member) {
Features features = new Features();
- void addLocals(String name, forEach(f(Local local, _))) {
+ void addLocals(
+ String name, forEach(KernelToLocalsMap localsMap, f(Local local, _))) {
List<String> names = <String>[];
- forEach((Local local, _) {
+ forEach(_localsMap, (Local local, _) {
if (local is BoxLocal) {
names.add(boxNames[local]);
} else {
@@ -263,7 +266,7 @@
if (capturedScope.requiresContextBox) {
var keyword = 'boxed';
addLocals(keyword, capturedScope.forEachBoxedVariable);
- features['box'] = '(${boxNames[capturedScope.context]} which holds '
+ features['box'] = '(${boxNames[capturedScope.contextBox]} which holds '
'${features[keyword]})';
features.remove(keyword);
}
@@ -271,12 +274,13 @@
if (closureRepresentationInfo != null) {
addLocals('free', closureRepresentationInfo.forEachFreeVariable);
if (closureRepresentationInfo.closureClassEntity != null) {
- addLocals('fields', (f(Local local, _)) {
+ addLocals('fields', (KernelToLocalsMap localsMap, f(Local local, _)) {
_closedWorld.elementEnvironment.forEachInstanceField(
closureRepresentationInfo.closureClassEntity,
(_, FieldEntity field) {
if (_closedWorld.fieldAnalysis.getFieldData(field).isElided) return;
- f(closureRepresentationInfo.getLocalForField(field), field);
+ f(closureRepresentationInfo.getLocalForField(localsMap, field),
+ field);
});
});
}
diff --git a/pkg/compiler/test/codegen/expect_annotations_test.dart b/pkg/compiler/test/codegen/expect_annotations_test.dart
index 9ed3517..a3df294 100644
--- a/pkg/compiler/test/codegen/expect_annotations_test.dart
+++ b/pkg/compiler/test/codegen/expect_annotations_test.dart
@@ -55,7 +55,7 @@
AbstractValue expectedReturnType,
GlobalTypeInferenceResults results) {
closedWorld.elementEnvironment.forEachParameterAsLocal(
- closedWorld.globalLocalsMap, function, (Local parameter) {
+ results.globalLocalsMap, function, (Local parameter) {
AbstractValue type = results.resultOfParameter(parameter);
Expect.equals(
expectedParameterType, simplify(type, commonMasks), "$parameter");
diff --git a/pkg/compiler/test/codegen/type_inference8_test.dart b/pkg/compiler/test/codegen/type_inference8_test.dart
index 382ef35..252f2e4 100644
--- a/pkg/compiler/test/codegen/type_inference8_test.dart
+++ b/pkg/compiler/test/codegen/type_inference8_test.dart
@@ -62,7 +62,7 @@
// the argument to 'bar' is always false
MemberEntity bar = elementEnvironment.lookupLibraryMember(
elementEnvironment.mainLibrary, 'bar');
- elementEnvironment.forEachParameterAsLocal(closedWorld.globalLocalsMap, bar,
+ elementEnvironment.forEachParameterAsLocal(results.globalLocalsMap, bar,
(barArg) {
AbstractValue barArgMask = results.resultOfParameter(barArg);
Expect.equals(falseType, barArgMask);
@@ -110,7 +110,7 @@
Expect.identical(commonMasks.boolType, mask);
MemberEntity bar = elementEnvironment.lookupLibraryMember(
elementEnvironment.mainLibrary, 'bar');
- elementEnvironment.forEachParameterAsLocal(closedWorld.globalLocalsMap, bar,
+ elementEnvironment.forEachParameterAsLocal(results.globalLocalsMap, bar,
(barArg) {
AbstractValue barArgMask = results.resultOfParameter(barArg);
// The argument to bar should have the same type as the return type of foo
diff --git a/pkg/compiler/test/inference/inference_test_helper.dart b/pkg/compiler/test/inference/inference_test_helper.dart
index fa5feb0..d049559 100644
--- a/pkg/compiler/test/inference/inference_test_helper.dart
+++ b/pkg/compiler/test/inference/inference_test_helper.dart
@@ -52,7 +52,9 @@
{bool verbose: false}) {
JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
JsToElementMap elementMap = closedWorld.elementMap;
- GlobalLocalsMap localsMap = closedWorld.globalLocalsMap;
+ GlobalTypeInferenceResults results =
+ compiler.globalInference.resultsForTesting;
+ GlobalLocalsMap localsMap = results.globalLocalsMap;
MemberDefinition definition = elementMap.getMemberDefinition(member);
new TypeMaskIrComputer(
compiler.reporter,
@@ -60,7 +62,7 @@
elementMap,
member,
localsMap.getLocalsMap(member),
- compiler.globalInference.resultsForTesting,
+ results,
closedWorld.closureDataLookup)
.run(definition.node);
}
diff --git a/pkg/compiler/test/inference/load_deferred_library_test.dart b/pkg/compiler/test/inference/load_deferred_library_test.dart
index aad3724..8c6e15e 100644
--- a/pkg/compiler/test/inference/load_deferred_library_test.dart
+++ b/pkg/compiler/test/inference/load_deferred_library_test.dart
@@ -51,8 +51,9 @@
helperLibrary, 'loadDeferredLibrary');
TypeMask typeMask;
- KernelToLocalsMap localsMap =
- closedWorld.globalLocalsMap.getLocalsMap(loadDeferredLibrary);
+ KernelToLocalsMap localsMap = compiler
+ .globalInference.resultsForTesting.globalLocalsMap
+ .getLocalsMap(loadDeferredLibrary);
MemberDefinition definition =
closedWorld.elementMap.getMemberDefinition(loadDeferredLibrary);
ir.Procedure procedure = definition.node;
diff --git a/pkg/compiler/test/jumps/jump_test.dart b/pkg/compiler/test/jumps/jump_test.dart
index 35b67d1..b848bd7 100644
--- a/pkg/compiler/test/jumps/jump_test.dart
+++ b/pkg/compiler/test/jumps/jump_test.dart
@@ -39,7 +39,8 @@
{bool verbose: false}) {
JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
JsToElementMap elementMap = closedWorld.elementMap;
- GlobalLocalsMap localsMap = closedWorld.globalLocalsMap;
+ GlobalLocalsMap localsMap =
+ compiler.globalInference.resultsForTesting.globalLocalsMap;
MemberDefinition definition = elementMap.getMemberDefinition(member);
new JumpsIrChecker(
compiler.reporter, actualMap, localsMap.getLocalsMap(member))
diff --git a/tests/web/regress/scope_info_field_loop_test.dart b/tests/web/regress/scope_info_field_loop_test.dart
new file mode 100644
index 0000000..cf4c44b
--- /dev/null
+++ b/tests/web/regress/scope_info_field_loop_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for failure caused by refactoring of handling of scope info
+// locals map in the ssa locals handler.
+
+class Class {
+ static const list = [];
+ var field = {for (final key in list) key: null};
+
+ Class(parameter) {
+ parameter;
+ }
+}
+
+main() {
+ new Class(null);
+}
diff --git a/tests/web_2/regress/scope_info_field_loop_test.dart b/tests/web_2/regress/scope_info_field_loop_test.dart
new file mode 100644
index 0000000..c756dfa
--- /dev/null
+++ b/tests/web_2/regress/scope_info_field_loop_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for failure caused by refactoring of handling of scope info
+// locals map in the ssa locals handler.
+
+// @dart=2.9
+
+class Class {
+ static const list = [];
+ var field = {for (final key in list) key: null};
+
+ Class(parameter) {
+ parameter;
+ }
+}
+
+main() {
+ new Class(null);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 7ebd6a0..4da2654 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 8
+PRERELEASE 9
PRERELEASE_PATCH 0
\ No newline at end of file