Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_backend/backend.dart |
| =================================================================== |
| --- sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (revision 18614) |
| +++ sdk/lib/_internal/compiler/implementation/js_backend/backend.dart (working copy) |
| @@ -876,19 +876,39 @@ |
| initializeNoSuchMethod(); |
| seenAnyClass = true; |
| } |
| + |
| + // Register any helper that will be needed by the backend. |
| + if (enqueuer.isResolutionQueue) { |
| + if (cls == compiler.intClass |
| + || cls == compiler.doubleClass |
| + || cls == compiler.numClass) { |
| + // The backend will try to optimize number operations and use the |
| + // `iae` helper directly. |
| + enqueuer.registerStaticUse( |
| + compiler.findHelper(const SourceString('iae'))); |
| + } else if (cls == compiler.listClass |
| + || cls == compiler.stringClass) { |
| + // The backend will try to optimize array and string access and use the |
| + // `ioore` and `iae` helpers directly. |
| + enqueuer.registerStaticUse( |
| + compiler.findHelper(const SourceString('ioore'))); |
| + enqueuer.registerStaticUse( |
| + compiler.findHelper(const SourceString('iae'))); |
| + } else if (cls == compiler.functionClass) { |
| + enqueuer.registerInstantiatedClass(compiler.closureClass); |
| + } else if (cls == compiler.mapClass) { |
| + // The backend will use a literal list to initialize the entries |
| + // of the map. |
| + enqueuer.registerInstantiatedClass(compiler.listClass); |
| + enqueuer.registerInstantiatedClass(compiler.mapLiteralClass); |
| + enqueueInResolution(getMapMaker()); |
| + } |
| + } |
| ClassElement result = null; |
| if (cls == compiler.stringClass) { |
| addInterceptors(jsStringClass, enqueuer); |
| } else if (cls == compiler.listClass) { |
| addInterceptors(jsArrayClass, enqueuer); |
| - // The backend will try to optimize array access and use the |
| - // `ioore` and `iae` helpers directly. |
| - if (enqueuer.isResolutionQueue) { |
| - enqueuer.registerStaticUse( |
| - compiler.findHelper(const SourceString('ioore'))); |
| - enqueuer.registerStaticUse( |
| - compiler.findHelper(const SourceString('iae'))); |
| - } |
| } else if (cls == compiler.intClass) { |
| addInterceptors(jsIntClass, enqueuer); |
| addInterceptors(jsNumberClass, enqueuer); |
| @@ -906,17 +926,16 @@ |
| addInterceptors(jsDoubleClass, enqueuer); |
| addInterceptors(jsNumberClass, enqueuer); |
| } else if (cls == compiler.mapClass) { |
| - // The backend will use a literal list to initialize the entries |
| - // of the map. |
| - if (enqueuer.isResolutionQueue) { |
| - enqueuer.registerInstantiatedClass(compiler.listClass); |
| - enqueuer.registerInstantiatedClass(compiler.mapLiteralClass); |
| - } |
| } |
| - } |
| - Element get cyclicThrowHelper { |
| - return compiler.findHelper(const SourceString("throwCyclicInit")); |
| + if (compiler.enableTypeAssertions) { |
| + // We need to register is checks for assignments to fields. |
| + cls.forEachLocalMember((Element member) { |
| + if (!member.isInstanceMember() || !member.isField()) return; |
| + DartType type = member.computeType(compiler); |
| + enqueuer.registerIsCheck(type); |
| + }); |
| + } |
| } |
| JavaScriptItemCompilationContext createItemCompilationContext() { |
| @@ -924,22 +943,119 @@ |
| } |
| void enqueueHelpers(ResolutionEnqueuer world) { |
| - enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world); |
| - |
| jsIndexingBehaviorInterface = |
| compiler.findHelper(const SourceString('JavaScriptIndexingBehavior')); |
| if (jsIndexingBehaviorInterface != null) { |
| world.registerIsCheck(jsIndexingBehaviorInterface.computeType(compiler)); |
| } |
| - for (var helper in [const SourceString('Closure'), |
| - const SourceString('ConstantMap'), |
| - const SourceString('ConstantProtoMap')]) { |
| - var e = compiler.findHelper(helper); |
| - if (e != null) world.registerInstantiatedClass(e); |
| + if (compiler.enableTypeAssertions) { |
| + // Unconditionally register the helper that checks if the |
| + // expression in an if/while/for is a boolean. |
| + // TODO(ngeoffray): Should we have the resolver register those instead? |
| + Element e = |
| + compiler.findHelper(const SourceString('boolConversionCheck')); |
| + if (e != null) world.addToWorkList(e); |
| } |
| } |
| + void registerStringInterpolation() { |
| + enqueueInResolution(getStringInterpolationHelper()); |
| + } |
| + |
| + void registerCatchStatement() { |
| + enqueueInResolution(getExceptionUnwrapper()); |
| + } |
| + |
| + void registerThrow() { |
| + enqueueInResolution(getThrowHelper()); |
| + } |
| + |
| + void registerLazyField() { |
| + enqueueInResolution(getCyclicThrowHelper()); |
| + } |
| + |
| + void registerTypeLiteral() { |
| + enqueueInResolution(getCreateRuntimeType()); |
| + } |
| + |
| + void registerStackTraceInCatch() { |
| + enqueueInResolution(getTraceFromException()); |
| + } |
| + |
| + void registerRuntimeType() { |
| + enqueueInResolution(getSetRuntimeTypeInfo()); |
| + enqueueInResolution(getGetRuntimeTypeInfo()); |
| + enqueueInResolution(getGetRuntimeTypeArgument()); |
| + } |
| + |
| + void registerIsCheck(DartType type, Enqueuer world) { |
| + if (!type.isRaw) { |
| + enqueueInResolution(getSetRuntimeTypeInfo()); |
| + enqueueInResolution(getGetRuntimeTypeInfo()); |
| + enqueueInResolution(getGetRuntimeTypeArgument()); |
| + enqueueInResolution(getCheckArguments()); |
| + } |
| + // [registerIsCheck] is also called for checked mode checks, so we |
| + // need to register checked mode helpers. |
| + if (compiler.enableTypeAssertions) { |
| + SourceString helperName = getCheckedModeHelper(type); |
| + Element e = compiler.findHelper(helperName); |
| + if (e != null) world.addToWorkList(e); |
| + // We also need the native variant of the check (for DOM types). |
| + helperName = nativeNames[helperName.stringValue]; |
| + if (helperName != null) { |
| + e = compiler.findHelper(helperName); |
| + if (e != null) world.addToWorkList(e); |
| + } |
| + } |
| + } |
| + |
| + void registerAsCheck(DartType type) { |
| + SourceString checkedHelperName = getCheckedModeHelper(type); |
| + SourceString helperName = castNames[checkedHelperName.stringValue]; |
| + Element e = compiler.findHelper(helperName); |
| + enqueueInResolution(e); |
| + // We also need the native variant of the check (for DOM types). |
| + checkedHelperName = nativeNames[checkedHelperName.stringValue]; |
| + if (checkedHelperName != null) { |
| + helperName = castNames[checkedHelperName.stringValue]; |
| + Element e = compiler.findHelper(helperName); |
| + enqueueInResolution(e); |
| + } |
| + } |
| + |
| + void registerThrowNoSuchMethod() { |
| + enqueueInResolution(getThrowNoSuchMethod()); |
| + } |
| + |
| + void registerThrowRuntimeError() { |
| + enqueueInResolution(getThrowRuntimeError()); |
| + } |
| + |
| + void registerAbstractClassInstantiation() { |
| + enqueueInResolution(getThrowAbstractClassInstantiationError()); |
| + } |
| + |
| + void registerFallThroughError() { |
| + enqueueInResolution(getFallThroughError()); |
| + } |
| + |
| + void registerSuperNoSuchMethod() { |
| + enqueueInResolution(getCreateInvocationMirror()); |
| + } |
| + |
| + void enqueueInResolution(Element e) { |
| + if (e != null) compiler.enqueuer.resolution.addToWorkList(e); |
| + } |
| + |
| + void registerConstantMap() { |
| + Element e = compiler.findHelper(const SourceString('ConstantMap')); |
| + if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); |
| + e = compiler.findHelper(const SourceString('ConstantProtoMap')); |
| + if (e != null) compiler.enqueuer.resolution.registerInstantiatedClass(e); |
| + } |
| + |
| void codegen(CodegenWorkItem work) { |
| Element element = work.element; |
| if (element.kind.category == ElementCategory.VARIABLE) { |
| @@ -951,7 +1067,7 @@ |
| // go through the builder (below) to generate the lazy initializer for |
| // the static variable. |
| // We also need to register the use of the cyclic-error helper. |
| - compiler.enqueuer.codegen.registerStaticUse(cyclicThrowHelper); |
| + compiler.enqueuer.codegen.registerStaticUse(getCyclicThrowHelper()); |
| } |
| } |
| @@ -1194,6 +1310,54 @@ |
| } |
| } |
| + Map<String, SourceString> nativeNames = const <String, SourceString> { |
|
ahe
2013/02/18 12:38:04
Document this.
|
| + 'stringSuperTypeCheck': |
| + const SourceString('stringSuperNativeTypeCheck'), |
| + 'numberOrStringSuperTypeCheck': |
| + const SourceString('numberOrStringSuperNativeTypeCheck'), |
| + 'listSuperTypeCheck': |
| + const SourceString('listSuperNativeTypeCheck'), |
| + 'propertyTypeCheck': |
| + const SourceString('callTypeCheck') |
| + }; |
| + |
| + Map<String, SourceString> castNames = const <String, SourceString> { |
|
ahe
2013/02/18 12:38:04
Ditto.
|
| + "stringTypeCheck": |
| + const SourceString("stringTypeCast"), |
| + "doubleTypeCheck": |
| + const SourceString("doubleTypeCast"), |
| + "numTypeCheck": |
| + const SourceString("numTypeCast"), |
| + "boolTypeCheck": |
| + const SourceString("boolTypeCast"), |
| + "functionTypeCheck": |
| + const SourceString("functionTypeCast"), |
| + "intTypeCheck": |
| + const SourceString("intTypeCast"), |
| + "numberOrStringSuperNativeTypeCheck": |
| + const SourceString("numberOrStringSuperNativeTypeCast"), |
| + "numberOrStringSuperTypeCheck": |
| + const SourceString("numberOrStringSuperTypeCast"), |
| + "stringSuperNativeTypeCheck": |
| + const SourceString("stringSuperNativeTypeCast"), |
| + "stringSuperTypeCheck": |
| + const SourceString("stringSuperTypeCast"), |
| + "listTypeCheck": |
| + const SourceString("listTypeCast"), |
| + "listSuperNativeTypeCheck": |
| + const SourceString("listSuperNativeTypeCast"), |
| + "listSuperTypeCheck": |
| + const SourceString("listSuperTypeCast"), |
| + "callTypeCheck": |
| + const SourceString("callTypeCast"), |
| + "propertyTypeCheck": |
| + const SourceString("propertyTypeCast"), |
| + // TODO(johnniwinther): Add a malformedTypeCast which produces a TypeError |
| + // with another message. |
| + "malformedTypeCheck": |
| + const SourceString("malformedTypeCheck") |
| + }; |
| + |
| void dumpInferredTypes() { |
| print("Inferred argument types:"); |
| print("------------------------"); |
| @@ -1227,6 +1391,14 @@ |
| const SourceString('throwAbstractClassInstantiationError')); |
| } |
| + Element getStringInterpolationHelper() { |
| + return compiler.findHelper(const SourceString('S')); |
| + } |
| + |
| + Element getThrowHelper() { |
| + return compiler.findHelper(const SourceString(r'$throw')); |
| + } |
| + |
| Element getClosureConverter() { |
| return compiler.findHelper(const SourceString('convertDartClosureToJS')); |
| } |
| @@ -1251,6 +1423,30 @@ |
| return compiler.findHelper(const SourceString('getRuntimeTypeArgument')); |
| } |
| + Element getCheckArguments() { |
| + return compiler.findHelper(const SourceString('checkArguments')); |
| + } |
| + |
| + Element getThrowNoSuchMethod() { |
| + return compiler.findHelper(const SourceString('throwNoSuchMethod')); |
| + } |
| + |
| + Element getCreateRuntimeType() { |
| + return compiler.findHelper(const SourceString('createRuntimeType')); |
| + } |
| + |
| + Element getFallThroughError() { |
| + return compiler.findHelper(const SourceString("getFallThroughError")); |
| + } |
| + |
| + Element getCreateInvocationMirror() { |
| + return compiler.findHelper(Compiler.CREATE_INVOCATION_MIRROR); |
| + } |
| + |
| + Element getCyclicThrowHelper() { |
| + return compiler.findHelper(const SourceString("throwCyclicInit")); |
| + } |
| + |
| /** |
| * Remove [element] from the set of generated code, and put it back |
| * into the worklist. |