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

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

Issue 2283443002: Make LocalsHandler depend on GraphBuilder instead of SsaBuilder. (Closed)
Patch Set: fix tests Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/builder_kernel.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/ssa/builder.dart
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 14615b42ac1e8aa3cc52301d92a71c8c62ac0077..7d088f14978d313aae0b52297de15470e678ad17 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -39,6 +39,7 @@ import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../util/util.dart';
import '../world.dart' show ClassWorld;
import 'graph_builder.dart';
+import 'locals_handler.dart';
import 'nodes.dart';
import 'optimize.dart';
import 'types.dart';
@@ -123,632 +124,6 @@ class SsaBuilderTask extends CompilerTask {
}
}
-/**
- * Keeps track of locals (including parameters and phis) when building. The
- * 'this' reference is treated as parameter and hence handled by this class,
- * too.
- */
-class LocalsHandler {
- /**
- * The values of locals that can be directly accessed (without redirections
- * to boxes or closure-fields).
- *
- * [directLocals] is iterated, so it is "insertion ordered" to make the
- * iteration order a function only of insertions and not a function of
- * e.g. Element hash codes. I'd prefer to use a SortedMap but some elements
- * don't have source locations for [Elements.compareByPosition].
- */
- Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>();
- Map<Local, CapturedVariable> redirectionMapping =
- new Map<Local, CapturedVariable>();
- SsaBuilder builder;
- ClosureClassMap closureData;
- Map<TypeVariableType, TypeVariableLocal> typeVariableLocals =
- new Map<TypeVariableType, TypeVariableLocal>();
- final ExecutableElement executableContext;
-
- /// The class that defines the current type environment or null if no type
- /// variables are in scope.
- ClassElement get contextClass => executableContext.contextClass;
-
- /// The type of the current instance, if concrete.
- ///
- /// This allows for handling fixed type argument in case of inlining. For
- /// instance, checking `'foo'` against `String` instead of `T` in `main`:
- ///
- /// class Foo<T> {
- /// T field;
- /// Foo(this.field);
- /// }
- /// main() {
- /// new Foo<String>('foo');
- /// }
- ///
- /// [instanceType] is not used if it contains type variables, since these
- /// might not be in scope or from the current instance.
- ///
- final InterfaceType instanceType;
-
- SourceInformationBuilder get sourceInformationBuilder {
- return builder.sourceInformationBuilder;
- }
-
- LocalsHandler(
- this.builder, this.executableContext, InterfaceType instanceType)
- : this.instanceType = instanceType == null ||
- instanceType.containsTypeVariables ? null : instanceType;
-
- /// Substituted type variables occurring in [type] into the context of
- /// [contextClass].
- DartType substInContext(DartType type) {
- if (contextClass != null) {
- ClassElement typeContext = Types.getClassContext(type);
- if (typeContext != null) {
- type = type.substByContext(contextClass.asInstanceOf(typeContext));
- }
- }
- if (instanceType != null) {
- type = type.substByContext(instanceType);
- }
- return type;
- }
-
- get typesTask => builder.compiler.typesTask;
-
- /**
- * Creates a new [LocalsHandler] based on [other]. We only need to
- * copy the [directLocals], since the other fields can be shared
- * throughout the AST visit.
- */
- LocalsHandler.from(LocalsHandler other)
- : directLocals = new Map<Local, HInstruction>.from(other.directLocals),
- redirectionMapping = other.redirectionMapping,
- executableContext = other.executableContext,
- instanceType = other.instanceType,
- builder = other.builder,
- closureData = other.closureData;
-
- /**
- * 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, CapturedVariable to) {
- assert(redirectionMapping[from] == null);
- redirectionMapping[from] = to;
- assert(isStoredInClosureField(from) || isBoxed(from));
- }
-
- HInstruction createBox() {
- // TODO(floitsch): Clean up this hack. Should we create a box-object by
- // just creating an empty object literal?
- JavaScriptBackend backend = builder.backend;
- HInstruction box = new HForeignCode(
- js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[],
- nativeBehavior: native.NativeBehavior.PURE_ALLOCATION);
- builder.add(box);
- return box;
- }
-
- /**
- * If the scope (function or loop) [node] has captured variables then this
- * method creates a box and sets up the redirections.
- */
- void enterScope(ast.Node node, Element element) {
- // See if any variable in the top-scope of the function is captured. If yes
- // we need to create a box-object.
- ClosureScope scopeData = closureData.capturingScopes[node];
- if (scopeData == null) return;
- HInstruction box;
- // The scope has captured variables.
- if (element != null && element.isGenerativeConstructorBody) {
- // The box is passed as a parameter to a generative
- // constructor body.
- JavaScriptBackend backend = builder.backend;
- box = builder.addParameter(scopeData.boxElement, backend.nonNullType);
- } else {
- box = createBox();
- }
- // Add the box to the known locals.
- directLocals[scopeData.boxElement] = 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.
- scopeData.forEachCapturedVariable(
- (LocalVariableElement from, BoxFieldElement to) {
- // The [from] can only be a parameter for function-scopes and not
- // loop scopes.
- if (from.isRegularParameter && !element.isGenerativeConstructorBody) {
- // Now that the redirection is set up, the update to the local will
- // write the parameter value into the box.
- // Store the captured parameter in the box. Get the current value
- // before we put the redirection in place.
- // We don't need to update the local for a generative
- // constructor body, because it receives a box that already
- // contains the updates as the last parameter.
- HInstruction instruction = readLocal(from);
- redirectElement(from, to);
- updateLocal(from, instruction);
- } else {
- redirectElement(from, to);
- }
- });
- }
-
- /**
- * Replaces the current box with a new box and copies over the given list
- * of elements from the old box into the new box.
- */
- void updateCaptureBox(
- BoxLocal boxElement, List<LocalVariableElement> toBeCopiedElements) {
- // Create a new box and copy over the values from the old box into the
- // new one.
- HInstruction oldBox = readLocal(boxElement);
- HInstruction newBox = createBox();
- for (LocalVariableElement boxedVariable in toBeCopiedElements) {
- // [readLocal] uses the [boxElement] to find its box. By replacing it
- // behind its back we can still get to the old values.
- updateLocal(boxElement, oldBox);
- HInstruction oldValue = readLocal(boxedVariable);
- updateLocal(boxElement, newBox);
- updateLocal(boxedVariable, oldValue);
- }
- updateLocal(boxElement, newBox);
- }
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [function] must be an implementation element.
- */
- void startFunction(AstElement element, ast.Node node) {
- assert(invariant(element, element.isImplementation));
- Compiler compiler = builder.compiler;
- closureData = compiler.closureToClassMapper
- .computeClosureToClassMapping(element.resolvedAst);
-
- if (element is FunctionElement) {
- FunctionElement functionElement = element;
- FunctionSignature params = functionElement.functionSignature;
- ClosureScope scopeData = closureData.capturingScopes[node];
- params.orderedForEachParameter((ParameterElement parameterElement) {
- if (element.isGenerativeConstructorBody) {
- if (scopeData != null &&
- scopeData.isCapturedVariable(parameterElement)) {
- // The parameter will be a field in the box passed as the
- // last parameter. So no need to have it.
- return;
- }
- }
- HInstruction parameter = builder.addParameter(parameterElement,
- TypeMaskFactory.inferredTypeForElement(parameterElement, compiler));
- builder.parameters[parameterElement] = parameter;
- directLocals[parameterElement] = parameter;
- });
- }
-
- enterScope(node, element);
-
- // 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, CapturedVariable to) {
- redirectElement(from, to);
- });
- JavaScriptBackend backend = compiler.backend;
- if (closureData.isClosure) {
- // Inside closure redirect references to itself to [:this:].
- HThis thisInstruction =
- new HThis(closureData.thisLocal, backend.nonNullType);
- builder.graph.thisInstruction = thisInstruction;
- builder.graph.entry.addAtEntry(thisInstruction);
- updateLocal(closureData.closureElement, 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
- // context.
- HThis thisInstruction =
- new HThis(closureData.thisLocal, builder.getTypeOfThis());
- builder.graph.thisInstruction = thisInstruction;
- builder.graph.entry.addAtEntry(thisInstruction);
- directLocals[closureData.thisLocal] = thisInstruction;
- }
-
- // If this method is an intercepted method, add the extra
- // parameter to it, that is the actual receiver for intercepted
- // classes, or the same as [:this:] for non-intercepted classes.
- ClassElement cls = element.enclosingClass;
-
- // When the class extends a native class, the instance is pre-constructed
- // and passed to the generative constructor factory function as a parameter.
- // Instead of allocating and initializing the object, the constructor
- // 'upgrades' the native subclass object by initializing the Dart fields.
- bool isNativeUpgradeFactory =
- element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls);
- if (backend.isInterceptedMethod(element)) {
- bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
- String name = isInterceptorClass ? 'receiver' : '_';
- SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
- HParameterValue value =
- new HParameterValue(parameter, builder.getTypeOfThis());
- builder.graph.explicitReceiverParameter = value;
- builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value);
- if (builder.lastAddedParameter == null) {
- // If this is the first parameter inserted, make sure it stays first.
- builder.lastAddedParameter = value;
- }
- if (isInterceptorClass) {
- // Only use the extra parameter in intercepted classes.
- directLocals[closureData.thisLocal] = value;
- }
- } else if (isNativeUpgradeFactory) {
- SyntheticLocal parameter =
- new SyntheticLocal('receiver', executableContext);
- // Unlike `this`, receiver is nullable since direct calls to generative
- // constructor call the constructor with `null`.
- ClassWorld classWorld = compiler.world;
- HParameterValue value =
- new HParameterValue(parameter, new TypeMask.exact(cls, classWorld));
- builder.graph.explicitReceiverParameter = value;
- builder.graph.entry.addAtEntry(value);
- }
- }
-
- /**
- * Returns true if the local can be accessed directly. Boxed variables or
- * captured variables that are stored in the closure-field return [:false:].
- */
- bool isAccessedDirectly(Local local) {
- assert(local != null);
- return !redirectionMapping.containsKey(local) &&
- !closureData.variablesUsedInTryOrGenerator.contains(local);
- }
-
- bool isStoredInClosureField(Local local) {
- assert(local != null);
- if (isAccessedDirectly(local)) return false;
- CapturedVariable redirectTarget = redirectionMapping[local];
- if (redirectTarget == null) return false;
- return redirectTarget is ClosureFieldElement;
- }
-
- bool isBoxed(Local local) {
- if (isAccessedDirectly(local)) return false;
- if (isStoredInClosureField(local)) return false;
- return redirectionMapping.containsKey(local);
- }
-
- bool isUsedInTryOrGenerator(Local local) {
- return closureData.variablesUsedInTryOrGenerator.contains(local);
- }
-
- /**
- * Returns an [HInstruction] for the given element. If the element is
- * boxed or stored in a closure then the method generates code to retrieve
- * the value.
- */
- HInstruction readLocal(Local local, {SourceInformation sourceInformation}) {
- if (isAccessedDirectly(local)) {
- if (directLocals[local] == null) {
- if (local is TypeVariableElement) {
- builder.reporter.internalError(builder.compiler.currentElement,
- "Runtime type information not available for $local.");
- } else {
- builder.reporter.internalError(
- local, "Cannot find value $local in ${directLocals.keys}.");
- }
- }
- HInstruction value = directLocals[local];
- if (sourceInformation != null) {
- value = new HRef(value, sourceInformation);
- builder.add(value);
- }
- return value;
- } else if (isStoredInClosureField(local)) {
- ClosureFieldElement redirect = redirectionMapping[local];
- HInstruction receiver = readLocal(closureData.closureElement);
- TypeMask type = local is BoxLocal
- ? builder.backend.nonNullType
- : builder.getTypeOfCapturedVariable(redirect);
- HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
- builder.add(fieldGet);
- return fieldGet..sourceInformation = sourceInformation;
- } else if (isBoxed(local)) {
- BoxFieldElement redirect = redirectionMapping[local];
- // In the function that declares the captured variable the box is
- // accessed as direct local. Inside the nested closure the box is
- // accessed through a closure-field.
- // Calling [readLocal] makes sure we generate the correct code to get
- // the box.
- HInstruction box = readLocal(redirect.box);
- HInstruction lookup = new HFieldGet(
- redirect, box, builder.getTypeOfCapturedVariable(redirect));
- builder.add(lookup);
- return lookup..sourceInformation = sourceInformation;
- } else {
- assert(isUsedInTryOrGenerator(local));
- HLocalValue localValue = getLocal(local);
- HInstruction instruction = new HLocalGet(
- local, localValue, builder.backend.dynamicType, sourceInformation);
- builder.add(instruction);
- return instruction;
- }
- }
-
- HInstruction readThis() {
- HInstruction res = readLocal(closureData.thisLocal);
- if (res.instructionType == null) {
- res.instructionType = builder.getTypeOfThis();
- }
- return res;
- }
-
- HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) {
- // If the element is a parameter, we already have a
- // HParameterValue for it. We cannot create another one because
- // it could then have another name than the real parameter. And
- // the other one would not know it is just a copy of the real
- // parameter.
- if (local is ParameterElement) {
- assert(invariant(local, builder.parameters.containsKey(local),
- message: "No local value for parameter $local in "
- "${builder.parameters}."));
- return builder.parameters[local];
- }
-
- return builder.activationVariables.putIfAbsent(local, () {
- JavaScriptBackend backend = builder.backend;
- HLocalValue localValue = new HLocalValue(local, backend.nonNullType)
- ..sourceInformation = sourceInformation;
- builder.graph.entry.addAtExit(localValue);
- return localValue;
- });
- }
-
- Local getTypeVariableAsLocal(TypeVariableType type) {
- return typeVariableLocals.putIfAbsent(type, () {
- return new TypeVariableLocal(type, executableContext);
- });
- }
-
- /**
- * Sets the [element] to [value]. If the element is boxed or stored in a
- * closure then the method generates code to set the value.
- */
- void updateLocal(Local local, HInstruction value,
- {SourceInformation sourceInformation}) {
- if (value is HRef) {
- HRef ref = value;
- value = ref.value;
- }
- assert(!isStoredInClosureField(local));
- if (isAccessedDirectly(local)) {
- directLocals[local] = value;
- } else if (isBoxed(local)) {
- BoxFieldElement redirect = redirectionMapping[local];
- // The box itself could be captured, or be local. A local variable that
- // is captured will be boxed, but the box itself will be a local.
- // Inside the closure the box is stored in a closure-field and cannot
- // be accessed directly.
- HInstruction box = readLocal(redirect.box);
- builder.add(new HFieldSet(redirect, box, value)
- ..sourceInformation = sourceInformation);
- } else {
- assert(isUsedInTryOrGenerator(local));
- HLocalValue localValue = getLocal(local);
- builder.add(new HLocalSet(local, localValue, value)
- ..sourceInformation = sourceInformation);
- }
- }
-
- /**
- * This function, startLoop, must be called before visiting any children of
- * the loop. In particular it needs to be called before executing the
- * initializers.
- *
- * The [LocalsHandler] will make the boxes and updates at the right moment.
- * The builder just needs to call [enterLoopBody] and [enterLoopUpdates]
- * (for [ast.For] loops) at the correct places. For phi-handling
- * [beginLoopHeader] and [endLoop] must also be called.
- *
- * The correct place for the box depends on the given loop. In most cases
- * the box will be created when entering the loop-body: while, do-while, and
- * for-in (assuming the call to [:next:] is inside the body) can always be
- * constructed this way.
- *
- * Things are slightly more complicated for [ast.For] loops. If no declared
- * loop variable is boxed then the loop-body approach works here too. If a
- * loop-variable is boxed we need to introduce a new box for the
- * loop-variable before we enter the initializer so that the initializer
- * writes the values into the box. In any case we need to create the box
- * before the condition since the condition could box the variable.
- * Since the first box is created outside the actual loop we have a second
- * location where a box is created: just before the updates. This is
- * necessary since updates are considered to be part of the next iteration
- * (and can again capture variables).
- *
- * For example the following Dart code prints 1 3 -- 3 4.
- *
- * var fs = [];
- * for (var i = 0; i < 3; (f() { fs.add(f); print(i); i++; })()) {
- * i++;
- * }
- * print("--");
- * for (var i = 0; i < 2; i++) fs[i]();
- *
- * We solve this by emitting the following code (only for [ast.For] loops):
- * <Create box> <== move the first box creation outside the loop.
- * <initializer>;
- * loop-entry:
- * if (!<condition>) goto loop-exit;
- * <body>
- * <update box> // create a new box and copy the captured loop-variables.
- * <updates>
- * goto loop-entry;
- * loop-exit:
- */
- void startLoop(ast.Node node) {
- ClosureScope scopeData = closureData.capturingScopes[node];
- if (scopeData == null) return;
- if (scopeData.hasBoxedLoopVariables()) {
- // If there are boxed loop variables then we set up the box and
- // redirections already now. This way the initializer can write its
- // values into the box.
- // For other loops the box will be created when entering the body.
- enterScope(node, null);
- }
- }
-
- /**
- * Create phis at the loop entry for local variables (ready for the values
- * from the back edge). Populate the phis with the current values.
- */
- void beginLoopHeader(HBasicBlock loopEntry) {
- // Create a copy because we modify the map while iterating over it.
- Map<Local, HInstruction> savedDirectLocals =
- new Map<Local, HInstruction>.from(directLocals);
-
- JavaScriptBackend backend = builder.backend;
- // Create phis for all elements in the definitions environment.
- savedDirectLocals.forEach((Local local, HInstruction instruction) {
- if (isAccessedDirectly(local)) {
- // We know 'this' cannot be modified.
- if (local != closureData.thisLocal) {
- HPhi phi =
- new HPhi.singleInput(local, instruction, backend.dynamicType);
- loopEntry.addPhi(phi);
- directLocals[local] = phi;
- } else {
- directLocals[local] = instruction;
- }
- }
- });
- }
-
- void enterLoopBody(ast.Node node) {
- ClosureScope scopeData = closureData.capturingScopes[node];
- if (scopeData == null) return;
- // If there are no declared boxed loop variables then we did not create the
- // box before the initializer and we have to create the box now.
- if (!scopeData.hasBoxedLoopVariables()) {
- enterScope(node, null);
- }
- }
-
- void enterLoopUpdates(ast.Node node) {
- // If there are declared boxed loop variables then the updates might have
- // access to the box and we must switch to a new box before executing the
- // updates.
- // In all other cases a new box will be created when entering the body of
- // the next iteration.
- ClosureScope scopeData = closureData.capturingScopes[node];
- if (scopeData == null) return;
- if (scopeData.hasBoxedLoopVariables()) {
- updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables);
- }
- }
-
- /**
- * Goes through the phis created in beginLoopHeader entry and adds the
- * input from the back edge (from the current value of directLocals) to them.
- */
- void endLoop(HBasicBlock loopEntry) {
- // If the loop has an aborting body, we don't update the loop
- // phis.
- if (loopEntry.predecessors.length == 1) return;
- loopEntry.forEachPhi((HPhi phi) {
- Local element = phi.sourceElement;
- HInstruction postLoopDefinition = directLocals[element];
- phi.addInput(postLoopDefinition);
- });
- }
-
- /**
- * Merge [otherLocals] into this locals handler, creating phi-nodes when
- * there is a conflict.
- * If a phi node is necessary, it will use this handler's instruction as the
- * first input, and the otherLocals instruction as the second.
- */
- void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) {
- // If an element is in one map but not the other we can safely
- // ignore it. It means that a variable was declared in the
- // block. Since variable declarations are scoped the declared
- // variable cannot be alive outside the block. Note: this is only
- // true for nodes where we do joins.
- Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
- JavaScriptBackend backend = builder.backend;
- otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
- // We know 'this' cannot be modified.
- if (local == closureData.thisLocal) {
- assert(directLocals[local] == instruction);
- joinedLocals[local] = instruction;
- } else {
- HInstruction mine = directLocals[local];
- if (mine == null) return;
- if (identical(instruction, mine)) {
- joinedLocals[local] = instruction;
- } else {
- HInstruction phi = new HPhi.manyInputs(
- local, <HInstruction>[mine, instruction], backend.dynamicType);
- joinBlock.addPhi(phi);
- joinedLocals[local] = phi;
- }
- }
- });
- directLocals = joinedLocals;
- }
-
- /**
- * When control flow merges, this method can be used to merge several
- * localsHandlers into a new one using phis. The new localsHandler is
- * returned. Unless it is also in the list, the current localsHandler is not
- * used for its values, only for its declared variables. This is a way to
- * exclude local values from the result when they are no longer in scope.
- */
- LocalsHandler mergeMultiple(
- List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) {
- assert(localsHandlers.length > 0);
- if (localsHandlers.length == 1) return localsHandlers[0];
- Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
- HInstruction thisValue = null;
- JavaScriptBackend backend = builder.backend;
- directLocals.forEach((Local local, HInstruction instruction) {
- if (local != closureData.thisLocal) {
- HPhi phi = new HPhi.noInputs(local, backend.dynamicType);
- joinedLocals[local] = phi;
- joinBlock.addPhi(phi);
- } else {
- // We know that "this" never changes, if it's there.
- // Save it for later. While merging, there is no phi for "this",
- // so we don't have to special case it in the merge loop.
- thisValue = instruction;
- }
- });
- for (LocalsHandler handler in localsHandlers) {
- handler.directLocals.forEach((Local local, HInstruction instruction) {
- HPhi phi = joinedLocals[local];
- if (phi != null) {
- phi.addInput(instruction);
- }
- });
- }
- if (thisValue != null) {
- // If there was a "this" for the scope, add it to the new locals.
- joinedLocals[closureData.thisLocal] = thisValue;
- }
-
- // Remove locals that are not in all handlers.
- directLocals = new Map<Local, HInstruction>();
- joinedLocals.forEach((Local local, HInstruction instruction) {
- if (local != closureData.thisLocal &&
- instruction.inputs.length != localsHandlers.length) {
- joinBlock.removePhi(instruction);
- } else {
- directLocals[local] = instruction;
- }
- });
- return this;
- }
-}
-
// Represents a single break/continue instruction.
class JumpHandlerEntry {
final HJump jumpInstruction;
@@ -1040,20 +415,8 @@ class SsaBuilder extends ast.Visitor
HInstruction rethrowableException;
- HParameterValue lastAddedParameter;
-
- Map<ParameterElement, HInstruction> parameters =
- <ParameterElement, HInstruction>{};
-
Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{};
- /**
- * Variables stored in the current activation. These variables are
- * being updated in try/catch blocks, and should be
- * accessed indirectly through [HLocalGet] and [HLocalSet].
- */
- Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{};
-
// We build the Ssa graph by simulating a stack machine.
List<HInstruction> stack = <HInstruction>[];
@@ -1080,12 +443,12 @@ class SsaBuilder extends ast.Visitor
this.rti = backend.rti {
assert(target.isImplementation);
graph.element = target;
- localsHandler = new LocalsHandler(this, target, null);
sourceElementStack.add(target);
sourceInformationBuilder =
sourceInformationFactory.createBuilderForContext(resolvedAst);
graph.sourceInformation =
sourceInformationBuilder.buildVariableDeclaration();
+ localsHandler = new LocalsHandler(this, target, null, compiler);
}
BackendHelpers get helpers => backend.helpers;
@@ -1488,7 +851,7 @@ class SsaBuilder extends ast.Visitor
/**
* Return null so it is simple to remove the optional parameters completely
- * from interop methods to match JavaScript semantics for ommitted arguments.
+ * from interop methods to match JavaScript semantics for omitted arguments.
*/
HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
null;
@@ -1538,38 +901,6 @@ class SsaBuilder extends ast.Visitor
return graph.addConstant(getConstantForNode(node), compiler);
}
- TypeMask cachedTypeOfThis;
-
- TypeMask getTypeOfThis() {
- TypeMask result = cachedTypeOfThis;
- if (result == null) {
- ThisLocal local = localsHandler.closureData.thisLocal;
- ClassElement cls = local.enclosingClass;
- ClassWorld classWorld = compiler.world;
- if (classWorld.isUsedAsMixin(cls)) {
- // If the enclosing class is used as a mixin, [:this:] can be
- // of the class that mixins the enclosing class. These two
- // classes do not have a subclass relationship, so, for
- // simplicity, we mark the type as an interface type.
- result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world);
- } else {
- result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world);
- }
- cachedTypeOfThis = result;
- }
- return result;
- }
-
- Map<Element, TypeMask> cachedTypesOfCapturedVariables =
- new Map<Element, TypeMask>();
-
- TypeMask getTypeOfCapturedVariable(Element element) {
- assert(element.isField);
- return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
- return TypeMaskFactory.inferredTypeForElement(element, compiler);
- });
- }
-
/**
* Documentation wanted -- johnniwinther
*
@@ -1716,18 +1047,6 @@ class SsaBuilder extends ast.Visitor
return bodyElement;
}
- HParameterValue addParameter(Entity parameter, TypeMask type) {
- assert(inliningStack.isEmpty);
- HParameterValue result = new HParameterValue(parameter, type);
- if (lastAddedParameter == null) {
- graph.entry.addBefore(graph.entry.first, result);
- } else {
- graph.entry.addAfter(lastAddedParameter, result);
- }
- lastAddedParameter = result;
- return result;
- }
-
/**
* This method sets up the local state of the builder for inlining [function].
* The arguments of the function are inserted into the [localsHandler].
@@ -1742,7 +1061,7 @@ class SsaBuilder extends ast.Visitor
{InterfaceType instanceType}) {
ResolvedAst resolvedAst = function.resolvedAst;
assert(resolvedAst != null);
- localsHandler = new LocalsHandler(this, function, instanceType);
+ localsHandler = new LocalsHandler(this, function, instanceType, compiler);
localsHandler.closureData =
compiler.closureToClassMapper.computeClosureToClassMapping(resolvedAst);
returnLocal = new SyntheticLocal("result", function);
@@ -5540,8 +4859,10 @@ class SsaBuilder extends ast.Visitor
// Native behavior effects here are similar to native/behavior.dart.
// The return type is dynamic if we don't trust js-interop type
// declarations.
- nativeBehavior.typesReturned.add(compiler
- .options.trustJSInteropTypeAnnotations ? type : const DynamicType());
+ nativeBehavior.typesReturned.add(
+ compiler.options.trustJSInteropTypeAnnotations
+ ? type
+ : const DynamicType());
// The allocation effects include the declared type if it is native (which
// includes js interop types).
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/builder_kernel.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698