Compute Compiler.proxyConstant on demand.

BUG=
R=karlklose@google.com

Review URL: https://codereview.chromium.org//1334203002.
This commit is contained in:
Johnni Winther
2015-09-11 14:47:49 +02:00
parent 7407a72115
commit bda5146f40
10 changed files with 146 additions and 38 deletions
@@ -114,4 +114,7 @@ class ResolutionCallbacks {
/// Called when resolving the `Symbol` constructor.
void onSymbolConstructor(Registry registry) {}
/// Called when resolving a prefix or postfix expression.
void onIncDecOperation(Registry registry) {}
}
+12 -5
View File
@@ -848,11 +848,6 @@ abstract class Compiler implements DiagnosticListener {
functionClass.ensureResolved(this);
functionApplyMethod = functionClass.lookupLocalMember('apply');
proxyConstant =
constants.getConstantValue(
resolver.constantCompiler.compileConstant(
coreLibrary.find('proxy')));
if (preserveComments) {
return libraryLoader.loadLibrary(Uris.dart_mirrors)
.then((LibraryElement libraryElement) {
@@ -862,6 +857,18 @@ abstract class Compiler implements DiagnosticListener {
}).then((_) => backend.onLibrariesLoaded(loadedLibraries));
}
bool isProxyConstant(ConstantValue value) {
FieldElement field = coreLibrary.find('proxy');
if (field == null) return false;
if (!enqueuer.resolution.hasBeenResolved(field)) return false;
if (proxyConstant == null) {
proxyConstant =
constants.getConstantValue(
resolver.constantCompiler.compileConstant(field));
}
return proxyConstant == value;
}
Element findRequiredElement(LibraryElement library, String name) {
var element = library.find(name);
if (element == null) {
+35 -5
View File
@@ -2991,6 +2991,7 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
registerBackendInstantiation(backend.compiler.listClass, registry);
registerBackendStaticInvocation(backend.getRuntimeTypeToString(), registry);
registerBackendStaticInvocation(backend.getCreateRuntimeType(), registry);
needsInt(registry, 'Needed for accessing a type variable literal on this.');
}
// TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
@@ -3051,7 +3052,7 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
registerBackendStaticInvocation(
backend.getThrowAbstractClassInstantiationError(), registry);
// Also register the types of the arguments passed to this method.
registerBackendInstantiation(backend.compiler.stringClass, registry);
needsString(registry, '// Needed to encode the message.');
}
void onFallThroughError(Registry registry) {
@@ -3068,8 +3069,10 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
assert(registry.isForResolution);
registerBackendStaticInvocation(backend.getThrowNoSuchMethod(), registry);
// Also register the types of the arguments passed to this method.
registerBackendInstantiation(backend.compiler.listClass, registry);
registerBackendInstantiation(backend.compiler.stringClass, registry);
needsList(registry,
'Needed to encode the arguments for throw NoSuchMethodError.');
needsString(registry,
'Needed to encode the name for throw NoSuchMethodError.');
}
void onThrowRuntimeError(Registry registry) {
@@ -3094,8 +3097,12 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
backend.compiler.objectClass.lookupLocalMember(
Identifiers.noSuchMethod_),
registry);
registerBackendInstantiation(backend.compiler.listClass, registry);
registerBackendInstantiation(backend.compiler.stringClass, registry);
needsInt(registry,
'Needed to encode the invocation kind of super.noSuchMethod.');
needsList(registry,
'Needed to encode the arguments of super.noSuchMethod.');
needsString(registry,
'Needed to encode the name of super.noSuchMethod.');
}
void onMapLiteral(ResolutionRegistry registry,
@@ -3125,6 +3132,29 @@ class JavaScriptResolutionCallbacks extends ResolutionCallbacks {
registerBackendStaticInvocation(
backend.compiler.symbolValidatedConstructor, registry);
}
/// Called when resolving a prefix or postfix expression.
void onIncDecOperation(Registry registry) {
needsInt(registry, 'Needed for the `+ 1` or `- 1` operation of ++/--.');
}
/// Helper for registering that `int` is needed.
void needsInt(Registry registry, String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
registerBackendInstantiation(backend.compiler.intClass, registry);
}
/// Helper for registering that `List` is needed.
void needsList(Registry registry, String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
registerBackendInstantiation(backend.compiler.listClass, registry);
}
/// Helper for registering that `String` is needed.
void needsString(Registry registry, String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
registerBackendInstantiation(backend.compiler.stringClass, registry);
}
}
/// Records that [constant] is used by the element behind [registry].
@@ -3422,6 +3422,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
? new PrefixStructure(semantics, operator)
: new PostfixStructure(semantics, operator);
registry.registerSendStructure(node, sendStructure);
registry.registerIncDecOperation();
} else {
Node rhs = node.arguments.head;
visitExpression(rhs);
@@ -610,6 +610,10 @@ class ResolutionRegistry implements Registry {
backend.resolutionCallbacks.onAsyncForIn(node, this);
}
void registerIncDecOperation() {
backend.resolutionCallbacks.onIncDecOperation(this);
}
void registerTryStatement() {
mapping.containsTryStatement = true;
}
@@ -598,7 +598,7 @@ class ResolverTask extends CompilerTask {
metadata.ensureResolved(compiler);
ConstantValue value =
compiler.constants.getConstantValue(metadata.constant);
if (!element.isProxy && value == compiler.proxyConstant) {
if (!element.isProxy && compiler.isProxyConstant(value)) {
element.isProxy = true;
}
}
+1 -1
View File
@@ -2694,7 +2694,7 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor {
checkString(input, '!==', input.sourceInformation);
return pop();
}
compiler.internalError(input, 'Unexpected check.');
compiler.internalError(input, 'Unexpected check: $checkedType.');
return null;
}
+58 -24
View File
@@ -882,6 +882,32 @@ abstract class HInstruction implements Spannable {
return instructionType.isEmpty && !instructionType.isNullable;
}
/// Returns `true` if [typeMask] contains [cls].
static bool containsType(
TypeMask typeMask,
ClassElement cls,
ClassWorld classWorld) {
return classWorld.isInstantiated(cls) && typeMask.contains(cls, classWorld);
}
/// Returns `true` if [typeMask] contains only [cls].
static bool containsOnlyType(
TypeMask typeMask,
ClassElement cls,
ClassWorld classWorld) {
return classWorld.isInstantiated(cls) &&
typeMask.containsOnly(cls);
}
/// Returns `true` if [typeMask] is an instance of [cls].
static bool isInstanceOf(
TypeMask typeMask,
ClassElement cls,
ClassWorld classWorld) {
return classWorld.isInstantiated(cls) &&
typeMask.satisfies(cls, classWorld);
}
bool canBePrimitive(Compiler compiler) {
return canBePrimitiveNumber(compiler)
|| canBePrimitiveArray(compiler)
@@ -895,27 +921,28 @@ abstract class HInstruction implements Spannable {
JavaScriptBackend backend = compiler.backend;
// TODO(sra): It should be possible to test only jsDoubleClass and
// jsUInt31Class, since all others are superclasses of these two.
return instructionType.contains(backend.jsNumberClass, classWorld)
|| instructionType.contains(backend.jsIntClass, classWorld)
|| instructionType.contains(backend.jsPositiveIntClass, classWorld)
|| instructionType.contains(backend.jsUInt32Class, classWorld)
|| instructionType.contains(backend.jsUInt31Class, classWorld)
|| instructionType.contains(backend.jsDoubleClass, classWorld);
return containsType(instructionType, backend.jsNumberClass, classWorld)
|| containsType(instructionType, backend.jsIntClass, classWorld)
|| containsType(instructionType, backend.jsPositiveIntClass, classWorld)
|| containsType(instructionType, backend.jsUInt32Class, classWorld)
|| containsType(instructionType, backend.jsUInt31Class, classWorld)
|| containsType(instructionType, backend.jsDoubleClass, classWorld);
}
bool canBePrimitiveBoolean(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.contains(backend.jsBoolClass, classWorld);
return containsType(instructionType, backend.jsBoolClass, classWorld);
}
bool canBePrimitiveArray(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.contains(backend.jsArrayClass, classWorld)
|| instructionType.contains(backend.jsFixedArrayClass, classWorld)
|| instructionType.contains(backend.jsExtendableArrayClass, classWorld)
|| instructionType.contains(
return containsType(instructionType, backend.jsArrayClass, classWorld)
|| containsType(instructionType, backend.jsFixedArrayClass, classWorld)
|| containsType(
instructionType, backend.jsExtendableArrayClass, classWorld)
|| containsType(instructionType,
backend.jsUnmodifiableArrayClass, classWorld);
}
@@ -923,37 +950,43 @@ abstract class HInstruction implements Spannable {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.containsOnlyString(classWorld)
|| instructionType.satisfies(backend.jsIndexableClass, classWorld);
|| isInstanceOf(instructionType, backend.jsIndexableClass, classWorld);
}
bool isFixedArray(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
// TODO(sra): Recognize the union of these types as well.
return instructionType.containsOnly(backend.jsFixedArrayClass)
|| instructionType.containsOnly(backend.jsUnmodifiableArrayClass);
return containsOnlyType(
instructionType, backend.jsFixedArrayClass, classWorld)
|| containsOnlyType(
instructionType, backend.jsUnmodifiableArrayClass, classWorld);
}
bool isExtendableArray(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.containsOnly(backend.jsExtendableArrayClass);
return containsOnlyType(
instructionType, backend.jsExtendableArrayClass, classWorld);
}
bool isMutableArray(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.satisfies(backend.jsMutableArrayClass, classWorld);
return isInstanceOf(
instructionType, backend.jsMutableArrayClass, classWorld);
}
bool isReadableArray(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.satisfies(backend.jsArrayClass, classWorld);
return isInstanceOf(instructionType, backend.jsArrayClass, classWorld);
}
bool isMutableIndexable(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.satisfies(
return isInstanceOf(instructionType,
backend.jsMutableIndexableClass, classWorld);
}
@@ -962,7 +995,7 @@ abstract class HInstruction implements Spannable {
bool canBePrimitiveString(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.contains(backend.jsStringClass, classWorld);
return containsType(instructionType, backend.jsStringClass, classWorld);
}
bool isInteger(Compiler compiler) {
@@ -975,27 +1008,28 @@ abstract class HInstruction implements Spannable {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return !instructionType.isNullable
&& instructionType.satisfies(backend.jsUInt32Class, classWorld);
&& isInstanceOf(instructionType, backend.jsUInt32Class, classWorld);
}
bool isUInt31(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return !instructionType.isNullable
&& instructionType.satisfies(backend.jsUInt31Class, classWorld);
&& isInstanceOf(instructionType, backend.jsUInt31Class, classWorld);
}
bool isPositiveInteger(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return !instructionType.isNullable
&& instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
return !instructionType.isNullable &&
isInstanceOf(instructionType, backend.jsPositiveIntClass, classWorld);
}
bool isPositiveIntegerOrNull(Compiler compiler) {
ClassWorld classWorld = compiler.world;
JavaScriptBackend backend = compiler.backend;
return instructionType.satisfies(backend.jsPositiveIntClass, classWorld);
return isInstanceOf(
instructionType, backend.jsPositiveIntClass, classWorld);
}
bool isIntegerOrNull(Compiler compiler) {
+4 -2
View File
@@ -268,9 +268,11 @@ class SsaInstructionSimplifier extends HBaseVisitor
ClassWorld classWorld = compiler.world;
TypeMask resultType = backend.positiveIntType;
// If we already have computed a more specific type, keep that type.
if (actualType.satisfies(backend.jsUInt31Class, classWorld)) {
if (HInstruction.isInstanceOf(
actualType, backend.jsUInt31Class, classWorld)) {
resultType = backend.uint31Type;
} else if (actualType.satisfies(backend.jsUInt32Class, classWorld)) {
} else if (HInstruction.isInstanceOf(
actualType, backend.jsUInt32Class, classWorld)) {
resultType = backend.uint32Type;
}
HFieldGet result = new HFieldGet(
@@ -0,0 +1,27 @@
// Copyright (c) 2015, 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.
// Test that elements are not needlessly required by dart2js.
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:expect/expect.dart';
import 'memory_compiler.dart';
main() {
asyncTest(() async {
await analyze('main() {}');
await analyze('main() => proxy;', proxyConstant: true);
});
}
analyze(String code,
{bool proxyConstant: false}) async {
CompilationResult result = await runCompiler(
memorySourceFiles: {'main.dart': code},
options: ['--analyze-only']);
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
Expect.equals(proxyConstant, compiler.proxyConstant != null);
}