Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
| 6 | 6 |
| 7 import '../../dart2jslib.dart' show Compiler; | 7 import '../../dart2jslib.dart' show Compiler; |
| 8 import '../../dart_types.dart' show DartType; | |
| 8 import '../../js/js.dart' as js; | 9 import '../../js/js.dart' as js; |
| 9 import '../../js_backend/js_backend.dart' show | 10 import '../../js_backend/js_backend.dart' show |
| 10 JavaScriptBackend, | 11 JavaScriptBackend, |
| 11 Namer, | 12 Namer, |
| 12 ConstantEmitter; | 13 ConstantEmitter; |
| 13 | 14 |
| 14 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show | 15 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show |
| 15 DEFERRED_LIBRARY_URIS, | 16 DEFERRED_LIBRARY_URIS, |
| 16 DEFERRED_LIBRARY_HASHES, | 17 DEFERRED_LIBRARY_HASHES, |
| 17 GET_TYPE_FROM_NAME, | 18 GET_TYPE_FROM_NAME, |
| 18 INITIALIZE_LOADED_HUNK, | 19 INITIALIZE_LOADED_HUNK, |
| 19 IS_HUNK_INITIALIZED, | 20 IS_HUNK_INITIALIZED, |
| 20 IS_HUNK_LOADED, | 21 IS_HUNK_LOADED, |
| 21 MANGLED_GLOBAL_NAMES, | 22 MANGLED_GLOBAL_NAMES, |
| 22 METADATA, | 23 METADATA, |
| 23 TYPE_TO_INTERCEPTOR_MAP; | 24 TYPE_TO_INTERCEPTOR_MAP; |
| 24 | 25 |
| 25 import '../js_emitter.dart' show NativeGenerator; | 26 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; |
| 26 import '../model.dart'; | 27 import '../model.dart'; |
| 27 | 28 |
| 29 | |
| 28 class ModelEmitter { | 30 class ModelEmitter { |
| 29 final Compiler compiler; | 31 final Compiler compiler; |
| 30 final Namer namer; | 32 final Namer namer; |
| 31 final ConstantEmitter constantEmitter; | 33 final ConstantEmitter constantEmitter; |
| 32 | 34 |
| 33 JavaScriptBackend get backend => compiler.backend; | 35 JavaScriptBackend get backend => compiler.backend; |
| 34 | 36 |
| 35 /// For deferred loading we communicate the initializers via this global var. | 37 /// For deferred loading we communicate the initializers via this global var. |
| 36 static const String deferredInitializersGlobal = | 38 static const String deferredInitializersGlobal = |
| 37 r"$__dart_deferred_initializers__"; | 39 r"$__dart_deferred_initializers__"; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 } else { | 103 } else { |
| 102 nativeBoilerplate = js.js.statement(";"); | 104 nativeBoilerplate = js.js.statement(";"); |
| 103 } | 105 } |
| 104 | 106 |
| 105 js.Expression code = new js.ArrayInitializer(elements); | 107 js.Expression code = new js.ArrayInitializer(elements); |
| 106 | 108 |
| 107 return js.js.statement( | 109 return js.js.statement( |
| 108 boilerplate, | 110 boilerplate, |
| 109 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 111 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 110 'holders': emitHolders(fragment.holders), | 112 'holders': emitHolders(fragment.holders), |
| 113 'tearOff': buildTearOffCode(backend), | |
| 114 'parseFunctionDescriptor': | |
| 115 js.js.statement(parseFunctionDescriptorBoilerplate), | |
| 111 'cyclicThrow': | 116 'cyclicThrow': |
| 112 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 117 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
| 113 'outputContainsConstantList': program.outputContainsConstantList, | 118 'outputContainsConstantList': program.outputContainsConstantList, |
| 114 'embeddedGlobals': emitEmbeddedGlobals(program), | 119 'embeddedGlobals': emitEmbeddedGlobals(program), |
| 115 'constants': emitConstants(fragment.constants), | 120 'constants': emitConstants(fragment.constants), |
| 116 'staticNonFinals': | 121 'staticNonFinals': |
| 117 emitStaticNonFinalFields(fragment.staticNonFinalFields), | 122 emitStaticNonFinalFields(fragment.staticNonFinalFields), |
| 118 'nativeBoilerplate': nativeBoilerplate, | 123 'nativeBoilerplate': nativeBoilerplate, |
| 119 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 124 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 120 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 125 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 List elements = [js.string(cls.superclassName), | 393 List elements = [js.string(cls.superclassName), |
| 389 js.number(cls.superclassHolderIndex)]; | 394 js.number(cls.superclassHolderIndex)]; |
| 390 | 395 |
| 391 if (cls.isMixinApplication) { | 396 if (cls.isMixinApplication) { |
| 392 MixinApplication mixin = cls; | 397 MixinApplication mixin = cls; |
| 393 elements.add(js.string(mixin.mixinClass.name)); | 398 elements.add(js.string(mixin.mixinClass.name)); |
| 394 elements.add(js.number(mixin.mixinClass.holder.index)); | 399 elements.add(js.number(mixin.mixinClass.holder.index)); |
| 395 } else { | 400 } else { |
| 396 elements.add(_generateConstructor(cls)); | 401 elements.add(_generateConstructor(cls)); |
| 397 } | 402 } |
| 398 Iterable<Method> methods = cls.methods.expand((Method method) { | 403 Iterable<Method> methods = cls.methods; |
| 399 // TODO(floitsch): can there be anything else than a DartMethod? | |
| 400 if (method is DartMethod) { | |
| 401 return [method]..addAll(method.parameterStubs); | |
| 402 } else { | |
| 403 return [method]; | |
| 404 } | |
| 405 }); | |
| 406 Iterable<Method> isChecks = cls.isChecks; | 404 Iterable<Method> isChecks = cls.isChecks; |
| 407 Iterable<Method> callStubs = cls.callStubs; | 405 Iterable<Method> callStubs = cls.callStubs; |
| 408 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; | 406 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; |
| 409 Iterable<Method> gettersSetters = _generateGettersSetters(cls); | 407 Iterable<Method> gettersSetters = _generateGettersSetters(cls); |
| 410 Iterable<Method> allMethods = | 408 Iterable<Method> allMethods = |
| 411 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters] | 409 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters] |
| 412 .expand((x) => x); | 410 .expand((x) => x); |
| 413 elements.addAll(allMethods.expand((e) => [js.string(e.name), e.code])); | 411 elements.addAll(allMethods.expand(emitInstanceMethod)); |
| 412 | |
| 414 return unparse(compiler, new js.ArrayInitializer(elements)); | 413 return unparse(compiler, new js.ArrayInitializer(elements)); |
| 415 } | 414 } |
| 416 | 415 |
| 417 js.Expression emitLazyInitializer(StaticField field) { | 416 js.Expression emitLazyInitializer(StaticField field) { |
| 418 assert(field.isLazy); | 417 assert(field.isLazy); |
| 419 return unparse(compiler, field.code); | 418 return unparse(compiler, field.code); |
| 420 } | 419 } |
| 421 | 420 |
| 421 /// JavaScript code template that implements parsing of a function descriptor. | |
| 422 /// Descriptors are used in place of the actual JavaScript function | |
| 423 /// definition in the output if additional information needs to be passed to | |
| 424 /// facilitate the generation of tearOffs at runtime. The format is an array | |
| 425 /// with the following fields: | |
| 426 /// | |
| 427 /// [Method.code] | |
| 428 /// [DartMethod.callName] | |
| 429 /// [DartMethod.tearOffName] | |
| 430 /// [JavaScriptBackend.isInterceptedMethod] | |
| 431 /// functionType | |
| 432 /// | |
| 433 /// followed by | |
| 434 /// | |
| 435 /// [ParameterStubMethod.name] | |
| 436 /// [ParameterStubMethod.code] | |
| 437 /// | |
| 438 /// for each stub in [DartMethod.parameterStubs]. | |
| 439 | |
| 440 static final String parseFunctionDescriptorBoilerplate = r""" | |
| 441 function parseFunctionDescriptor(proto, name, descriptor) { | |
| 442 if (descriptor instanceof Array) { | |
| 443 proto[name] = descriptor[0]; | |
| 444 var funs = [descriptor[0]]; | |
| 445 funs[0].$callName = descriptor[1]; | |
| 446 for (var pos = 5; pos < descriptor.length; pos += 3) { | |
| 447 var stub = descriptor[pos+2]; | |
|
floitsch
2015/02/03 19:40:02
nit: "pos + 2"
(and "pos + 1" in the next line).
herhut
2015/02/03 21:18:58
Done.
| |
| 448 stub.$callName = descriptor[pos+1]; | |
| 449 proto[descriptor[pos]] = stub; | |
| 450 funs.push(stub); | |
| 451 } | |
| 452 if (descriptor[2] != null) { | |
| 453 var isIntercepted = descriptor[3]; | |
| 454 var reflectionInfo = descriptor[4]; | |
| 455 proto[descriptor[2]] = | |
| 456 tearOff(funs, reflectionInfo, false, name, isIntercepted); | |
| 457 } | |
| 458 } else { | |
| 459 proto[name] = descriptor; | |
| 460 } | |
| 461 } | |
| 462 """; | |
| 463 | |
| 464 js.Expression _generateFunctionType(DartType memberType) { | |
| 465 if (memberType.containsTypeVariables) { | |
| 466 js.Expression thisAccess = js.js(r'this.$receiver'); | |
| 467 return backend.rti.getSignatureEncoding(memberType, thisAccess); | |
| 468 } else { | |
| 469 return js.number(backend.emitter.metadataCollector.reifyType(memberType)); | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 Iterable<js.Expression> emitInstanceMethod(Method method) { | |
| 474 | |
| 475 List<js.Expression> makeNameCodePair(Method method) { | |
| 476 return [js.string(method.name), method.code]; | |
| 477 } | |
| 478 | |
| 479 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { | |
| 480 js.Expression callName = stub.callName == null | |
| 481 ? new js.LiteralNull() | |
| 482 : js.string(stub.callName); | |
| 483 return [js.string(stub.name), callName, stub.code]; | |
| 484 } | |
| 485 | |
| 486 if (method is DartMethod) { | |
| 487 if (method.needsTearOff) { | |
| 488 /// See [parseFunctionDescriptorBoilerplate] for a full description of | |
| 489 /// the format. | |
| 490 // [name, [function, callName, tearOffName, isIntercepted, functionType, | |
| 491 // stub1_name, stub1_callName, stub1_code, ...] | |
| 492 bool isIntercepted = backend.isInterceptedMethod(method.element); | |
| 493 var data = [method.code]; | |
| 494 data.add(js.string(method.callName)); | |
| 495 data.add(js.string(method.tearOffName)); | |
| 496 data.add(new js.LiteralBool(isIntercepted)); | |
| 497 data.add(_generateFunctionType(method.type)); | |
| 498 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); | |
| 499 return [js.string(method.name), new js.ArrayInitializer(data)]; | |
| 500 } else { | |
| 501 // TODO(floitsch): not the most efficient way... | |
| 502 return ([method]..addAll(method.parameterStubs)) | |
| 503 .expand(makeNameCodePair); | |
| 504 } | |
| 505 } else { | |
| 506 return makeNameCodePair(method); | |
| 507 } | |
| 508 } | |
| 509 | |
| 422 Iterable<js.Expression> emitStaticMethod(StaticMethod method) { | 510 Iterable<js.Expression> emitStaticMethod(StaticMethod method) { |
| 423 js.Expression holderIndex = js.number(method.holder.index); | 511 js.Expression holderIndex = js.number(method.holder.index); |
| 424 List<js.Expression> output = <js.Expression>[]; | 512 List<js.Expression> output = <js.Expression>[]; |
| 425 | 513 |
| 426 void _addMethod(Method method) { | 514 void _addMethod(Method method) { |
| 427 js.Expression unparsed = unparse(compiler, method.code); | 515 js.Expression unparsed = unparse(compiler, method.code); |
| 428 output.add(js.string(method.name)); | 516 output.add(js.string(method.name)); |
| 429 output.add(holderIndex); | 517 output.add(holderIndex); |
| 430 output.add(unparsed); | 518 output.add(unparsed); |
| 431 } | 519 } |
| 432 | 520 |
| 521 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { | |
| 522 js.Expression callName = stub.callName == null | |
| 523 ? new js.LiteralNull() | |
| 524 : js.string(stub.callName); | |
| 525 return [js.string(stub.name), callName, unparse(compiler, stub.code)]; | |
| 526 } | |
| 527 | |
| 433 _addMethod(method); | 528 _addMethod(method); |
| 434 // TODO(floitsch): can there be anything else than a StaticDartMethod? | 529 // TODO(floitsch): can there be anything else than a StaticDartMethod? |
|
floitsch
2015/02/03 19:40:02
Well now there can be, since you run it over every
herhut
2015/02/03 21:18:58
Doesn't this still only run over static methods?
floitsch
2015/02/03 21:44:17
Never mind...
| |
| 435 if (method is StaticDartMethod) { | 530 if (method is StaticDartMethod) { |
| 436 method.parameterStubs.forEach(_addMethod); | 531 if (method.needsTearOff) { |
| 532 /// The format emitted is the same as for the parser specified at | |
| 533 /// [parseFunctionDescriptorBoilerplate] except for the missing | |
| 534 /// field whether the method is intercepted. | |
| 535 // [name, [function, callName, tearOffName, functionType, | |
| 536 // stub1_name, stub1_callName, stub1_code, ...] | |
| 537 var data = [unparse(compiler, method.code)]; | |
| 538 data.add(js.string(method.callName)); | |
| 539 data.add(js.string(method.tearOffName)); | |
| 540 data.add(_generateFunctionType(method.type)); | |
| 541 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); | |
| 542 return [js.string(method.name), holderIndex, new js.ArrayInitializer(dat a)]; | |
|
floitsch
2015/02/03 19:40:02
long line.
herhut
2015/02/03 21:18:58
Done.
| |
| 543 } else { | |
| 544 method.parameterStubs.forEach(_addMethod); | |
| 545 } | |
| 437 } | 546 } |
| 438 return output; | 547 return output; |
| 439 } | 548 } |
| 440 | 549 |
| 441 static final String boilerplate = """ | 550 static final String boilerplate = """ |
| 442 { | 551 { |
| 443 // Declare deferred-initializer global. | 552 // Declare deferred-initializer global. |
| 444 #deferredInitializer; | 553 #deferredInitializer; |
| 445 | 554 |
| 446 !function(start, program) { | 555 !function(start, program) { |
| 447 | |
| 448 // Initialize holder objects. | 556 // Initialize holder objects. |
| 449 #holders; | 557 #holders; |
| 450 | 558 |
| 559 // Counter to generate unique names for tear offs. | |
| 560 var functionCounter = 0; | |
|
floitsch
2015/02/03 19:40:02
:/
Can this be emitted with the tear-off function?
herhut
2015/02/03 21:18:58
In a separate CL to do it for both emitters.
floitsch
2015/02/03 21:44:17
Acknowledged.
| |
| 561 | |
| 451 function setupProgram() { | 562 function setupProgram() { |
| 452 for (var i = 0; i < program.length - 1; i++) { | 563 for (var i = 0; i < program.length - 1; i++) { |
| 453 setupLibrary(program[i]); | 564 setupLibrary(program[i]); |
| 454 } | 565 } |
| 455 setupLazyStatics(program[i]); | 566 setupLazyStatics(program[i]); |
| 456 } | 567 } |
| 457 | 568 |
| 458 function setupLibrary(library) { | 569 function setupLibrary(library) { |
| 459 var statics = library[0]; | 570 var statics = library[0]; |
| 460 for (var i = 0; i < statics.length; i += 3) { | 571 for (var i = 0; i < statics.length; i += 3) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 474 for (var i = 0; i < statics.length; i += 4) { | 585 for (var i = 0; i < statics.length; i += 4) { |
| 475 var name = statics[i]; | 586 var name = statics[i]; |
| 476 var getterName = statics[i + 1]; | 587 var getterName = statics[i + 1]; |
| 477 var holderIndex = statics[i + 2]; | 588 var holderIndex = statics[i + 2]; |
| 478 var initializer = statics[i + 3]; | 589 var initializer = statics[i + 3]; |
| 479 setupLazyStatic(name, getterName, holders[holderIndex], initializer); | 590 setupLazyStatic(name, getterName, holders[holderIndex], initializer); |
| 480 } | 591 } |
| 481 } | 592 } |
| 482 | 593 |
| 483 function setupStatic(name, holder, descriptor) { | 594 function setupStatic(name, holder, descriptor) { |
| 484 holder[name] = function() { | 595 if (typeof descriptor == 'string') { |
| 485 var method = compile(name, descriptor); | 596 holder[name] = function() { |
| 486 holder[name] = method; | 597 var method = compile(name, descriptor); |
| 487 return method.apply(this, arguments); | 598 holder[name] = method; |
| 488 }; | 599 return method.apply(this, arguments); |
| 600 }; | |
| 601 } else { | |
| 602 // Parse the tear off information and generate compile handlers. | |
| 603 // TODO(herhut): Share parser with instance methods. | |
|
floitsch
2015/02/03 19:40:02
I'm not sure that's worth the effort, but I agree
herhut
2015/02/03 21:18:58
Acknowledged.
| |
| 604 function compileAllStubs() { | |
| 605 var funs; | |
| 606 var fun = compile(name, descriptor[0]); | |
| 607 fun.\$callName = descriptor[1]; | |
| 608 holder[name] = fun; | |
| 609 funs = [fun]; | |
| 610 for (var pos = 4; pos < descriptor.length; pos += 3) { | |
| 611 var stubName = descriptor[pos]; | |
| 612 fun = compile(stubName, descriptor[pos + 2]); | |
| 613 fun.\$callName = descriptor[pos + 1]; | |
| 614 holder[stubName] = fun; | |
| 615 funs.push(fun); | |
| 616 } | |
| 617 if (descriptor[2] != null) { // tear-off name. | |
| 618 // functions, reflectionInfo, isStatic, name, isIntercepted. | |
| 619 holder[descriptor[2]] = | |
| 620 tearOff(funs, descriptor[3], true, name, false); | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 function setupCompileAllAndDelegateStub(name) { | |
| 625 holder[name] = function() { | |
| 626 compileAllStubs(); | |
| 627 return holder[name].apply(this, arguments); | |
| 628 }; | |
| 629 } | |
| 630 | |
| 631 setupCompileAllAndDelegateStub(name); | |
| 632 for (var pos = 4; pos < descriptor.length; pos += 3) { | |
| 633 setupCompileAllAndDelegateStub(descriptor[pos]); | |
| 634 } | |
| 635 if (descriptor[2] != null) { // tear-off name. | |
| 636 setupCompileAllAndDelegateStub(descriptor[2]) | |
| 637 } | |
| 638 } | |
| 489 } | 639 } |
| 490 | 640 |
| 491 function setupLazyStatic(name, getterName, holder, descriptor) { | 641 function setupLazyStatic(name, getterName, holder, descriptor) { |
| 492 holder[name] = null; | 642 holder[name] = null; |
| 493 holder[getterName] = function() { | 643 holder[getterName] = function() { |
| 494 var initializer = compile(name, descriptor); | 644 var initializer = compile(name, descriptor); |
| 495 holder[getterName] = function() { #cyclicThrow(name) }; | 645 holder[getterName] = function() { #cyclicThrow(name) }; |
| 496 var result; | 646 var result; |
| 497 var sentinelInProgress = descriptor; | 647 var sentinelInProgress = descriptor; |
| 498 try { | 648 try { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 526 constructor.apply(object, arguments); | 676 constructor.apply(object, arguments); |
| 527 return object; | 677 return object; |
| 528 }; | 678 }; |
| 529 | 679 |
| 530 // We store the ensureResolved function on the patch function to make it | 680 // We store the ensureResolved function on the patch function to make it |
| 531 // possible to resolve superclass references without constructing instances. | 681 // possible to resolve superclass references without constructing instances. |
| 532 patch.ensureResolved = ensureResolved; | 682 patch.ensureResolved = ensureResolved; |
| 533 holder[name] = patch; | 683 holder[name] = patch; |
| 534 } | 684 } |
| 535 | 685 |
| 686 #tearOff; | |
| 687 | |
| 688 #parseFunctionDescriptor; | |
| 689 | |
| 536 function compileConstructor(name, descriptor) { | 690 function compileConstructor(name, descriptor) { |
| 537 descriptor = compile(name, descriptor); | 691 descriptor = compile(name, descriptor); |
| 538 var prototype = determinePrototype(descriptor); | 692 var prototype = determinePrototype(descriptor); |
| 539 var constructor; | 693 var constructor; |
| 540 // $mixinFormatDescription. | 694 // $mixinFormatDescription. |
| 541 if (typeof descriptor[2] !== 'function') { | 695 if (typeof descriptor[2] !== 'function') { |
| 542 constructor = compileMixinConstructor(name, prototype, descriptor); | 696 constructor = compileMixinConstructor(name, prototype, descriptor); |
| 543 for (var i = 4; i < descriptor.length; i += 2) { | 697 for (var i = 4; i < descriptor.length; i += 2) { |
| 544 prototype[descriptor[i]] = descriptor[i + 1]; | 698 parseFunctionDescriptor(prototype, descriptor, descriptor[i + 1]); |
| 545 } | 699 } |
| 546 } else { | 700 } else { |
| 547 constructor = descriptor[2]; | 701 constructor = descriptor[2]; |
| 548 for (var i = 3; i < descriptor.length; i += 2) { | 702 for (var i = 3; i < descriptor.length; i += 2) { |
| 549 prototype[descriptor[i]] = descriptor[i + 1]; | 703 parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]); |
| 550 } | 704 } |
| 551 } | 705 } |
| 552 constructor.builtin\$cls = name; // Needed for RTI. | 706 constructor.builtin\$cls = name; // Needed for RTI. |
| 553 constructor.prototype = prototype; | 707 constructor.prototype = prototype; |
| 554 prototype[#operatorIsPrefix + name] = constructor; | 708 prototype[#operatorIsPrefix + name] = constructor; |
| 555 prototype.constructor = constructor; | 709 prototype.constructor = constructor; |
| 556 return constructor; | 710 return constructor; |
| 557 } | 711 } |
| 558 | 712 |
| 559 function compileMixinConstructor(name, prototype, descriptor) { | 713 function compileMixinConstructor(name, prototype, descriptor) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 | 780 |
| 627 var end = Date.now(); | 781 var end = Date.now(); |
| 628 print('Setup: ' + (end - start) + ' ms.'); | 782 print('Setup: ' + (end - start) + ' ms.'); |
| 629 | 783 |
| 630 #main(); // Start main. | 784 #main(); // Start main. |
| 631 | 785 |
| 632 }(Date.now(), #code) | 786 }(Date.now(), #code) |
| 633 }"""; | 787 }"""; |
| 634 | 788 |
| 635 } | 789 } |
| OLD | NEW |