Only have one method for generating a method.

R=kasperl@google.com

Review URL: https://codereview.chromium.org//25657008

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@28199 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 9bee82c..f11ac3b 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -802,10 +802,14 @@
 
   String getNameOfField(VariableElement field) => getNameX(field);
 
+  // TODO(ahe): Remove this method. Use get getNameOfMember instead.
   String getNameOfInstanceMember(Element member) => getNameX(member);
 
+  String getNameOfMember(Element member) => getNameX(member);
+
   String getNameOfGlobalField(VariableElement field) => getNameX(field);
 
+  // TODO(ahe): Remove this method. Use get getNameOfMember instead.
   String getNameOfGlobalFunction(FunctionElement element) => getNameX(element);
 
   /// Returns true if [element] is stored on CURRENT_ISOLATE ('$').  We intend
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
index a49ea1a..626de96 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
@@ -21,4 +21,15 @@
   jsAst.Expression toObjectInitializer() {
     return new jsAst.ObjectInitializer(properties);
   }
+
+  /// This method is temporary. Do not use it unless you're working on
+  /// transforming code to build jsAst.Nodes.
+  void writeOn_DO_NOT_USE(CodeBuffer buffer,
+                          Compiler compiler,
+                          String separatedBy) {
+    for (jsAst.Property property in properties) {
+      if (!buffer.isEmpty) buffer.write(separatedBy);
+      buffer.write(jsAst.prettyPrint(property, compiler));
+    }
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 8d0c6a9..dae8663 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -911,55 +911,6 @@
     return field is ClosureFieldElement;
   }
 
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: [member] must be a declaration element.
-   */
-  void addInstanceMember(Element member, ClassBuilder builder) {
-    assert(invariant(member, member.isDeclaration));
-    // TODO(floitsch): we don't need to deal with members of
-    // uninstantiated classes, that have been overwritten by subclasses.
-
-    if (member.isFunction()
-        || member.isGenerativeConstructorBody()
-        || member.isAccessor()) {
-      if (member.isAbstract(compiler)) return;
-      jsAst.Expression code = backend.generatedCode[member];
-      if (code == null) return;
-      String name = namer.getNameOfInstanceMember(member);
-      if (backend.isInterceptedMethod(member)) {
-        interceptorInvocationNames.add(name);
-      }
-      code = extendWithMetadata(member, code);
-      builder.addProperty(name, code);
-      String reflectionName = getReflectionName(member, name);
-      if (reflectionName != null) {
-        var reflectable =
-            js(backend.isAccessibleByReflection(member) ? '1' : '0');
-        builder.addProperty('+$reflectionName', reflectable);
-        jsAst.Node defaultValues = reifyDefaultArguments(member);
-        if (defaultValues != null) {
-          String unmangledName = member.name.slowToString();
-          builder.addProperty('*$unmangledName', defaultValues);
-        }
-      }
-      code = backend.generatedBailoutCode[member];
-      if (code != null) {
-        builder.addProperty(namer.getBailoutName(member), code);
-      }
-      FunctionElement function = member;
-      FunctionSignature parameters = function.computeSignature(compiler);
-      if (!parameters.optionalParameters.isEmpty) {
-        containerBuilder.addParameterStubs(function, builder.addProperty);
-      }
-    } else if (!member.isField()) {
-      compiler.internalError('unexpected kind: "${member.kind}"',
-                             element: member);
-    }
-    containerBuilder.emitExtraAccessors(member, builder);
-  }
-
   /// Returns the "reflection name" of an [Element] or [Selector].
   /// The reflection name of a getter 'foo' is 'foo'.
   /// The reflection name of a setter 'foo' is 'foo='.
@@ -1082,7 +1033,7 @@
     void visitMember(ClassElement enclosing, Element member) {
       assert(invariant(classElement, member.isDeclaration));
       if (member.isInstanceMember()) {
-        addInstanceMember(member, builder);
+        containerBuilder.addMember(member, builder);
       }
     }
 
@@ -2038,18 +1989,6 @@
     }
   }
 
-  void emitStaticFunction(CodeBuffer buffer,
-                          String name,
-                          jsAst.Expression functionExpression) {
-    // TODO(ahe): This method (emitStaticFunction) should return a
-    // jsAst.Expression.
-    if (!buffer.isEmpty) {
-      buffer.write(',$n$n');
-    }
-    buffer.write('$name:$_');
-    buffer.write(jsAst.prettyPrint(functionExpression, compiler));
-  }
-
   void emitStaticFunctions(CodeBuffer eagerBuffer) {
     bool isStaticFunction(Element element) =>
         !element.isInstanceMember() && !element.isField();
@@ -2062,27 +2001,11 @@
             .toSet();
 
     for (Element element in Elements.sortedByPosition(elements)) {
-      CodeBuffer buffer = bufferForElement(element, eagerBuffer);
-      jsAst.Expression code = backend.generatedCode[element];
-      String name = namer.getNameOfGlobalFunction(element);
-      code = extendWithMetadata(element, code);
-      emitStaticFunction(buffer, name, code);
-      String reflectionName = getReflectionName(element, name);
-      if (reflectionName != null) {
-        var reflectable = backend.isAccessibleByReflection(element) ? 1 : 0;
-        buffer.write(',$n$n"+$reflectionName":${_}$reflectable');
-        jsAst.Node defaultValues = reifyDefaultArguments(element);
-        if (defaultValues != null) {
-          String unmangledName = element.name.slowToString();
-          buffer.write(',$n$n"*$unmangledName":${_}');
-          buffer.write(jsAst.prettyPrint(defaultValues, compiler));
-        }
-      }
-      jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
-      if (bailoutCode != null) {
-        pendingElementsWithBailouts.remove(element);
-        emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
-      }
+      pendingElementsWithBailouts.remove(element);
+      ClassBuilder builder = new ClassBuilder();
+      containerBuilder.addMember(element, builder);
+      builder.writeOn_DO_NOT_USE(
+          bufferForElement(element, eagerBuffer), compiler, ',$n$n');
     }
 
     if (!pendingElementsWithBailouts.isEmpty) {
@@ -2091,9 +2014,11 @@
     // Is it possible the primary function was inlined but the bailout was not?
     for (Element element in
              Elements.sortedByPosition(pendingElementsWithBailouts)) {
-      CodeBuffer buffer = bufferForElement(element, eagerBuffer);
       jsAst.Expression bailoutCode = backend.generatedBailoutCode[element];
-      emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
+      new ClassBuilder()
+          ..addProperty(namer.getBailoutName(element), bailoutCode)
+          ..writeOn_DO_NOT_USE(
+              bufferForElement(element, eagerBuffer), compiler, ',$n$n');
     }
   }
 
@@ -3066,33 +2991,6 @@
     });
   }
 
