Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 class CodeEmitterNoEvalTask extends CodeEmitterTask { | 7 class CodeEmitterNoEvalTask extends CodeEmitterTask { |
| 8 CodeEmitterNoEvalTask(Compiler compiler, | 8 CodeEmitterNoEvalTask(Compiler compiler, |
| 9 Namer namer, | 9 Namer namer, |
| 10 bool generateSourceMap) | 10 bool generateSourceMap) |
| 11 : super(compiler, namer, generateSourceMap); | 11 : super(compiler, namer, generateSourceMap); |
| 12 | 12 |
| 13 String get generateGetterSetterFunction { | 13 bool get getterAndSetterCanBeImplementedByFieldSpec => false; |
| 14 return """ | |
| 15 function() { | |
| 16 throw 'Internal Error: no dynamic generation of getters and setters allowed'; | |
| 17 }"""; | |
| 18 } | |
| 19 | 14 |
| 20 String get defineClassFunction { | 15 void emitSuper(String superName, ClassBuilder builder) { |
| 21 return """ | 16 if (superName != '') { |
| 22 function(cls, constructor, prototype) { | 17 builder.addProperty('super', js.string(superName)); |
| 23 constructor.prototype = prototype; | |
| 24 constructor.builtin\$cls = cls; | |
| 25 return constructor; | |
| 26 }"""; | |
| 27 } | |
| 28 | |
| 29 String get protoSupportCheck { | |
| 30 // We don't modify the prototypes in CSP mode. Therefore we can have an | |
| 31 // easier prototype-check. | |
| 32 return 'var $supportsProtoName = !!{}.__proto__;\n'; | |
| 33 } | |
| 34 | |
| 35 String get finishIsolateConstructorFunction { | |
| 36 // We replace the old Isolate function with a new one that initializes | |
| 37 // all its field with the initial (and often final) value of all globals. | |
| 38 // | |
| 39 // We also copy over old values like the prototype, and the | |
| 40 // isolateProperties themselves. | |
| 41 return """ | |
| 42 function(oldIsolate) { | |
| 43 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; | |
| 44 function Isolate() { | |
| 45 for (var staticName in isolateProperties) { | |
| 46 if (Object.prototype.hasOwnProperty.call(isolateProperties, staticName)) { | |
| 47 this[staticName] = isolateProperties[staticName]; | |
| 48 } | |
| 49 } | 18 } |
| 50 // Use the newly created object as prototype. In Chrome this creates a | |
| 51 // hidden class for the object and makes sure it is fast to access. | |
| 52 function ForceEfficientMap() {} | |
| 53 ForceEfficientMap.prototype = this; | |
| 54 new ForceEfficientMap; | |
| 55 } | |
| 56 Isolate.prototype = oldIsolate.prototype; | |
| 57 Isolate.prototype.constructor = Isolate; | |
| 58 Isolate.${namer.isolatePropertiesName} = isolateProperties; | |
| 59 return Isolate; | |
| 60 }"""; | |
| 61 } | |
| 62 | |
| 63 String get lazyInitializerFunction { | |
| 64 return """ | |
| 65 function(prototype, staticName, fieldName, getterName, lazyValue, getter) { | |
| 66 $lazyInitializerLogic | |
| 67 }"""; | |
| 68 } | |
| 69 | |
| 70 js.Expression buildLazyInitializedGetter(VariableElement element) { | |
| 71 String isolate = namer.CURRENT_ISOLATE; | |
| 72 return js.fun([], | |
| 73 js.block1( | |
| 74 js.return_( | |
| 75 js.fieldAccess(js.use(isolate), namer.getName(element))))); | |
| 76 } | |
| 77 | |
| 78 js.Expression buildConstructor(String mangledName, List<String> fieldNames) { | |
| 79 return new js.NamedFunction( | |
| 80 new js.VariableDeclaration(mangledName), | |
| 81 new js.Fun( | |
| 82 fieldNames | |
| 83 .map((fieldName) => new js.Parameter(fieldName)) | |
| 84 .toList(), | |
| 85 new js.Block( | |
| 86 fieldNames.map((fieldName) => | |
| 87 new js.ExpressionStatement( | |
| 88 new js.Assignment( | |
| 89 new js.This().dot(fieldName), | |
| 90 new js.VariableUse(fieldName)))) | |
| 91 .toList()))); | |
| 92 } | 19 } |
| 93 | 20 |
| 94 void emitBoundClosureClassHeader(String mangledName, | 21 void emitBoundClosureClassHeader(String mangledName, |
| 95 String superName, | 22 String superName, |
| 96 List<String> fieldNames, | 23 List<String> fieldNames, |
| 97 ClassBuilder builder) { | 24 ClassBuilder builder) { |
| 98 builder.addProperty('', buildConstructor(mangledName, fieldNames)); | 25 builder.addProperty('', buildConstructor(mangledName, fieldNames)); |
| 99 builder.addProperty('super', js.string(superName)); | 26 emitSuper(superName, builder); |
| 27 } | |
| 28 | |
| 29 | |
| 30 void emitClassFields(ClassElement classElement, | |
| 31 ClassBuilder builder, | |
| 32 { String superClass: "", | |
| 33 bool classIsNative: false }) { | |
| 34 // Class fields are dynamically generated so they are have | |
|
ngeoffray
2013/02/28 13:11:31
are have -> have
kasperl
2013/02/28 13:18:48
Done.
| |
| 35 // to be emitted using getters and setters instead. | |
| 100 } | 36 } |
| 101 | 37 |
| 102 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { | 38 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { |
| 103 // Say we have a class A with fields b, c and d, where c needs a getter and | 39 // Say we have a class A with fields b, c and d, where c needs a getter and |
| 104 // d needs both a getter and a setter. Then we produce: | 40 // d needs both a getter and a setter. Then we produce: |
| 105 // - a constructor (directly into the given [buffer]): | 41 // - a constructor (directly into the given [buffer]): |
| 106 // function A(b, c, d) { this.b = b, this.c = c, this.d = d; } | 42 // function A(b, c, d) { this.b = b, this.c = c, this.d = d; } |
| 107 // - getters and setters (stored in the [explicitGettersSetters] list): | 43 // - getters and setters (stored in the [explicitGettersSetters] list): |
| 108 // get$c : function() { return this.c; } | 44 // get$c : function() { return this.c; } |
| 109 // get$d : function() { return this.d; } | 45 // get$d : function() { return this.d; } |
| 110 // set$d : function(x) { this.d = x; } | 46 // set$d : function(x) { this.d = x; } |
| 111 List<String> fields = <String>[]; | 47 List<String> fields = <String>[]; |
| 112 visitClassFields(classElement, (Element member, | 48 visitClassFields(classElement, (Element member, |
| 113 String name, | 49 String name, |
| 114 String accessorName, | 50 String accessorName, |
| 115 bool needsGetter, | 51 bool needsGetter, |
| 116 bool needsSetter, | 52 bool needsSetter, |
| 117 bool needsCheckedSetter) { | 53 bool needsCheckedSetter) { |
| 118 fields.add(name); | 54 fields.add(name); |
| 119 }); | 55 }); |
| 120 String constructorName = namer.safeName(classElement.name.slowToString()); | 56 String constructorName = namer.safeName(classElement.name.slowToString()); |
| 121 | |
| 122 builder.addProperty('', buildConstructor(constructorName, fields)); | 57 builder.addProperty('', buildConstructor(constructorName, fields)); |
| 123 } | 58 } |
| 124 | 59 |
| 125 void emitSuper(String superName, ClassBuilder builder) { | 60 List get defineClassFunction { |
| 126 if (superName != '') { | 61 return [new jsAst.FunctionDeclaration( |
| 127 builder.addProperty('super', js.string(superName)); | 62 new jsAst.VariableDeclaration('defineClass'), |
| 128 } | 63 js.fun(['cls', 'constructor', 'prototype'], |
| 64 [js[r'constructor.prototype = prototype'], | |
| 65 js[r'constructor.builtin$cls = cls'], | |
| 66 js.return_('constructor')]))]; | |
| 129 } | 67 } |
| 130 | 68 |
| 131 void emitClassFields(ClassElement classElement, | 69 List buildProtoSupportCheck() { |
| 132 ClassBuilder builder, | 70 // We don't modify the prototypes in CSP mode. Therefore we can have an |
| 133 { String superClass: "", | 71 // easier prototype-check. |
| 134 bool classIsNative: false}) { | 72 return [js['var $supportsProtoName = !(!({}.__proto__))']]; |
| 135 } | 73 } |
| 136 | 74 |
| 137 bool get getterAndSetterCanBeImplementedByFieldSpec => false; | 75 jsAst.Expression buildConstructor(String mangledName, |
| 76 List<String> fieldNames) { | |
| 77 return new jsAst.NamedFunction( | |
| 78 new jsAst.VariableDeclaration(mangledName), | |
| 79 js.fun(fieldNames, fieldNames.map( | |
| 80 (name) => js['this.$name = $name']).toList())); | |
| 81 } | |
| 82 | |
| 83 jsAst.FunctionDeclaration get generateAccessorFunction { | |
| 84 String message = | |
| 85 'Internal error: no dynamic generation of accessors allowed.'; | |
| 86 return new jsAst.FunctionDeclaration( | |
| 87 new jsAst.VariableDeclaration('generateAccessor'), | |
| 88 js.fun([], new jsAst.Throw(js.string(message)))); | |
| 89 } | |
| 90 | |
| 91 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { | |
| 92 String isolate = namer.CURRENT_ISOLATE; | |
| 93 String name = namer.getName(element); | |
| 94 return js.fun([], js.return_(js['$isolate.$name'])); | |
| 95 } | |
| 96 | |
| 97 jsAst.Fun get lazyInitializerFunction { | |
| 98 // function(prototype, staticName, fieldName, getterName, lazyValue, getter) { | |
|
ngeoffray
2013/02/28 13:11:31
line too long
kasperl
2013/02/28 13:18:48
Done.
| |
| 99 var parameters = <String>['prototype', 'staticName', 'fieldName', | |
| 100 'getterName', 'lazyValue', 'getter']; | |
| 101 return js.fun(parameters, addLazyInitializerLogic()); | |
| 102 } | |
| 103 | |
| 104 jsAst.Fun get finishIsolateConstructorFunction { | |
| 105 // We replace the old Isolate function with a new one that initializes | |
| 106 // all its field with the initial (and often final) value of all globals. | |
|
ngeoffray
2013/02/28 13:11:31
field -> fields
kasperl
2013/02/28 13:18:48
Done.
| |
| 107 // | |
| 108 // We also copy over old values like the prototype, and the | |
| 109 // isolateProperties themselves. | |
| 110 return js.fun('oldIsolate', [ | |
| 111 js['var isolateProperties = oldIsolate.${namer.isolatePropertiesName}'], | |
| 112 new jsAst.FunctionDeclaration( | |
| 113 new jsAst.VariableDeclaration('Isolate'), | |
| 114 js.fun([], [ | |
| 115 js['var hasOwnProperty = Object.prototype.hasOwnProperty'], | |
| 116 js.forIn('staticName', 'isolateProperties', | |
| 117 js.if_(js['hasOwnProperty.call(isolateProperties, staticName)'], | |
| 118 js['this[staticName] = isolateProperties[staticName]'])), | |
| 119 // Use the newly created object as prototype. In Chrome, | |
| 120 // this creates a hidden class for the object and makes | |
| 121 // sure it is fast to access. | |
| 122 new jsAst.FunctionDeclaration( | |
| 123 new jsAst.VariableDeclaration('ForceEfficientMap'), | |
| 124 js.fun([], [])), | |
| 125 js['ForceEfficientMap.prototype = this'], | |
| 126 js['new ForceEfficientMap()']])), | |
| 127 js['Isolate.prototype = oldIsolate.prototype'], | |
| 128 js['Isolate.prototype.constructor = Isolate'], | |
| 129 js['Isolate.${namer.isolatePropertiesName} = isolateProperties'], | |
| 130 js.return_('Isolate')]); | |
| 131 } | |
| 138 } | 132 } |
| OLD | NEW |