| Index: pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
|
| index 6036711be963411c17086727877199f0a92447d9..7b8e1eb03fdb473f7f90123dd1c77707bd029c25 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart
|
| @@ -4,37 +4,62 @@
|
|
|
| library dart2js.js_emitter.interceptor_stub_generator;
|
|
|
| -import '../compiler.dart' show Compiler;
|
| +import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
|
| +
|
| +import '../common_elements.dart';
|
| import '../constants/values.dart';
|
| import '../elements/entities.dart';
|
| import '../elements/types.dart' show InterfaceType;
|
| import '../js/js.dart' as jsAst;
|
| import '../js/js.dart' show js;
|
| -import '../js_backend/js_backend.dart'
|
| - show
|
| - CustomElementsCodegenAnalysis,
|
| - JavaScriptBackend,
|
| - JavaScriptConstantCompiler,
|
| - Namer;
|
| +import '../js_backend/namer.dart' show Namer;
|
| +import '../js_backend/constant_handler_javascript.dart'
|
| + show JavaScriptConstantCompiler;
|
| +import '../js_backend/custom_elements_analysis.dart'
|
| + show CustomElementsCodegenAnalysis;
|
| +import '../js_backend/native_data.dart';
|
| +import '../js_backend/interceptor_data.dart';
|
| +import '../native/enqueue.dart';
|
| +import '../options.dart';
|
| import '../universe/selector.dart' show Selector;
|
| +import '../universe/world_builder.dart' show CodegenWorldBuilder;
|
| import '../world.dart' show ClosedWorld;
|
|
|
| -import 'code_emitter_task.dart' show Emitter;
|
| +import 'code_emitter_task.dart' show CodeEmitterTask, Emitter;
|
|
|
| class InterceptorStubGenerator {
|
| - final Compiler compiler;
|
| - final Namer namer;
|
| - final JavaScriptBackend backend;
|
| - final ClosedWorld closedWorld;
|
| + final CompilerOptions _options;
|
| + final CommonElements _commonElements;
|
| + final CodeEmitterTask _emitterTask;
|
| + final NativeCodegenEnqueuer _nativeCodegenEnqueuer;
|
| + final JavaScriptConstantCompiler _constants;
|
| + final Namer _namer;
|
| + final NativeData _nativeData;
|
| + final InterceptorData _interceptorData;
|
| + final OneShotInterceptorData _oneShotInterceptorData;
|
| + final CustomElementsCodegenAnalysis _customElementsCodegenAnalysis;
|
| + final CodegenWorldBuilder _codegenWorldBuilder;
|
| + final ClosedWorld _closedWorld;
|
|
|
| InterceptorStubGenerator(
|
| - this.compiler, this.namer, this.backend, this.closedWorld);
|
| -
|
| - Emitter get emitter => backend.emitter.emitter;
|
| + this._options,
|
| + this._commonElements,
|
| + this._emitterTask,
|
| + this._nativeCodegenEnqueuer,
|
| + this._constants,
|
| + this._namer,
|
| + this._nativeData,
|
| + this._interceptorData,
|
| + this._oneShotInterceptorData,
|
| + this._customElementsCodegenAnalysis,
|
| + this._codegenWorldBuilder,
|
| + this._closedWorld);
|
| +
|
| + Emitter get _emitter => _emitterTask.emitter;
|
|
|
| jsAst.Expression generateGetInterceptorMethod(Set<ClassEntity> classes) {
|
| jsAst.Expression interceptorFor(ClassEntity cls) {
|
| - return backend.emitter.interceptorPrototypeAccess(cls);
|
| + return _emitterTask.interceptorPrototypeAccess(cls);
|
| }
|
|
|
| /**
|
| @@ -43,21 +68,21 @@ class InterceptorStubGenerator {
|
| */
|
| jsAst.Statement buildInterceptorCheck(ClassEntity cls) {
|
| jsAst.Expression condition;
|
| - assert(backend.interceptorData.isInterceptedClass(cls));
|
| - if (cls == compiler.commonElements.jsBoolClass) {
|
| + assert(_interceptorData.isInterceptedClass(cls));
|
| + if (cls == _commonElements.jsBoolClass) {
|
| condition = js('(typeof receiver) == "boolean"');
|
| - } else if (cls == compiler.commonElements.jsIntClass ||
|
| - cls == compiler.commonElements.jsDoubleClass ||
|
| - cls == compiler.commonElements.jsNumberClass) {
|
| + } else if (cls == _commonElements.jsIntClass ||
|
| + cls == _commonElements.jsDoubleClass ||
|
| + cls == _commonElements.jsNumberClass) {
|
| throw 'internal error';
|
| - } else if (cls == compiler.commonElements.jsArrayClass ||
|
| - cls == compiler.commonElements.jsMutableArrayClass ||
|
| - cls == compiler.commonElements.jsFixedArrayClass ||
|
| - cls == compiler.commonElements.jsExtendableArrayClass) {
|
| + } else if (cls == _commonElements.jsArrayClass ||
|
| + cls == _commonElements.jsMutableArrayClass ||
|
| + cls == _commonElements.jsFixedArrayClass ||
|
| + cls == _commonElements.jsExtendableArrayClass) {
|
| condition = js('receiver.constructor == Array');
|
| - } else if (cls == compiler.commonElements.jsStringClass) {
|
| + } else if (cls == _commonElements.jsStringClass) {
|
| condition = js('(typeof receiver) == "string"');
|
| - } else if (cls == compiler.commonElements.jsNullClass) {
|
| + } else if (cls == _commonElements.jsNullClass) {
|
| condition = js('receiver == null');
|
| } else {
|
| throw 'internal error';
|
| @@ -73,26 +98,25 @@ class InterceptorStubGenerator {
|
| bool hasNumber = false;
|
| bool hasString = false;
|
| bool hasNative = false;
|
| - bool anyNativeClasses =
|
| - backend.nativeCodegenEnqueuer.hasInstantiatedNativeClasses;
|
| + bool anyNativeClasses = _nativeCodegenEnqueuer.hasInstantiatedNativeClasses;
|
|
|
| for (ClassEntity cls in classes) {
|
| - if (cls == compiler.commonElements.jsArrayClass ||
|
| - cls == compiler.commonElements.jsMutableArrayClass ||
|
| - cls == compiler.commonElements.jsFixedArrayClass ||
|
| - cls == compiler.commonElements.jsExtendableArrayClass)
|
| + if (cls == _commonElements.jsArrayClass ||
|
| + cls == _commonElements.jsMutableArrayClass ||
|
| + cls == _commonElements.jsFixedArrayClass ||
|
| + cls == _commonElements.jsExtendableArrayClass)
|
| hasArray = true;
|
| - else if (cls == compiler.commonElements.jsBoolClass)
|
| + else if (cls == _commonElements.jsBoolClass)
|
| hasBool = true;
|
| - else if (cls == compiler.commonElements.jsDoubleClass)
|
| + else if (cls == _commonElements.jsDoubleClass)
|
| hasDouble = true;
|
| - else if (cls == compiler.commonElements.jsIntClass)
|
| + else if (cls == _commonElements.jsIntClass)
|
| hasInt = true;
|
| - else if (cls == compiler.commonElements.jsNullClass)
|
| + else if (cls == _commonElements.jsNullClass)
|
| hasNull = true;
|
| - else if (cls == compiler.commonElements.jsNumberClass)
|
| + else if (cls == _commonElements.jsNumberClass)
|
| hasNumber = true;
|
| - else if (cls == compiler.commonElements.jsStringClass)
|
| + else if (cls == _commonElements.jsStringClass)
|
| hasString = true;
|
| else {
|
| // The set of classes includes classes mixed-in to interceptor classes
|
| @@ -105,7 +129,7 @@ class InterceptorStubGenerator {
|
| // unresolved PlainJavaScriptObject by testing for anyNativeClasses.
|
|
|
| if (anyNativeClasses) {
|
| - if (backend.nativeData.isNativeOrExtendsNative(cls)) hasNative = true;
|
| + if (_nativeData.isNativeOrExtendsNative(cls)) hasNative = true;
|
| }
|
| }
|
| }
|
| @@ -114,7 +138,7 @@ class InterceptorStubGenerator {
|
| }
|
| if (hasInt) hasNumber = true;
|
|
|
| - if (classes.containsAll(backend.interceptorData.interceptedClasses)) {
|
| + if (classes.containsAll(_interceptorData.interceptedClasses)) {
|
| // I.e. this is the general interceptor.
|
| hasNative = anyNativeClasses;
|
| }
|
| @@ -129,8 +153,8 @@ class InterceptorStubGenerator {
|
| /// is the fallback used when we have determined that receiver
|
| /// is a JavaScript Number.
|
| jsAst.Expression interceptorForNumber = interceptorFor(hasDouble
|
| - ? compiler.commonElements.jsDoubleClass
|
| - : compiler.commonElements.jsNumberClass);
|
| + ? _commonElements.jsDoubleClass
|
| + : _commonElements.jsNumberClass);
|
|
|
| if (hasInt) {
|
| whenNumber = js.statement(
|
| @@ -138,10 +162,7 @@ class InterceptorStubGenerator {
|
| if (Math.floor(receiver) == receiver) return #;
|
| return #;
|
| }''',
|
| - [
|
| - interceptorFor(compiler.commonElements.jsIntClass),
|
| - interceptorForNumber
|
| - ]);
|
| + [interceptorFor(_commonElements.jsIntClass), interceptorForNumber]);
|
| } else {
|
| whenNumber = js.statement('return #', interceptorForNumber);
|
| }
|
| @@ -150,12 +171,10 @@ class InterceptorStubGenerator {
|
| }
|
|
|
| if (hasString) {
|
| - statements
|
| - .add(buildInterceptorCheck(compiler.commonElements.jsStringClass));
|
| + statements.add(buildInterceptorCheck(_commonElements.jsStringClass));
|
| }
|
| if (hasNull) {
|
| - statements
|
| - .add(buildInterceptorCheck(compiler.commonElements.jsNullClass));
|
| + statements.add(buildInterceptorCheck(_commonElements.jsNullClass));
|
| } else {
|
| // Returning "undefined" or "null" here will provoke a JavaScript
|
| // TypeError which is later identified as a null-error by
|
| @@ -163,14 +182,12 @@ class InterceptorStubGenerator {
|
| statements.add(js.statement('if (receiver == null) return receiver'));
|
| }
|
| if (hasBool) {
|
| - statements
|
| - .add(buildInterceptorCheck(compiler.commonElements.jsBoolClass));
|
| + statements.add(buildInterceptorCheck(_commonElements.jsBoolClass));
|
| }
|
| // TODO(ahe): It might be faster to check for Array before
|
| // function and bool.
|
| if (hasArray) {
|
| - statements
|
| - .add(buildInterceptorCheck(compiler.commonElements.jsArrayClass));
|
| + statements.add(buildInterceptorCheck(_commonElements.jsArrayClass));
|
| }
|
|
|
| if (hasNative) {
|
| @@ -184,20 +201,17 @@ class InterceptorStubGenerator {
|
| return #(receiver);
|
| }''',
|
| [
|
| - interceptorFor(compiler.commonElements.jsJavaScriptFunctionClass),
|
| - backend.emitter
|
| - .constructorAccess(compiler.commonElements.objectClass),
|
| - backend.emitter.staticFunctionAccess(
|
| - compiler.commonElements.getNativeInterceptorMethod)
|
| + interceptorFor(_commonElements.jsJavaScriptFunctionClass),
|
| + _emitter.constructorAccess(_commonElements.objectClass),
|
| + _emitter.staticFunctionAccess(
|
| + _commonElements.getNativeInterceptorMethod)
|
| ]));
|
| } else {
|
| - ClassEntity jsUnknown =
|
| - compiler.commonElements.jsUnknownJavaScriptObjectClass;
|
| - if (compiler.codegenWorldBuilder.directlyInstantiatedClasses
|
| + ClassEntity jsUnknown = _commonElements.jsUnknownJavaScriptObjectClass;
|
| + if (_codegenWorldBuilder.directlyInstantiatedClasses
|
| .contains(jsUnknown)) {
|
| statements.add(js.statement('if (!(receiver instanceof #)) return #;', [
|
| - backend.emitter
|
| - .constructorAccess(compiler.commonElements.objectClass),
|
| + _emitter.constructorAccess(_commonElements.objectClass),
|
| interceptorFor(jsUnknown)
|
| ]));
|
| }
|
| @@ -208,6 +222,24 @@ class InterceptorStubGenerator {
|
| return js('''function(receiver) { #; }''', new jsAst.Block(statements));
|
| }
|
|
|
| + jsAst.Call _generateIsJsIndexableCall(
|
| + jsAst.Expression use1, jsAst.Expression use2) {
|
| + String dispatchPropertyName = embeddedNames.DISPATCH_PROPERTY_NAME;
|
| + jsAst.Expression dispatchProperty =
|
| + _emitter.generateEmbeddedGlobalAccess(dispatchPropertyName);
|
| +
|
| + // We pass the dispatch property record to the isJsIndexable
|
| + // helper rather than reading it inside the helper to increase the
|
| + // chance of making the dispatch record access monomorphic.
|
| + jsAst.PropertyAccess record =
|
| + new jsAst.PropertyAccess(use2, dispatchProperty);
|
| +
|
| + List<jsAst.Expression> arguments = <jsAst.Expression>[use1, record];
|
| + FunctionEntity helper = _commonElements.isJsIndexable;
|
| + jsAst.Expression helperExpression = _emitter.staticFunctionAccess(helper);
|
| + return new jsAst.Call(helperExpression, arguments);
|
| + }
|
| +
|
| // Returns a statement that takes care of performance critical
|
| // common case for a one-shot interceptor, or null if there is no
|
| // fast path.
|
| @@ -222,9 +254,9 @@ class InterceptorStubGenerator {
|
| return a0 != null && receiver === a0;
|
| }''');
|
| }
|
| - if (!classes.contains(compiler.commonElements.jsIntClass) &&
|
| - !classes.contains(compiler.commonElements.jsNumberClass) &&
|
| - !classes.contains(compiler.commonElements.jsDoubleClass)) {
|
| + if (!classes.contains(_commonElements.jsIntClass) &&
|
| + !classes.contains(_commonElements.jsNumberClass) &&
|
| + !classes.contains(_commonElements.jsDoubleClass)) {
|
| return null;
|
| }
|
| if (selector.argumentCount == 1) {
|
| @@ -271,21 +303,19 @@ class InterceptorStubGenerator {
|
| // }
|
| // }
|
| // }
|
| - bool containsArray =
|
| - classes.contains(compiler.commonElements.jsArrayClass);
|
| - bool containsString =
|
| - classes.contains(compiler.commonElements.jsStringClass);
|
| - bool containsJsIndexable = closedWorld.isImplemented(
|
| - compiler.commonElements.jsIndexingBehaviorInterface) &&
|
| + bool containsArray = classes.contains(_commonElements.jsArrayClass);
|
| + bool containsString = classes.contains(_commonElements.jsStringClass);
|
| + bool containsJsIndexable = _closedWorld
|
| + .isImplemented(_commonElements.jsIndexingBehaviorInterface) &&
|
| classes.any((cls) {
|
| - return closedWorld.isSubtypeOf(
|
| - cls, compiler.commonElements.jsIndexingBehaviorInterface);
|
| + return _closedWorld.isSubtypeOf(
|
| + cls, _commonElements.jsIndexingBehaviorInterface);
|
| });
|
| // The index set operator requires a check on its set value in
|
| // checked mode, so we don't optimize the interceptor if the
|
| - // compiler has type assertions enabled.
|
| + // _compiler has type assertions enabled.
|
| if (selector.isIndexSet &&
|
| - (compiler.options.enableTypeAssertions || !containsArray)) {
|
| + (_options.enableTypeAssertions || !containsArray)) {
|
| return null;
|
| }
|
| if (!containsArray && !containsString) {
|
| @@ -293,7 +323,7 @@ class InterceptorStubGenerator {
|
| }
|
| jsAst.Expression arrayCheck = js('receiver.constructor == Array');
|
| jsAst.Expression indexableCheck =
|
| - backend.generateIsJsIndexableCall(js('receiver'), js('receiver'));
|
| + _generateIsJsIndexableCall(js('receiver'), js('receiver'));
|
|
|
| jsAst.Expression orExp(left, right) {
|
| return left == null ? right : js('# || #', [left, right]);
|
| @@ -346,10 +376,10 @@ class InterceptorStubGenerator {
|
|
|
| jsAst.Expression generateOneShotInterceptor(jsAst.Name name) {
|
| Selector selector =
|
| - backend.oneShotInterceptorData.getOneShotInterceptorSelector(name);
|
| + _oneShotInterceptorData.getOneShotInterceptorSelector(name);
|
| Set<ClassEntity> classes =
|
| - backend.interceptorData.getInterceptedClassesOn(selector.name);
|
| - jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes);
|
| + _interceptorData.getInterceptedClassesOn(selector.name);
|
| + jsAst.Name getInterceptorName = _namer.nameForGetInterceptor(classes);
|
|
|
| List<String> parameterNames = <String>[];
|
| parameterNames.add('receiver');
|
| @@ -362,9 +392,9 @@ class InterceptorStubGenerator {
|
| }
|
| }
|
|
|
| - jsAst.Name invocationName = backend.namer.invocationName(selector);
|
| - String globalObject = namer
|
| - .globalObjectForLibrary(compiler.commonElements.interceptorsLibrary);
|
| + jsAst.Name invocationName = _namer.invocationName(selector);
|
| + String globalObject =
|
| + _namer.globalObjectForLibrary(_commonElements.interceptorsLibrary);
|
|
|
| jsAst.Statement optimizedPath =
|
| _fastPathForOneShotInterceptor(selector, classes);
|
| @@ -382,14 +412,12 @@ class InterceptorStubGenerator {
|
|
|
| jsAst.ArrayInitializer generateTypeToInterceptorMap() {
|
| // TODO(sra): Perhaps inject a constant instead?
|
| - CustomElementsCodegenAnalysis analysis =
|
| - backend.customElementsCodegenAnalysis;
|
| + CustomElementsCodegenAnalysis analysis = _customElementsCodegenAnalysis;
|
| if (!analysis.needsTable) return null;
|
|
|
| List<jsAst.Expression> elements = <jsAst.Expression>[];
|
| - JavaScriptConstantCompiler handler = backend.constants;
|
| List<ConstantValue> constants =
|
| - handler.getConstantsForEmission(emitter.compareConstants);
|
| + _constants.getConstantsForEmission(_emitter.compareConstants);
|
| for (ConstantValue constant in constants) {
|
| if (constant is TypeConstantValue &&
|
| constant.representedType is InterfaceType) {
|
| @@ -397,8 +425,8 @@ class InterceptorStubGenerator {
|
| ClassEntity classElement = type.element;
|
| if (!analysis.needsClass(classElement)) continue;
|
|
|
| - elements.add(emitter.constantReference(constant));
|
| - elements.add(backend.emitter.interceptorClassAccess(classElement));
|
| + elements.add(_emitter.constantReference(constant));
|
| + elements.add(_emitter.interceptorClassAccess(classElement));
|
|
|
| // Create JavaScript Object map for by-name lookup of generative
|
| // constructors. For example, the class A has three generative
|
| @@ -417,8 +445,8 @@ class InterceptorStubGenerator {
|
| // We expect most of the time the map will be a singleton.
|
| var properties = [];
|
| for (ConstructorEntity member in analysis.constructors(classElement)) {
|
| - properties.add(new jsAst.Property(js.string(member.name),
|
| - backend.emitter.staticFunctionAccess(member)));
|
| + properties.add(new jsAst.Property(
|
| + js.string(member.name), _emitter.staticFunctionAccess(member)));
|
| }
|
|
|
| var map = new jsAst.ObjectInitializer(properties);
|
|
|