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); |