Compute Compiler.proxyConstant on demand.
BUG= R=karlklose@google.com Review URL: https://codereview.chromium.org//1334203002.
This commit is contained in:
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user