Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(552)

Unified Diff: lib/compiler/implementation/native_emitter.dart

Issue 10854066: Start moving the JavaScript backend related code into a separate library (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add missing import Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/compiler/implementation/leg.dart ('k') | lib/compiler/implementation/native_handler.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/native_emitter.dart
diff --git a/lib/compiler/implementation/native_emitter.dart b/lib/compiler/implementation/native_emitter.dart
deleted file mode 100644
index d2c38251314b9597450d9e73526053a869b47b8f..0000000000000000000000000000000000000000
--- a/lib/compiler/implementation/native_emitter.dart
+++ /dev/null
@@ -1,435 +0,0 @@
-// Copyright (c) 2012, 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.
-
-class NativeEmitter {
-
- CodeEmitterTask emitter;
- CodeBuffer nativeBuffer;
-
- // Classes that participate in dynamic dispatch. These are the
- // classes that contain used members.
- Set<ClassElement> classesWithDynamicDispatch;
-
- // Native classes found in the application.
- Set<ClassElement> nativeClasses;
-
- // Caches the native subtypes of a native class.
- Map<ClassElement, List<ClassElement>> subtypes;
-
- // Caches the direct native subtypes of a native class.
- Map<ClassElement, List<ClassElement>> directSubtypes;
-
- // Caches the native methods that are overridden by a native class.
- // Note that the method that overrides does not have to be native:
- // it's the overridden method that must make sure it will dispatch
- // to its subclass if it sees an instance whose class is a subclass.
- Set<FunctionElement> overriddenMethods;
-
- // Caches the methods that have a native body.
- Set<FunctionElement> nativeMethods;
-
- // Caches the methods that redirect to a JS method.
- Map<FunctionElement, String> redirectingMethods;
-
- // Do we need the native emitter to take care of handling
- // noSuchMethod for us? This flag is set to true in the emitter if
- // it finds any native class that needs noSuchMethod handling.
- bool handleNoSuchMethod = false;
-
- NativeEmitter(this.emitter)
- : classesWithDynamicDispatch = new Set<ClassElement>(),
- nativeClasses = new Set<ClassElement>(),
- subtypes = new Map<ClassElement, List<ClassElement>>(),
- directSubtypes = new Map<ClassElement, List<ClassElement>>(),
- overriddenMethods = new Set<FunctionElement>(),
- nativeMethods = new Set<FunctionElement>(),
- redirectingMethods = new Map<FunctionElement, String>(),
- nativeBuffer = new CodeBuffer();
-
- Compiler get compiler() => emitter.compiler;
-
- void addRedirectingMethod(FunctionElement element, String name) {
- redirectingMethods[element] = name;
- }
-
- String get dynamicName() {
- Element element = compiler.findHelper(
- const SourceString('dynamicFunction'));
- return compiler.namer.isolateAccess(element);
- }
-
- String get dynamicSetMetadataName() {
- Element element = compiler.findHelper(
- const SourceString('dynamicSetMetadata'));
- return compiler.namer.isolateAccess(element);
- }
-
- String get typeNameOfName() {
- Element element = compiler.findHelper(
- const SourceString('getTypeNameOf'));
- return compiler.namer.isolateAccess(element);
- }
-
- String get defPropName() {
- Element element = compiler.findHelper(
- const SourceString('defineProperty'));
- return compiler.namer.isolateAccess(element);
- }
-
- String get toStringHelperName() {
- Element element = compiler.findHelper(
- const SourceString('toStringForNativeObject'));
- return compiler.namer.isolateAccess(element);
- }
-
- String get defineNativeClassName()
- => '${compiler.namer.CURRENT_ISOLATE}.\$defineNativeClass';
-
- String get defineNativeClassFunction() {
- return """
-function(cls, fields, methods) {
- var generateGetterSetter = ${emitter.generateGetterSetterFunction};
- for (var i = 0; i < fields.length; i++) {
- generateGetterSetter(fields[i], methods);
- }
- for (var method in methods) {
- $dynamicName(method)[cls] = methods[method];
- }
-}""";
- }
-
- void generateNativeLiteral(ClassElement classElement) {
- String quotedNative = classElement.nativeName.slowToString();
- String nativeCode = quotedNative.substring(2, quotedNative.length - 1);
- String className = compiler.namer.getName(classElement);
- nativeBuffer.add(className);
- nativeBuffer.add(' = ');
- nativeBuffer.add(nativeCode);
- nativeBuffer.add(';\n');
-
- void defineInstanceMember(String name, CodeBuffer value) {
- nativeBuffer.add("$className.$name = $value;\n");
- }
-
- for (Element member in classElement.members) {
- if (member.isInstanceMember()) {
- emitter.addInstanceMember(member, defineInstanceMember);
- }
- }
- }
-
- bool isNativeLiteral(String quotedName) {
- return quotedName[1] === '=';
- }
-
- bool isNativeGlobal(String quotedName) {
- return quotedName[1] === '@';
- }
-
- String toNativeName(ClassElement cls) {
- String quotedName = cls.nativeName.slowToString();
- if (isNativeGlobal(quotedName)) {
- // Global object, just be like the other types for now.
- return quotedName.substring(3, quotedName.length - 1);
- } else {
- return quotedName.substring(2, quotedName.length - 1);
- }
- }
-
- void generateNativeClass(ClassElement classElement) {
- nativeClasses.add(classElement);
-
- assert(classElement.backendMembers.isEmpty());
- String quotedName = classElement.nativeName.slowToString();
- if (isNativeLiteral(quotedName)) {
- generateNativeLiteral(classElement);
- // The native literal kind needs to be dealt with specially when
- // generating code for it.
- return;
- }
-
- CodeBuffer fieldBuffer = new CodeBuffer();
- emitter.emitClassFields(classElement, fieldBuffer);
-
- CodeBuffer methodBuffer = new CodeBuffer();
- emitter.emitInstanceMembers(classElement, methodBuffer, false);
-
- if (methodBuffer.isEmpty() && fieldBuffer.isEmpty()) return;
-
- String nativeName = toNativeName(classElement);
- nativeBuffer.add("$defineNativeClassName('$nativeName', [");
- nativeBuffer.add(fieldBuffer);
- nativeBuffer.add('], {');
- nativeBuffer.add(methodBuffer);
- nativeBuffer.add('\n});\n\n');
-
- classesWithDynamicDispatch.add(classElement);
- }
-
- List<ClassElement> getDirectSubclasses(ClassElement cls) {
- List<ClassElement> result = directSubtypes[cls];
- return result === null ? const<ClassElement>[] : result;
- }
-
- void potentiallyConvertDartClosuresToJs(CodeBuffer code,
- FunctionElement member,
- List<String> argumentsBuffer) {
- FunctionSignature parameters = member.computeSignature(compiler);
- Element converter =
- compiler.findHelper(const SourceString('convertDartClosureToJS'));
- String closureConverter = compiler.namer.isolateAccess(converter);
- parameters.forEachParameter((Element parameter) {
- String name = parameter.name.slowToString();
- // If [name] is not in [argumentsBuffer], then the parameter is
- // an optional parameter that was not provided for that stub.
- if (argumentsBuffer.indexOf(name) == -1) return;
- Type type = parameter.computeType(compiler);
- if (type is FunctionType) {
- int arity = type.computeArity();
- code.add(' $name = $closureConverter($name, $arity);\n');
- }
- });
- }
-
- String generateParameterStub(Element member,
- String invocationName,
- String stubParameters,
- List<String> argumentsBuffer,
- int indexOfLastOptionalArgumentInParameters,
- CodeBuffer buffer) {
- // The target JS function may check arguments.length so we need to
- // make sure not to pass any unspecified optional arguments to it.
- // For example, for the following Dart method:
- // foo([x, y, z]);
- // The call:
- // foo(y: 1)
- // must be turned into a JS call to:
- // foo(null, y).
-
- List<String> nativeArgumentsBuffer = argumentsBuffer.getRange(
- 0, indexOfLastOptionalArgumentInParameters + 1);
-
- ClassElement classElement = member.enclosingElement;
- String nativeName = classElement.nativeName.slowToString();
- String nativeArguments = Strings.join(nativeArgumentsBuffer, ",");
-
- CodeBuffer code = new CodeBuffer();
- potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer);
-
- if (!nativeMethods.contains(member)) {
- // When calling a method that has a native body, we call it
- // with our calling conventions.
- String arguments = Strings.join(argumentsBuffer, ",");
- code.add(' return this.${compiler.namer.getName(member)}($arguments)');
- } else {
- // When calling a JS method, we call it with the native name.
- String name = redirectingMethods[member];
- if (name === null) name = member.name.slowToString();
- code.add(' return this.$name($nativeArguments);');
- }
-
- if (isNativeLiteral(nativeName) || !overriddenMethods.contains(member)) {
- // Call the method directly.
- buffer.add(code.toString());
- } else {
- native.generateMethodWithPrototypeCheck(
- compiler, buffer, invocationName, code.toString(), stubParameters);
- }
- }
-
- void emitDynamicDispatchMetadata() {
- if (classesWithDynamicDispatch.isEmpty()) return;
- int length = classesWithDynamicDispatch.length;
- nativeBuffer.add('// $length dynamic classes.\n');
-
- // Build a pre-order traversal over all the classes and their subclasses.
- Set<ClassElement> seen = new Set<ClassElement>();
- List<ClassElement> classes = <ClassElement>[];
- void visit(ClassElement cls) {
- if (seen.contains(cls)) return;
- seen.add(cls);
- for (final ClassElement subclass in getDirectSubclasses(cls)) {
- visit(subclass);
- }
- classes.add(cls);
- }
- for (final ClassElement classElement in classesWithDynamicDispatch) {
- visit(classElement);
- }
-
- Collection<ClassElement> dispatchClasses = classes.filter(
- (cls) => !getDirectSubclasses(cls).isEmpty() &&
- classesWithDynamicDispatch.contains(cls));
-
- nativeBuffer.add('// ${classes.length} classes\n');
- Collection<ClassElement> classesThatHaveSubclasses = classes.filter(
- (ClassElement t) => !getDirectSubclasses(t).isEmpty());
- nativeBuffer.add('// ${classesThatHaveSubclasses.length} !leaf\n');
-
- // Generate code that builds the map from cls tags used in dynamic dispatch
- // to the set of cls tags of classes that extend (TODO: or implement) those
- // classes. The set is represented as a string of tags joined with '|'.
- // This is easily split into an array of tags, or converted into a regexp.
- //
- // To reduce the size of the sets, subsets are CSE-ed out into variables.
- // The sets could be much smaller if we could make assumptions about the
- // cls tags of other classes (which are constructor names or part of the
- // result of Object.protocls.toString). For example, if objects that are
- // Dart objects could be easily excluded, then we might be able to simplify
- // the test, replacing dozens of HTMLxxxElement classes with the regexp
- // /HTML.*Element/.
-
- // Temporary variables for common substrings.
- List<String> varNames = <String>[];
- // var -> expression
- Map<String, String> varDefns = <String>{};
- // tag -> expression (a string or a variable)
- Map<ClassElement, String> tagDefns = new Map<ClassElement, String>();
-
- String makeExpression(ClassElement classElement) {
- // Expression fragments for this set of cls keys.
- List<String> expressions = <String>[];
- // TODO: Remove if cls is abstract.
- List<String> subtags = [toNativeName(classElement)];
- void walk(ClassElement cls) {
- for (final ClassElement subclass in getDirectSubclasses(cls)) {
- ClassElement tag = subclass;
- String existing = tagDefns[tag];
- if (existing == null) {
- subtags.add(toNativeName(tag));
- walk(subclass);
- } else {
- if (varDefns.containsKey(existing)) {
- expressions.add(existing);
- } else {
- String varName = 'v${varNames.length}/*${tag}*/';
- varNames.add(varName);
- varDefns[varName] = existing;
- tagDefns[tag] = varName;
- expressions.add(varName);
- }
- }
- }
- }
- walk(classElement);
- String constantPart = "'${Strings.join(subtags, '|')}'";
- if (constantPart != "''") expressions.add(constantPart);
- String expression;
- if (expressions.length == 1) {
- expression = expressions[0];
- } else {
- expression = "[${Strings.join(expressions, ',')}].join('|')";
- }
- return expression;
- }
-
- for (final ClassElement classElement in dispatchClasses) {
- tagDefns[classElement] = makeExpression(classElement);
- }
-
- // Write out a thunk that builds the metadata.
- if (!tagDefns.isEmpty()) {
- nativeBuffer.add('(function(){\n');
-
- for (final String varName in varNames) {
- nativeBuffer.add(' var ${varName} = ${varDefns[varName]};\n');
- }
-
- nativeBuffer.add(' var table = [\n');
- nativeBuffer.add(
- ' // [dynamic-dispatch-tag, '
- 'tags of classes implementing dynamic-dispatch-tag]');
- bool needsComma = false;
- List<String> entries = <String>[];
- for (final ClassElement cls in dispatchClasses) {
- String clsName = toNativeName(cls);
- entries.add("\n ['$clsName', ${tagDefns[cls]}]");
- }
- nativeBuffer.add(Strings.join(entries, ','));
- nativeBuffer.add('];\n');
- nativeBuffer.add('$dynamicSetMetadataName(table);\n');
-
- nativeBuffer.add('})();\n');
- }
- }
-
- bool isSupertypeOfNativeClass(Element element) {
- if (element.isTypeVariable()) {
- compiler.cancel("Is check for type variable", element: element);
- return false;
- }
- if (element.computeType(compiler) is FunctionType) return false;
-
- if (!element.isClass()) {
- compiler.cancel("Is check does not handle element", element: element);
- return false;
- }
-
- return subtypes[element] !== null;
- }
-
- bool requiresNativeIsCheck(Element element) {
- if (!element.isClass()) return false;
- ClassElement cls = element;
- if (cls.isNative()) return true;
- return isSupertypeOfNativeClass(element);
- }
-
- void emitIsChecks(Map<String, String> objectProperties) {
- for (Element type in compiler.codegenWorld.isChecks) {
- if (!requiresNativeIsCheck(type)) continue;
- String name = compiler.namer.operatorIs(type);
- objectProperties[name] = 'function() { return false; }';
- }
- }
-
- void assembleCode(CodeBuffer targetBuffer) {
- if (nativeClasses.isEmpty()) return;
- emitDynamicDispatchMetadata();
- targetBuffer.add('$defineNativeClassName = '
- '$defineNativeClassFunction;\n\n');
-
- // Because of native classes, we have to generate some is checks
- // by calling a method, instead of accessing a property. So we
- // attach to the JS Object prototype these methods that return
- // false, and will be overridden by subclasses when they have to
- // return true.
- Map<String, String> objectProperties = new Map<String, String>();
- emitIsChecks(objectProperties);
-
- // In order to have the toString method on every native class,
- // we must patch the JS Object prototype with a helper method.
- String toStringName = compiler.namer.instanceMethodName(
- null, const SourceString('toString'), 0);
- objectProperties[toStringName] =
- 'function() { return $toStringHelperName(this); }';
-
- // If the native emitter has been asked to take care of the
- // noSuchMethod handlers, we do that now.
- if (handleNoSuchMethod) {
- emitter.emitNoSuchMethodHandlers((String name, CodeBuffer buffer) {
- objectProperties[name] = buffer.toString();
- });
- }
-
- // If we have any properties to add to Object.prototype, we run
- // through them and add them using defineProperty.
- if (!objectProperties.isEmpty()) {
- targetBuffer.add("(function(table) {\n"
- " for (var key in table) {\n"
- " $defPropName(Object.prototype, key, table[key]);\n"
- " }\n"
- "})({\n");
- bool first = true;
- objectProperties.forEach((String name, String function) {
- if (!first) targetBuffer.add(",\n");
- targetBuffer.add(" $name: $function");
- first = false;
- });
- targetBuffer.add("\n});\n\n");
- }
- targetBuffer.add('$nativeBuffer');
- targetBuffer.add('\n');
- }
-}
« no previous file with comments | « lib/compiler/implementation/leg.dart ('k') | lib/compiler/implementation/native_handler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698