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

Unified Diff: sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
deleted file mode 100644
index 3f177585739f3ec76c88b6ccd710f2b72619b2a9..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright (c) 2013, 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.
-
-part of ssa;
-
-/**
- * This phase simplifies interceptors in multiple ways:
- *
- * 1) If the interceptor is for an object whose type is known, it
- * tries to use a constant interceptor instead.
- *
- * 2) It specializes interceptors based on the selectors it is being
- * called with.
- *
- * 3) If we know the object is not intercepted, we just use it
- * instead.
- *
- * 4) It replaces all interceptors that are used only once with
- * one-shot interceptors. It saves code size and makes the receiver of
- * an intercepted call a candidate for being generated at use site.
- *
- */
-class SsaSimplifyInterceptors extends HBaseVisitor
- implements OptimizationPhase {
- final String name = "SsaSimplifyInterceptors";
- final ConstantSystem constantSystem;
- final Compiler compiler;
- final CodegenWorkItem work;
- HGraph graph;
-
- SsaSimplifyInterceptors(this.compiler, this.constantSystem, this.work);
-
- void visitGraph(HGraph graph) {
- this.graph = graph;
- visitDominatorTree(graph);
- }
-
- void visitBasicBlock(HBasicBlock node) {
- currentBlock = node;
-
- HInstruction instruction = node.first;
- while (instruction != null) {
- bool shouldRemove = instruction.accept(this);
- HInstruction next = instruction.next;
- if (shouldRemove) {
- instruction.block.remove(instruction);
- }
- instruction = next;
- }
- }
-
- bool visitInstruction(HInstruction instruction) => false;
-
- bool visitInvoke(HInvoke invoke) {
- if (!invoke.isInterceptedCall) return false;
- var interceptor = invoke.inputs[0];
- if (interceptor is! HInterceptor) return false;
- HInstruction constant = tryComputeConstantInterceptor(
- invoke.inputs[1], interceptor.interceptedClasses);
- if (constant != null) {
- invoke.changeUse(interceptor, constant);
- }
- return false;
- }
-
- bool canUseSelfForInterceptor(HInstruction receiver,
- Set<ClassElement> interceptedClasses) {
- JavaScriptBackend backend = compiler.backend;
- ClassWorld classWorld = compiler.world;
-
- if (receiver.canBePrimitive(compiler)) {
- // Primitives always need interceptors.
- return false;
- }
- if (receiver.canBeNull() &&
- interceptedClasses.contains(backend.jsNullClass)) {
- // Need the JSNull interceptor.
- return false;
- }
-
- // All intercepted classes extend `Interceptor`, so if the receiver can't be
- // a class extending `Interceptor` then it can be called directly.
- return new TypeMask.nonNullSubclass(backend.jsInterceptorClass, classWorld)
- .intersection(receiver.instructionType, classWorld)
- .isEmpty;
- }
-
- HInstruction tryComputeConstantInterceptor(
- HInstruction input,
- Set<ClassElement> interceptedClasses) {
- if (input == graph.explicitReceiverParameter) {
- // If `explicitReceiverParameter` is set it means the current method is an
- // interceptor method, and `this` is the interceptor. The caller just did
- // `getInterceptor(foo).currentMethod(foo)` to enter the current method.
- return graph.thisInstruction;
- }
-
- ClassElement constantInterceptor;
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- if (input.canBeNull()) {
- if (input.isNull()) {
- constantInterceptor = backend.jsNullClass;
- }
- } else if (input.isInteger(compiler)) {
- constantInterceptor = backend.jsIntClass;
- } else if (input.isDouble(compiler)) {
- constantInterceptor = backend.jsDoubleClass;
- } else if (input.isBoolean(compiler)) {
- constantInterceptor = backend.jsBoolClass;
- } else if (input.isString(compiler)) {
- constantInterceptor = backend.jsStringClass;
- } else if (input.isArray(compiler)) {
- constantInterceptor = backend.jsArrayClass;
- } else if (input.isNumber(compiler) &&
- !interceptedClasses.contains(backend.jsIntClass) &&
- !interceptedClasses.contains(backend.jsDoubleClass)) {
- // If the method being intercepted is not defined in [int] or [double] we
- // can safely use the number interceptor. This is because none of the
- // [int] or [double] methods are called from a method defined on [num].
- constantInterceptor = backend.jsNumberClass;
- } else {
- // Try to find constant interceptor for a native class. If the receiver
- // is constrained to a leaf native class, we can use the class's
- // interceptor directly.
-
- // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
- // classes. When the receiver type is not a leaf class, we might still be
- // able to use the receiver class as a constant interceptor. It is
- // usually the case that methods defined on a non-leaf class don't test
- // for a subclass or call methods defined on a subclass. Provided the
- // code is completely insensitive to the specific instance subclasses, we
- // can use the non-leaf class directly.
- ClassElement element = input.instructionType.singleClass(classWorld);
- if (element != null && element.isNative) {
- constantInterceptor = element;
- }
- }
-
- if (constantInterceptor == null) return null;
-
- // If we just happen to be in an instance method of the constant
- // interceptor, `this` is a shorter alias.
- if (constantInterceptor == work.element.enclosingClass &&
- graph.thisInstruction != null) {
- return graph.thisInstruction;
- }
-
- ConstantValue constant =
- new InterceptorConstantValue(constantInterceptor.thisType);
- return graph.addConstant(constant, compiler);
- }
-
- HInstruction findDominator(Iterable<HInstruction> instructions) {
- HInstruction result;
- L1: for (HInstruction candidate in instructions) {
- for (HInstruction current in instructions) {
- if (current != candidate && !candidate.dominates(current)) continue L1;
- }
- result = candidate;
- break;
- }
- return result;
- }
-
- bool visitInterceptor(HInterceptor node) {
- if (node.isConstant()) return false;
-
- // Specialize the interceptor with set of classes it intercepts, considering
- // all uses. (The specialized interceptor has a shorter dispatch chain).
- // This operation applies only where the interceptor is used to dispatch a
- // method. Other uses, e.g. as an ordinary argument or a HIs check use the
- // most general interceptor.
- //
- // TODO(sra): Take into account the receiver type at each call. e.g:
- //
- // (a) => a.length + a.hashCode
- //
- // Currently we use the most general interceptor since all intercepted types
- // implement `hashCode`. But in this example, `a.hashCode` is only reached
- // if `a.length` succeeds, which is indicated by the hashCode receiver being
- // a HTypeKnown instruction.
-
- int useCount(HInstruction user, HInstruction used) =>
- user.inputs.where((input) => input == used).length;
-
- Set<ClassElement> interceptedClasses;
- JavaScriptBackend backend = compiler.backend;
- HInstruction dominator = findDominator(node.usedBy);
- // If there is a call that dominates all other uses, we can use just the
- // selector of that instruction.
- if (dominator is HInvokeDynamic &&
- dominator.isCallOnInterceptor(compiler) &&
- node == dominator.receiver &&
- useCount(dominator, node) == 1) {
- interceptedClasses =
- backend.getInterceptedClassesOn(dominator.selector.name);
-
- // If we found that we need number, we must still go through all
- // uses to check if they require int, or double.
- if (interceptedClasses.contains(backend.jsNumberClass) &&
- !(interceptedClasses.contains(backend.jsDoubleClass) ||
- interceptedClasses.contains(backend.jsIntClass))) {
- for (HInstruction user in node.usedBy) {
- if (user is! HInvoke) continue;
- Set<ClassElement> intercepted =
- backend.getInterceptedClassesOn(user.selector.name);
- if (intercepted.contains(backend.jsIntClass)) {
- interceptedClasses.add(backend.jsIntClass);
- }
- if (intercepted.contains(backend.jsDoubleClass)) {
- interceptedClasses.add(backend.jsDoubleClass);
- }
- }
- }
- } else {
- interceptedClasses = new Set<ClassElement>();
- for (HInstruction user in node.usedBy) {
- if (user is HInvokeDynamic &&
- user.isCallOnInterceptor(compiler) &&
- node == user.receiver &&
- useCount(user, node) == 1) {
- interceptedClasses.addAll(
- backend.getInterceptedClassesOn(user.selector.name));
- } else if (user is HInvokeSuper &&
- user.isCallOnInterceptor(compiler) &&
- node == user.receiver &&
- useCount(user, node) == 1) {
- interceptedClasses.addAll(
- backend.getInterceptedClassesOn(user.selector.name));
- } else {
- // Use a most general interceptor for other instructions, example,
- // is-checks and escaping interceptors.
- interceptedClasses.addAll(backend.interceptedClasses);
- break;
- }
- }
- }
-
- HInstruction receiver = node.receiver;
-
- if (canUseSelfForInterceptor(receiver, interceptedClasses)) {
- return rewriteToUseSelfAsInterceptor(node, receiver);
- }
-
- // Try computing a constant interceptor.
- HInstruction constantInterceptor =
- tryComputeConstantInterceptor(receiver, interceptedClasses);
- if (constantInterceptor != null) {
- node.block.rewrite(node, constantInterceptor);
- return false;
- }
-
- node.interceptedClasses = interceptedClasses;
-
- // Try creating a one-shot interceptor.
- if (node.usedBy.length != 1) return false;
- if (node.usedBy[0] is !HInvokeDynamic) return false;
-
- HInvokeDynamic user = node.usedBy[0];
-
- // If [node] was loop hoisted, we keep the interceptor.
- if (!user.hasSameLoopHeaderAs(node)) return false;
-
- // Replace the user with a [HOneShotInterceptor].
- HConstant nullConstant = graph.addConstantNull(compiler);
- List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
- inputs[0] = nullConstant;
- HOneShotInterceptor interceptor = new HOneShotInterceptor(
- user.selector, inputs, user.instructionType, node.interceptedClasses);
- interceptor.sourcePosition = user.sourcePosition;
- interceptor.sourceElement = user.sourceElement;
-
- HBasicBlock block = user.block;
- block.addAfter(user, interceptor);
- block.rewrite(user, interceptor);
- block.remove(user);
- return true;
- }
-
- bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) {
- for (HInstruction user in node.usedBy.toList()) {
- if (user is HIs) {
- user.changeUse(node, receiver);
- } else {
- // Use the potentially self-argument as new receiver. Note that the
- // self-argument could potentially have a tighter type than the
- // receiver which was the input to the interceptor.
- assert(user.inputs[0] == node);
- assert(receiver.nonCheck() == user.inputs[1].nonCheck());
- user.changeUse(node, user.inputs[1]);
- }
- }
- return false;
- }
-
- bool visitOneShotInterceptor(HOneShotInterceptor node) {
- HInstruction constant = tryComputeConstantInterceptor(
- node.inputs[1], node.interceptedClasses);
-
- if (constant == null) return false;
-
- Selector selector = node.selector;
- HInstruction instruction;
- if (selector.isGetter) {
- instruction = new HInvokeDynamicGetter(
- selector,
- node.element,
- <HInstruction>[constant, node.inputs[1]],
- node.instructionType);
- } else if (selector.isSetter) {
- instruction = new HInvokeDynamicSetter(
- selector,
- node.element,
- <HInstruction>[constant, node.inputs[1], node.inputs[2]],
- node.instructionType);
- } else {
- List<HInstruction> inputs = new List<HInstruction>.from(node.inputs);
- inputs[0] = constant;
- instruction = new HInvokeDynamicMethod(
- selector, inputs, node.instructionType, true);
- }
-
- HBasicBlock block = node.block;
- block.addAfter(node, instruction);
- block.rewrite(node, instruction);
- return true;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698