Index: tools/dart2js/class_generator/class_generator.dart |
diff --git a/tools/dart2js/class_generator/class_generator.dart b/tools/dart2js/class_generator/class_generator.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..59bf22e60ea029b58c43f332ca9280f33968046c |
--- /dev/null |
+++ b/tools/dart2js/class_generator/class_generator.dart |
@@ -0,0 +1,785 @@ |
+// Copyright (c) 2015, 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. |
+ |
+// Script that generates different approaches to initialize classes in |
+// JavaScript. |
+// Also benchmarks the approaches. |
+ |
+import 'dart:io'; |
+import 'dart:async'; |
+ |
+class Config { |
+ /// Number of classes that should be generated. |
+ final int nbClasses; |
+ |
+ /// Number of methods per class. |
+ final int nbMethodsPerClass; |
+ |
+ /// Should the JavaScript classes share a common super class? |
+ /// |
+ /// Currently unused for Dart, since it always has a common super class |
+ /// anyways. |
+ // TODO(floitsch): also create a common super class in Dart? |
+ final bool shareCommonSuperclass; |
+ |
+ /// Assign unique names to the methods or let them share the same one? |
+ /// |
+ /// Independent of this flag, the `callAll` and `instantiatePrevious` method |
+ /// names are the same for all classes. |
+ final bool sameMethodNames; |
+ |
+ /// Adds a `print` statement to the method. |
+ final bool shouldPrintInMethod; |
+ |
+ /// Adds while loops to the method body. |
+ /// |
+ /// This has the effect that dart2js won't be able to inline the method and |
+ /// controls the size of the method bodies. |
+ final int nbWhileLoopsInBody; |
+ |
+ /// Should the JavaScript output be wrapped into an anonymous function? |
+ /// |
+ /// When enabled wraps the program with the following pattern: |
+ /// `(function() { <program> })()`. |
+ final bool shouldWrapProgram; |
+ |
+ /// Adds a `callAll` method that invokes all other methods of the class. |
+ /// |
+ /// This is necessary for dart2js to avoid tree-shaking. |
+ /// Should probably always be on (except for presentations to demonstrate that |
+ /// dart2js knows how to tree-shake). |
+ /// |
+ /// This method counts towards the [nbMethodsPerClass] limit. |
+ final bool shouldEmitCallAllMethods; |
+ |
+ /// Adds an `instantiatePrevious` method that instantiates the previous class. |
+ /// |
+ /// A "previous" class is the class that was generated before the current |
+ /// class. The first class returns `null`. |
+ final bool shouldEmitInstantiatePreviousMethod; |
+ |
+ /// Makes sure that the dart2js tree-shaker doesn't remove classes. |
+ /// |
+ /// When set to `-1`, all classes are kept alive. |
+ final int fakeInstantiateClass; |
+ |
+ /// Defines the percent of classes that are dynamically instantiated. |
+ final int instantiateClassesPercent; |
+ |
+ Config({this.nbClasses, this.nbMethodsPerClass, |
+ this.shareCommonSuperclass, this.sameMethodNames, |
+ this.shouldPrintInMethod, this.nbWhileLoopsInBody, |
+ this.shouldWrapProgram, this.shouldEmitCallAllMethods, |
+ this.shouldEmitInstantiatePreviousMethod, |
+ this.fakeInstantiateClass, this.instantiateClassesPercent}); |
+} |
+ |
+String get d8Path { |
+ Uri scriptPath = Platform.script; |
+ String d8Executable = "../../../third_party/d8/"; |
+ if (Platform.isWindows) { |
+ d8Executable += "windows/d8.exe"; |
+ } else if (Platform.isMacOS) { |
+ d8Executable += "macos/d8"; |
+ } else if (Platform.isLinux) { |
+ d8Executable += "linux/d8"; |
+ } else { |
+ return null; |
+ } |
+ return scriptPath.resolve(d8Executable).path; |
+} |
+ |
+String get jsShellPath { |
+ Uri scriptPath = Platform.script; |
+ if (!Platform.isLinux) { |
+ return null; |
+ } |
+ return scriptPath.resolve("../../../tools/testing/bin/jsshell").path; |
+} |
+ |
+String get dart2jsPath { |
+ Uri scriptPath = Platform.script; |
+ return scriptPath.resolve("../../../sdk/bin/dart2js").path; |
+} |
+ |
+abstract class ClassGenerator { |
+ final StringBuffer buffer = new StringBuffer(); |
+ // By convention all methods should take one argument with this name. |
+ final String argumentName = "x"; |
+ final String callOtherMethodsName = "callAll"; |
+ final String instantiatePreviousMethodName = "instantiatePrevious"; |
+ |
+ final Config config; |
+ |
+ ClassGenerator(this.config); |
+ |
+ int get nbClasses => config.nbClasses; |
+ int get nbMethodsPerClass => config.nbMethodsPerClass; |
+ bool get shouldPrintInMethod => config.shouldPrintInMethod; |
+ bool get sameMethodNames => config.sameMethodNames; |
+ int get nbWhileLoopsInMethod => config.nbWhileLoopsInBody; |
+ bool get shareCommonSuperclass => config.shareCommonSuperclass; |
+ bool get shouldEmitCallAllMethods => config.shouldEmitCallAllMethods; |
+ bool get shouldEmitInstantiatePreviousMethod => |
+ config.shouldEmitInstantiatePreviousMethod; |
+ int get fakeInstantiateClass => config.fakeInstantiateClass; |
+ int get instantiateClassesPercent => config.instantiateClassesPercent; |
+ |
+ Future measure(String filePrefix) async { |
+ String fileName = await generateRawJs(filePrefix); |
+ if (fileName == null) return; |
+ Directory dir = Directory.systemTemp.createTempSync('classes'); |
+ try { |
+ File measuring = new File("${dir.path}/measuring.js"); |
+ IOSink sink = measuring.openWrite(); |
+ sink.writeln("var start = new Date();"); |
+ await sink.addStream(new File(fileName).openRead()); |
+ sink.writeln("print(new Date() - start)"); |
+ String command; |
+ List<String> args; |
+ bool runJsShell = false; |
+ if (runJsShell) { |
+ command = jsShellPath; |
+ print("Running $command"); |
+ args = [measuring.path]; |
+ } else { |
+ command = d8Path; |
+ print("Running $command"); |
+ args = ["--harmony-sloppy", measuring.path]; |
+ } |
+ print("Running: $fileName"); |
+ int nbRuns = 10; |
+ int sum = 0; |
+ int sumSw = 0; |
+ Stopwatch watch = new Stopwatch(); |
+ for (int i = 0; i < nbRuns; i++) { |
+ watch.reset(); |
+ watch.start(); |
+ ProcessResult result = await Process.run(command, args); |
+ if (result.exitCode != 0) { |
+ print("run failed"); |
+ print(result.stdout); |
+ print(result.stderr); |
+ } |
+ int elapsed = watch.elapsedMilliseconds; |
+ print(" output: ${result.stdout.trim()} ($elapsed)"); |
+ sum += int.parse(result.stdout, onError: (str) => 0); |
+ sumSw += elapsed; |
+ } |
+ int mean = sum == 0 ? 0 : sum ~/ nbRuns; |
+ int meanSw = sumSw == 0 ? 0 : sumSw ~/ nbRuns; |
+ print(" mean: $mean ($meanSw)"); |
+ } finally { |
+ dir.deleteSync(recursive: true); |
+ } |
+ } |
+ |
+ Future<String> generateRawJs(String filePrefix); |
+ |
+ String buildFileName(String filePrefix, String extension) { |
+ // TODO(floitsch): store other config info in the file name. |
+ return "$filePrefix.$nbClasses.$nbMethodsPerClass." |
+ "$instantiateClassesPercent.$description.$extension"; |
+ } |
+ |
+ String writeFile(String filePrefix) { |
+ buffer.clear(); |
+ emitClasses(); // Output is stored in `buffer`. |
+ |
+ String fileName = buildFileName(filePrefix, fileExtension); |
+ new File(fileName).writeAsStringSync(buffer.toString()); |
+ print("wrote: $fileName"); |
+ return fileName; |
+ } |
+ |
+ void writeln(x) => buffer.writeln(x); |
+ |
+ String classIdToName(int id) { |
+ if (id < 0) id = nbClasses + id; |
+ return "Class$id"; |
+ } |
+ |
+ /// [id] is per class. |
+ String methodIdToName(int id, int classId) { |
+ if (sameMethodNames) return "method$id"; |
+ return "method${classId}_$id"; |
+ } |
+ |
+ // Must work for Dart and JS. |
+ void emitMethodBody(int methodId, int classId) { |
+ writeln("{"); |
+ if (shouldPrintInMethod) { |
+ writeln("print('class: $classId, method: $methodId');"); |
+ } |
+ if (nbWhileLoopsInMethod > 0) { |
+ writeln("var sum = 0;"); |
+ for (int i = 0; i < nbWhileLoopsInMethod; i++) { |
+ writeln("for (var i = 0; i < $argumentName; i++) {"); |
+ writeln(" sum++;"); |
+ writeln("}"); |
+ } |
+ writeln("return sum;"); |
+ } |
+ writeln("}"); |
+ } |
+ |
+ // Must work for Dart and JS. |
+ void emitCallOtherMethodsBody(List<int> methodIds, int classId) { |
+ writeln("{"); |
+ writeln("var sum = 0;"); |
+ for (int methodId in methodIds) { |
+ String methodName = methodIdToName(methodId, classId); |
+ writeln("sum += this.$methodName($argumentName);"); |
+ } |
+ writeln("return sum;"); |
+ writeln("}"); |
+ } |
+ |
+ // Must work for Dart and JS. |
+ void emitInstantiatePrevious(int classId) { |
+ writeln("{"); |
+ if (classId == 0) { |
+ writeln("return null;"); |
+ } else { |
+ String previousClass = classIdToName(classId - 1); |
+ writeln("return new $previousClass();"); |
+ } |
+ writeln("}"); |
+ } |
+ |
+ /// Should write the class using [writeln]. |
+ void emitClasses(); |
+ |
+ String get description; |
+ String get fileExtension; |
+} |
+ |
+abstract class JavaScriptClassGenerator extends ClassGenerator { |
+ bool get wrapProgram => config.shouldWrapProgram; |
+ final String methodsObjectName = "methods"; |
+ |
+ JavaScriptClassGenerator(Config config) : super(config); |
+ |
+ Future<String> generateRawJs(String filePrefix) => |
+ new Future.value(writeFile(filePrefix)); |
+ |
+ void emitUtilityFunctions(); |
+ void emitClass(int classId, int superclassId); |
+ |
+ void emitClasses() { |
+ if (wrapProgram) writeln("(function() {"); |
+ writeln("var $methodsObjectName;"); |
+ emitUtilityFunctions(); |
+ for (int i = 0; i < nbClasses; i++) { |
+ int superclassId = shareCommonSuperclass && i != 0 ? 0 : null; |
+ emitClass(i, superclassId); |
+ } |
+ |
+ if (fakeInstantiateClass != null) { |
+ String className = classIdToName(fakeInstantiateClass); |
+ writeln(""" |
+ if (new Date() == 42) { |
+ var o = new $className(); |
+ do { |
+ o.$callOtherMethodsName(99); |
+ o = o.$instantiatePreviousMethodName(); |
+ } while(o != null); |
+ }"""); |
+ } |
+ if (instantiateClassesPercent != null) { |
+ int targetClassId = ((nbClasses - 1) * instantiateClassesPercent) ~/ 100; |
+ String targetClassName = classIdToName(targetClassId); |
+ writeln(""" |
+ var o = new $targetClassName(); |
+ do { |
+ o = o.$instantiatePreviousMethodName(); |
+ } while(o != null); |
+ """); |
+ } |
+ if (wrapProgram) writeln("})();"); |
+ } |
+ |
+ String get fileExtension => "js"; |
+} |
+ |
+enum PrototypeApproach { |
+ tmpFunction, |
+ internalProto, |
+ objectCreate |
+} |
+class PlainJavaScriptClassGenerator extends JavaScriptClassGenerator { |
+ final PrototypeApproach prototypeApproach; |
+ final bool shouldInlineInherit; |
+ final bool useMethodsObject; |
+ |
+ PlainJavaScriptClassGenerator(Config config, |
+ {this.prototypeApproach, |
+ this.shouldInlineInherit, |
+ this.useMethodsObject}) |
+ : super(config) { |
+ if (prototypeApproach == null) { |
+ throw "Must provide prototype approach"; |
+ } |
+ if (shouldInlineInherit == null) { |
+ throw "Must provide inlining approach"; |
+ } |
+ if (useMethodsObject == null) { |
+ throw "Must provide object-proto approach"; |
+ } |
+ if (shouldInlineInherit && |
+ prototypeApproach == PrototypeApproach.tmpFunction) { |
+ throw "Can't inline tmp-function approach"; |
+ } |
+ } |
+ |
+ void emitInherit(cls, superclassId) { |
+ if (superclassId == null && !useMethodsObject) return; |
+ String sup = (superclassId == null) ? "null" : classIdToName(superclassId); |
+ if (!shouldInlineInherit) { |
+ if (useMethodsObject) { |
+ writeln("inherit($cls, $sup, $methodsObjectName);"); |
+ } else { |
+ writeln("inherit($cls, $sup);"); |
+ } |
+ return; |
+ } |
+ switch (prototypeApproach) { |
+ case PrototypeApproach.tmpFunction: |
+ throw "Should not happen"; |
+ break; |
+ case PrototypeApproach.internalProto: |
+ if (useMethodsObject) { |
+ writeln("$cls.prototype = $methodsObjectName;"); |
+ } |
+ if (superclassId != null) { |
+ writeln("$cls.prototype.__proto__ = $sup.prototype;"); |
+ } |
+ break; |
+ case PrototypeApproach.objectCreate: |
+ if (useMethodsObject) { |
+ if (superclassId == null) { |
+ writeln("$cls.prototype = $methodsObjectName;"); |
+ } else { |
+ writeln("$cls.prototype = Object.create($sup.prototype);"); |
+ writeln("copyProperties($methodsObjectName, $cls.prototype);"); |
+ } |
+ } else { |
+ writeln("$cls.prototype = Object.create($sup.prototype);"); |
+ } |
+ break; |
+ } |
+ } |
+ |
+ void emitUtilityFunctions() { |
+ switch (prototypeApproach) { |
+ case PrototypeApproach.internalProto: |
+ if (useMethodsObject) { |
+ writeln(''' |
+ function inherit(cls, sup, methods) { |
+ cls.prototype = methods; |
+ if (sup != null) { |
+ cls.prototype.__proto__ = sup.prototype; |
+ } |
+ } |
+ '''); |
+ |
+ } else { |
+ writeln(''' |
+ function inherit(cls, sup) { |
+ cls.prototype.__proto__ = sup.prototype; |
+ } |
+ '''); |
+ } |
+ break; |
+ case PrototypeApproach.tmpFunction: |
+ if (useMethodsObject) { |
+ writeln(''' |
+ function inherit(cls, sup, methods) { |
+ if (sup != null) { |
+ function tmp() {} |
+ tmp.prototype = sup.prototype; |
+ var proto = new tmp(); |
+ proto.constructor = cls; |
+ cls.prototype = proto; |
+ } |
+ copyProperties(methods, cls.prototype); |
+ }'''); |
+ } else { |
+ writeln(''' |
+ function inherit(cls, sup) { |
+ function tmp() {} |
+ tmp.prototype = sup.prototype; |
+ var proto = new tmp(); |
+ proto.constructor = cls; |
+ cls.prototype = proto; |
+ }'''); |
+ } |
+ break; |
+ case PrototypeApproach.objectCreate: |
+ if (useMethodsObject) { |
+ writeln(''' |
+ function inherit(cls, sup, methods) { |
+ if (sup == null) { |
+ cls.prototype = methods; |
+ } else { |
+ cls.prototype = Object.create(sup.prototype); |
+ copyProperties(methods, cls.prototype); |
+ } |
+ } |
+ '''); |
+ } else { |
+ writeln(''' |
+ function inherit(cls, sup) { |
+ cls.prototype = Object.create(sup.prototype); |
+ } |
+ '''); |
+ } |
+ break; |
+ } |
+ writeln(""" |
+ function copyProperties(from, to) { |
+ var props = Object.keys(from); |
+ for (var i = 0; i < props.length; i++) { |
+ var p = props[i]; |
+ to[p] = from[p]; |
+ } |
+ }"""); |
+ } |
+ |
+ void emitMethod(int classId, String methodName, Function bodyEmitter, |
+ {bool emitArgument: true}) { |
+ String argumentString = emitArgument ? argumentName : ""; |
+ if (useMethodsObject) { |
+ writeln("$methodName: function($argumentString)"); |
+ bodyEmitter(); |
+ writeln(","); |
+ } else { |
+ String className = classIdToName(classId); |
+ String proto = "$className.prototype"; |
+ writeln("$proto.$methodName = function($argumentString)"); |
+ bodyEmitter(); |
+ } |
+ } |
+ |
+ /// Returns the methods object, if we use an object. |
+ void emitMethods(int classId) { |
+ List<int> methodIds = []; |
+ int nbGenericMethods = nbMethodsPerClass; |
+ if (useMethodsObject) { |
+ writeln("$methodsObjectName = {"); |
+ } |
+ if (shouldEmitCallAllMethods) nbGenericMethods--; |
+ for (int j = 0; j < nbGenericMethods; j++) { |
+ String methodName = methodIdToName(j, classId); |
+ emitMethod(classId, methodName, () => emitMethodBody(j, classId)); |
+ methodIds.add(j); |
+ } |
+ if (shouldEmitCallAllMethods) { |
+ emitMethod(classId, |
+ callOtherMethodsName, |
+ () => emitCallOtherMethodsBody(methodIds, classId)); |
+ } |
+ if (shouldEmitInstantiatePreviousMethod) { |
+ emitMethod(classId, |
+ instantiatePreviousMethodName, |
+ () => emitInstantiatePrevious(classId), |
+ emitArgument: false); |
+ } |
+ if (useMethodsObject) { |
+ writeln("};"); |
+ } |
+ } |
+ |
+ void emitClass(int classId, int superclassId) { |
+ String className = classIdToName(classId); |
+ writeln("function $className() {}"); |
+ switch (prototypeApproach) { |
+ case PrototypeApproach.objectCreate: |
+ if (useMethodsObject) { |
+ emitMethods(classId); |
+ emitInherit(className, superclassId); |
+ } else { |
+ emitInherit(className, superclassId); |
+ emitMethods(classId); |
+ } |
+ break; |
+ case PrototypeApproach.tmpFunction: |
+ if (useMethodsObject) { |
+ emitMethods(classId); |
+ emitInherit(className, superclassId); |
+ } else { |
+ emitInherit(className, superclassId); |
+ emitMethods(classId); |
+ } |
+ break; |
+ case PrototypeApproach.internalProto: |
+ emitMethods(classId); |
+ emitInherit(className, superclassId); |
+ break; |
+ } |
+ } |
+ |
+ String get description { |
+ String protoApproachDescription; |
+ switch (prototypeApproach) { |
+ case PrototypeApproach.objectCreate: |
+ protoApproachDescription = "objectCreate"; |
+ break; |
+ case PrototypeApproach.tmpFunction: |
+ protoApproachDescription = "tmpFunction"; |
+ break; |
+ case PrototypeApproach.internalProto: |
+ protoApproachDescription = "internalProto"; |
+ break; |
+ } |
+ String inline = shouldInlineInherit ? "inl" : "noInl"; |
+ String objectProto = useMethodsObject ? "obj" : "noObj"; |
+ return "plain_${protoApproachDescription}_${inline}_$objectProto"; |
+ } |
+} |
+ |
+class Es6ClassGenerator extends JavaScriptClassGenerator { |
+ Es6ClassGenerator(Config config) : super(config); |
+ |
+ void emitUtilityFunctions() {} |
+ |
+ void emitClass(int classId, int superclassId) { |
+ String className = classIdToName(classId); |
+ if (superclassId != null) { |
+ String superclassName = classIdToName(superclassId); |
+ buffer.writeln("class $className extends $superclassName {"); |
+ } else { |
+ buffer.writeln("class $className {"); |
+ } |
+ List<int> methodIds = []; |
+ int nbGenericMethods = nbMethodsPerClass; |
+ if (shouldEmitCallAllMethods) nbGenericMethods--; |
+ for (int j = 0; j < nbGenericMethods; j++) { |
+ String methodName = methodIdToName(j, classId); |
+ writeln("$methodName($argumentName) "); |
+ emitMethodBody(j, classId); |
+ methodIds.add(j); |
+ } |
+ if (shouldEmitCallAllMethods) { |
+ writeln("$callOtherMethodsName($argumentName)"); |
+ emitCallOtherMethodsBody(methodIds, classId); |
+ } |
+ if (shouldEmitInstantiatePreviousMethod) { |
+ writeln("$instantiatePreviousMethodName()"); |
+ emitInstantiatePrevious(classId); |
+ } |
+ writeln("}"); |
+ } |
+ |
+ String get description => "es6"; |
+} |
+ |
+class DartClassGenerator extends ClassGenerator { |
+ final bool shouldUseNewEmitter; |
+ |
+ DartClassGenerator(Config config, {this.shouldUseNewEmitter: false}) |
+ : super(config); |
+ |
+ void emitClasses() { |
+ // TODO(flo): instantiateAndCallPrevious |
+ for (int i = 0; i < nbClasses; i++) { |
+ String className = classIdToName(i); |
+ writeln("class $className {"); |
+ List<int> methodIds = []; |
+ int nbGenericMethods = nbMethodsPerClass; |
+ if (shouldEmitCallAllMethods) nbGenericMethods--; |
+ for (int j = 0; j < nbGenericMethods; j++) { |
+ String methodName = methodIdToName(j, i); |
+ writeln("$methodName($argumentName)"); |
+ emitMethodBody(j, i); |
+ methodIds.add(j); |
+ } |
+ if (shouldEmitCallAllMethods) { |
+ writeln("$callOtherMethodsName($argumentName)"); |
+ emitCallOtherMethodsBody(methodIds, i); |
+ } |
+ if (shouldEmitInstantiatePreviousMethod) { |
+ writeln("$instantiatePreviousMethodName()"); |
+ emitInstantiatePrevious(i); |
+ } |
+ writeln("}"); |
+ } |
+ writeln("main() {"); |
+ if (fakeInstantiateClass != null) { |
+ String className = classIdToName(fakeInstantiateClass); |
+ writeln(""" |
+ if (new DateTime.now().millisecondsSinceEpoch == 42) { |
+ var o = new $className(); |
+ do { |
+ o.$callOtherMethodsName(99); |
+ o = o.$instantiatePreviousMethodName(); |
+ } while(o != null); |
+ }"""); |
+ } |
+ if (instantiateClassesPercent != null) { |
+ int targetClassId = ((nbClasses - 1) * instantiateClassesPercent) ~/ 100; |
+ String targetClassName = classIdToName(targetClassId); |
+ writeln(""" |
+ var o = new $targetClassName(); |
+ do { |
+ o = o.$instantiatePreviousMethodName(); |
+ } while(o != null); |
+ """); |
+ } |
+ writeln("}"); |
+ } |
+ |
+ Future<String> generateRawJs(String filePrefix) async { |
+ String dartFile = writeFile(filePrefix); |
+ String outFile = buildFileName(filePrefix, "js"); |
+ Map<String, String> env = {}; |
+ if (shouldUseNewEmitter) { |
+ env["DART_VM_OPTIONS"] = '-Ddart2js.use.new.emitter=true'; |
+ } |
+ print("compiling"); |
+ print("dart2jsPath: $dart2jsPath"); |
+ ProcessResult result = |
+ await Process.run(dart2jsPath, [dartFile, "--out=$outFile"], |
+ environment: env); |
+ if (result.exitCode != 0) { |
+ print("compilation failed"); |
+ print(result.stdout); |
+ print(result.stderr); |
+ return null; |
+ } |
+ print("compilation done"); |
+ return outFile; |
+ } |
+ |
+ Future measureDart(String filePrefix, { bool useSnapshot: false }) async { |
+ String dartFile = writeFile(filePrefix); |
+ String command = Platform.executable; |
+ Stopwatch watch = new Stopwatch(); |
+ Directory dir = Directory.systemTemp.createTempSync('snapshot'); |
+ try { |
+ String measuring = dartFile; |
+ if (useSnapshot) { |
+ print("creating snapshot"); |
+ measuring = new File("${dir.path}/measuring.snapshot").path; |
+ ProcessResult result = |
+ await Process.run(command, ["--snapshot=$measuring", dartFile]); |
+ if (result.exitCode != 0) { |
+ print("snapshot creation failed"); |
+ print(result.stdout); |
+ print(result.stderr); |
+ return; |
+ } |
+ } |
+ List<String> args = [measuring]; |
+ print("Running: $command ${args.join(' ')}"); |
+ int nbRuns = 10; |
+ int sum = 0; |
+ for (int i = 0; i < nbRuns; i++) { |
+ watch.reset(); |
+ watch.start(); |
+ ProcessResult result = await Process.run(command, args); |
+ int elapsedMilliseconds = watch.elapsedMilliseconds; |
+ if (result.exitCode != 0) { |
+ print("run failed"); |
+ print(result.stdout); |
+ print(result.stderr); |
+ return; |
+ } |
+ print(" measured time (including VM startup): $elapsedMilliseconds"); |
+ sum += elapsedMilliseconds; |
+ } |
+ if (sum != 0) { |
+ print(" mean: ${sum ~/ nbRuns}"); |
+ } |
+ } finally { |
+ dir.deleteSync(recursive: true); |
+ } |
+ } |
+ |
+ String get fileExtension => "dart"; |
+ String get description { |
+ if (shouldUseNewEmitter) return "dartNew"; |
+ return "dart"; |
+ } |
+} |
+ |
+main(List<String> arguments) async { |
+ String filePrefix = arguments.length > 0 |
+ ? arguments.first |
+ : Directory.systemTemp.uri.resolve("classes").path; |
+ |
+ Config config = new Config( |
+ nbClasses: 2000, |
+ nbMethodsPerClass: 20, |
+ fakeInstantiateClass: -1, |
+ instantiateClassesPercent: 20, |
+ shareCommonSuperclass: true, |
+ sameMethodNames: true, |
+ shouldPrintInMethod: true, |
+ nbWhileLoopsInBody: 1, |
+ shouldWrapProgram: true, |
+ shouldEmitCallAllMethods: true, |
+ shouldEmitInstantiatePreviousMethod: true |
+ ); |
+ |
+ var plain = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.tmpFunction, |
+ useMethodsObject: false, |
+ shouldInlineInherit: false); |
+ var plainProto = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.internalProto, |
+ useMethodsObject: false, |
+ shouldInlineInherit: false); |
+ var plainObjectCreate = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.objectCreate, |
+ useMethodsObject: false, |
+ shouldInlineInherit: false); |
+ var plainProtoInline = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.internalProto, |
+ useMethodsObject: false, |
+ shouldInlineInherit: true); |
+ var plainObjectCreateInline = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.objectCreate, |
+ useMethodsObject: false, |
+ shouldInlineInherit: true); |
+ var plainObj = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.tmpFunction, |
+ useMethodsObject: true, |
+ shouldInlineInherit: false); |
+ var plainProtoObj = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.internalProto, |
+ useMethodsObject: true, |
+ shouldInlineInherit: false); |
+ var plainObjectCreateObj = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.objectCreate, |
+ useMethodsObject: true, |
+ shouldInlineInherit: false); |
+ var plainProtoInlineObj = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.internalProto, |
+ useMethodsObject: true, |
+ shouldInlineInherit: true); |
+ var plainObjectCreateInlineObj = new PlainJavaScriptClassGenerator(config, |
+ prototypeApproach: PrototypeApproach.objectCreate, |
+ useMethodsObject: true, |
+ shouldInlineInherit: true); |
+ var es6 = new Es6ClassGenerator(config); |
+ var dart = new DartClassGenerator(config); |
+ var dartNew = new DartClassGenerator(config, shouldUseNewEmitter: true); |
+ |
+ await plain.measure(filePrefix); |
+ await plainProto.measure(filePrefix); |
+ await plainObjectCreate.measure(filePrefix); |
+ await plainProtoInline.measure(filePrefix); |
+ await plainObjectCreateInline.measure(filePrefix); |
+ await plainObj.measure(filePrefix); |
+ await plainProtoObj.measure(filePrefix); |
+ await plainObjectCreateObj.measure(filePrefix); |
+ await plainProtoInlineObj.measure(filePrefix); |
+ await plainObjectCreateInlineObj.measure(filePrefix); |
+ await es6.measure(filePrefix); |
+ await dartNew.measure(filePrefix); |
+ await dart.measure(filePrefix); |
+ await dart.measureDart(filePrefix); |
+ await dart.measureDart(filePrefix, useSnapshot: true); |
+} |