-  jsAst.Fun extendWithMetadata(FunctionElement element, jsAst.Fun code) {
-    if (!backend.retainMetadataOf(element)) return code;
-    return compiler.withCurrentElement(element, () {
-      List<int> metadata = <int>[];
-      FunctionSignature signature = element.functionSignature;
-      if (element.isConstructor()) {
-        metadata.add(reifyType(element.getEnclosingClass().thisType));
-      } else {
-        metadata.add(reifyType(signature.returnType));
-      }
-      signature.forEachParameter((Element parameter) {
-        metadata
-            ..add(reifyName(parameter.name))
-            ..add(reifyType(parameter.computeType(compiler)));
-      });
-      Link link = element.metadata;
-      // TODO(ahe): Why is metadata sometimes null?
-      if (link != null) {
-        for (; !link.isEmpty; link = link.tail) {
-          metadata.add(reifyMetadata(link.head));
-        }
-      }
-      code.body.statements.add(js.string(metadata.join(',')).toStatement());
-      return code;
-    });
-  }
-
   void emitMetadata(CodeBuffer buffer) {
     var literals = backend.typedefTypeLiterals.toList();
     Elements.sortedByPosition(literals);
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index 6c1853f..15ad85a 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -593,4 +593,86 @@
       }
     }
   }
+
+  void addMember(Element member, ClassBuilder builder) {
+    assert(invariant(member, member.isDeclaration));
+
+    if (member.isField()) {
+      addMemberField(member, builder);
+    } else if (member.isFunction() ||
+               member.isGenerativeConstructorBody() ||
+               member.isGenerativeConstructor() ||
+               member.isAccessor()) {
+      addMemberMethod(member, builder);
+    } else {
+      compiler.internalErrorOnElement(
+          member, 'unexpected kind: "${member.kind}"');
+    }
+    if (member.isInstanceMember()) emitExtraAccessors(member, builder);
+  }
+
+  void addMemberMethod(FunctionElement member, ClassBuilder builder) {
+    if (member.isAbstract(compiler)) return;
+    jsAst.Expression code = backend.generatedCode[member];
+    if (code == null) return;
+    String name = namer.getNameOfMember(member);
+    if (backend.isInterceptedMethod(member)) {
+      task.interceptorInvocationNames.add(name);
+    }
+    code = extendWithMetadata(member, code);
+    builder.addProperty(name, code);
+    String reflectionName = task.getReflectionName(member, name);
+    if (reflectionName != null) {
+      var reflectable =
+          js(backend.isAccessibleByReflection(member) ? '1' : '0');
+      builder.addProperty('+$reflectionName', reflectable);
+      jsAst.Node defaultValues = task.reifyDefaultArguments(member);
+      if (defaultValues != null) {
+        String unmangledName = member.name.slowToString();
+        builder.addProperty('*$unmangledName', defaultValues);
+      }
+    }
+    code = backend.generatedBailoutCode[member];
+    if (code != null) {
+      builder.addProperty(namer.getBailoutName(member), code);
+    }
+    if (member.isInstanceMember()) {
+      // TODO(ahe): Where is this done for static/top-level methods?
+      FunctionSignature parameters = member.computeSignature(compiler);
+      if (!parameters.optionalParameters.isEmpty) {
+        addParameterStubs(member, builder.addProperty);
+      }
+    }
+  }
+
+  void addMemberField(VariableElement member, ClassBuilder builder) {
+    // For now, do nothing.
+  }
+
+  jsAst.Fun extendWithMetadata(FunctionElement element, jsAst.Fun code) {
+    if (!backend.retainMetadataOf(element)) return code;
+    return compiler.withCurrentElement(element, () {
+      List<int> metadata = <int>[];
+      FunctionSignature signature = element.functionSignature;
+      if (element.isConstructor()) {
+        metadata.add(task.reifyType(element.getEnclosingClass().thisType));
+      } else {
+        metadata.add(task.reifyType(signature.returnType));
+      }
+      signature.forEachParameter((Element parameter) {
+        metadata
+            ..add(task.reifyName(parameter.name))
+            ..add(task.reifyType(parameter.computeType(compiler)));
+      });
+      Link link = element.metadata;
+      // TODO(ahe): Why is metadata sometimes null?
+      if (link != null) {
+        for (; !link.isEmpty; link = link.tail) {
+          metadata.add(task.reifyMetadata(link.head));
+        }
+      }
+      code.body.statements.add(js.string(metadata.join(',')).toStatement());
+      return code;
+    });
+  }
 }