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 NativeEmitter { | 7 class NativeEmitter { |
8 | 8 |
9 CodeEmitterTask emitter; | 9 CodeEmitterTask emitter; |
10 CodeBuffer nativeBuffer; | 10 CodeBuffer nativeBuffer; |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 // An empty native class may be omitted since the superclass methods can be | 150 // An empty native class may be omitted since the superclass methods can be |
151 // located via the dispatch metadata. | 151 // located via the dispatch metadata. |
152 // TODO(sra): Also need to check there are no subclasses that will reference | 152 // TODO(sra): Also need to check there are no subclasses that will reference |
153 // this class. | 153 // this class. |
154 // bool hasOnlyGeneratedFields = builder.properties.length == 1; | 154 // bool hasOnlyGeneratedFields = builder.properties.length == 1; |
155 // if (hasOnlyGeneratedFields == 1 && !hasFields) return; | 155 // if (hasOnlyGeneratedFields == 1 && !hasFields) return; |
156 | 156 |
157 // Define interceptor class for [classElement]. | 157 // Define interceptor class for [classElement]. |
158 String className = backend.namer.getName(classElement); | 158 String className = backend.namer.getName(classElement); |
159 jsAst.Expression init = | 159 jsAst.Expression init = |
160 js[emitter.classesCollector][className].assign( | 160 js(emitter.classesCollector)[className].assign( |
161 builder.toObjectInitializer()); | 161 builder.toObjectInitializer()); |
162 mainBuffer.write(jsAst.prettyPrint(init, compiler)); | 162 mainBuffer.write(jsAst.prettyPrint(init, compiler)); |
163 mainBuffer.write('$N$n'); | 163 mainBuffer.write('$N$n'); |
164 | 164 |
165 emitter.needsDefineClass = true; | 165 emitter.needsDefineClass = true; |
166 | 166 |
167 // Define dispatch for [classElement]. | 167 // Define dispatch for [classElement]. |
168 String nativeTag = toNativeTag(classElement); | 168 String nativeTag = toNativeTag(classElement); |
169 String definer = directSubtypes[classElement] == null | 169 String definer = directSubtypes[classElement] == null |
170 ? defineNativeMethodsName | 170 ? defineNativeMethodsName |
171 : defineNativeMethodsNonleafName; | 171 : defineNativeMethodsNonleafName; |
172 | 172 |
173 // TODO(sra): Fix DOM generation. There is a missing proto in the picture | 173 // TODO(sra): Fix DOM generation. There is a missing proto in the picture |
174 // the DOM gives of the proto chain. We might need an annotation. | 174 // the DOM gives of the proto chain. We might need an annotation. |
175 if (nativeTag == 'HTMLElement') definer = defineNativeMethodsNonleafName; | 175 if (nativeTag == 'HTMLElement') definer = defineNativeMethodsNonleafName; |
176 | 176 |
177 jsAst.Expression definition = | 177 jsAst.Expression definition = |
178 js[definer]( | 178 js(definer)( |
179 [js.string(nativeTag), | 179 [js.string(nativeTag), |
180 js[backend.namer.isolateAccess(classElement)]]); | 180 js(backend.namer.isolateAccess(classElement))]); |
181 | 181 |
182 nativeBuffer.add(jsAst.prettyPrint(definition, compiler)); | 182 nativeBuffer.add(jsAst.prettyPrint(definition, compiler)); |
183 nativeBuffer.add('$N$n'); | 183 nativeBuffer.add('$N$n'); |
184 | 184 |
185 classesWithDynamicDispatch.add(classElement); | 185 classesWithDynamicDispatch.add(classElement); |
186 } | 186 } |
187 | 187 |
188 void finishGenerateNativeClasses() { | 188 void finishGenerateNativeClasses() { |
189 // TODO(sra): Put specialized version of getNativeMethods on | 189 // TODO(sra): Put specialized version of getNativeMethods on |
190 // `Object.prototype` to avoid checking in `getInterceptor` and | 190 // `Object.prototype` to avoid checking in `getInterceptor` and |
191 // specializations. | 191 // specializations. |
192 | 192 |
193 // jsAst.Expression call = js[defineNativeMethodsFinishName]([]); | 193 // jsAst.Expression call = js(defineNativeMethodsFinishName)([]); |
194 // nativeBuffer.add(jsAst.prettyPrint(call, compiler)); | 194 // nativeBuffer.add(jsAst.prettyPrint(call, compiler)); |
195 // nativeBuffer.add('$N$n'); | 195 // nativeBuffer.add('$N$n'); |
196 } | 196 } |
197 | 197 |
198 List<ClassElement> getDirectSubclasses(ClassElement cls) { | 198 List<ClassElement> getDirectSubclasses(ClassElement cls) { |
199 List<ClassElement> result = directSubtypes[cls]; | 199 List<ClassElement> result = directSubtypes[cls]; |
200 return result == null ? const<ClassElement>[] : result; | 200 return result == null ? const<ClassElement>[] : result; |
201 } | 201 } |
202 | 202 |
203 void potentiallyConvertDartClosuresToJs( | 203 void potentiallyConvertDartClosuresToJs( |
(...skipping 14 matching lines...) Expand all Loading... |
218 if (stubParameter.name == name) { | 218 if (stubParameter.name == name) { |
219 DartType type = parameter.computeType(compiler).unalias(compiler); | 219 DartType type = parameter.computeType(compiler).unalias(compiler); |
220 if (type is FunctionType) { | 220 if (type is FunctionType) { |
221 // The parameter type is a function type either directly or through | 221 // The parameter type is a function type either directly or through |
222 // typedef(s). | 222 // typedef(s). |
223 int arity = type.computeArity(); | 223 int arity = type.computeArity(); |
224 | 224 |
225 statements.add( | 225 statements.add( |
226 new jsAst.ExpressionStatement( | 226 new jsAst.ExpressionStatement( |
227 js.assign( | 227 js.assign( |
228 js[name], | 228 js(name), |
229 js[closureConverter]( | 229 js(closureConverter)( |
230 [js[name], | 230 [js(name), |
231 new jsAst.LiteralNumber('$arity')])))); | 231 new jsAst.LiteralNumber('$arity')])))); |
232 break; | 232 break; |
233 } | 233 } |
234 } | 234 } |
235 } | 235 } |
236 }); | 236 }); |
237 } | 237 } |
238 | 238 |
239 List<jsAst.Statement> generateParameterStubStatements( | 239 List<jsAst.Statement> generateParameterStubStatements( |
240 Element member, | 240 Element member, |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 // false, and will be overridden by subclasses when they have to | 481 // false, and will be overridden by subclasses when they have to |
482 // return true. | 482 // return true. |
483 void emitIsChecks() { | 483 void emitIsChecks() { |
484 for (ClassElement element in | 484 for (ClassElement element in |
485 Elements.sortedByPosition(emitter.checkedClasses)) { | 485 Elements.sortedByPosition(emitter.checkedClasses)) { |
486 if (!requiresNativeIsCheck(element)) continue; | 486 if (!requiresNativeIsCheck(element)) continue; |
487 if (element.isObject(compiler)) continue; | 487 if (element.isObject(compiler)) continue; |
488 // Add function for the is-test. | 488 // Add function for the is-test. |
489 String name = backend.namer.operatorIs(element); | 489 String name = backend.namer.operatorIs(element); |
490 addProperty(name, | 490 addProperty(name, |
491 js.fun([], js.return_(js['false']))); | 491 js.fun([], js.return_(js('false')))); |
492 // Add a function for the (trivial) substitution. | 492 // Add a function for the (trivial) substitution. |
493 addProperty(backend.namer.substitutionName(element), | 493 addProperty(backend.namer.substitutionName(element), |
494 js.fun([], js.return_(js['null']))); | 494 js.fun([], js.return_(js('null')))); |
495 } | 495 } |
496 } | 496 } |
497 emitIsChecks(); | 497 emitIsChecks(); |
498 | 498 |
499 jsAst.Expression makeCallOnThis(String functionName) { | 499 jsAst.Expression makeCallOnThis(String functionName) { |
500 // Because we know the function is intercepted, we need an extra | 500 // Because we know the function is intercepted, we need an extra |
501 // parameter. | 501 // parameter. |
502 return js.fun(['_'], js.return_(js['$functionName(this)'])); | 502 return js.fun(['_'], js.return_(js('$functionName(this)'))); |
503 } | 503 } |
504 | 504 |
505 if (!nativeClasses.isEmpty) { | 505 if (!nativeClasses.isEmpty) { |
506 emitDynamicDispatchMetadata(); | 506 emitDynamicDispatchMetadata(); |
507 | 507 |
508 // In order to have the toString method on every native class, | 508 // In order to have the toString method on every native class, |
509 // we must patch the JS Object prototype with a helper method. | 509 // we must patch the JS Object prototype with a helper method. |
510 String toStringName = backend.namer.publicInstanceMethodNameByArity( | 510 String toStringName = backend.namer.publicInstanceMethodNameByArity( |
511 const SourceString('toString'), 0); | 511 const SourceString('toString'), 0); |
512 addProperty(toStringName, makeCallOnThis(toStringHelperName)); | 512 addProperty(toStringName, makeCallOnThis(toStringHelperName)); |
513 | 513 |
514 // Same as above, but for hashCode. | 514 // Same as above, but for hashCode. |
515 String hashCodeName = | 515 String hashCodeName = |
516 backend.namer.publicGetterName(const SourceString('hashCode')); | 516 backend.namer.publicGetterName(const SourceString('hashCode')); |
517 addProperty(hashCodeName, makeCallOnThis(hashCodeHelperName)); | 517 addProperty(hashCodeName, makeCallOnThis(hashCodeHelperName)); |
518 | 518 |
519 // Same as above, but for operator==. | 519 // Same as above, but for operator==. |
520 String equalsName = backend.namer.publicInstanceMethodNameByArity( | 520 String equalsName = backend.namer.publicInstanceMethodNameByArity( |
521 const SourceString('=='), 1); | 521 const SourceString('=='), 1); |
522 // Because we know the function is intercepted, we need an extra | 522 // Because we know the function is intercepted, we need an extra |
523 // parameter. | 523 // parameter. |
524 addProperty(equalsName, js.fun(['_', 'a'], | 524 addProperty(equalsName, js.fun(['_', 'a'], |
525 js.return_(js['this === a']))); | 525 js.return_(js('this === a')))); |
526 | 526 |
527 // If the native emitter has been asked to take care of the | 527 // If the native emitter has been asked to take care of the |
528 // noSuchMethod handlers, we do that now. | 528 // noSuchMethod handlers, we do that now. |
529 if (handleNoSuchMethod) { | 529 if (handleNoSuchMethod) { |
530 emitter.emitNoSuchMethodHandlers(addProperty); | 530 emitter.emitNoSuchMethodHandlers(addProperty); |
531 } | 531 } |
532 } | 532 } |
533 | 533 |
534 // If we have any properties to add to Object.prototype, we run | 534 // If we have any properties to add to Object.prototype, we run |
535 // through them and add them using defineProperty. | 535 // through them and add them using defineProperty. |
536 if (!objectProperties.isEmpty) { | 536 if (!objectProperties.isEmpty) { |
537 jsAst.Expression init = | 537 jsAst.Expression init = |
538 js.fun(['table'], | 538 js.fun(['table'], |
539 new jsAst.ForIn( | 539 new jsAst.ForIn( |
540 new jsAst.VariableDeclarationList( | 540 new jsAst.VariableDeclarationList( |
541 [new jsAst.VariableInitialization( | 541 [new jsAst.VariableInitialization( |
542 new jsAst.VariableDeclaration('key'), | 542 new jsAst.VariableDeclaration('key'), |
543 null)]), | 543 null)]), |
544 js['table'], | 544 js('table'), |
545 new jsAst.ExpressionStatement( | 545 new jsAst.ExpressionStatement( |
546 js['$defPropName(Object.prototype, key, table[key])'])))( | 546 js('$defPropName(Object.prototype, key, table[key])'))))( |
547 new jsAst.ObjectInitializer(objectProperties)); | 547 new jsAst.ObjectInitializer(objectProperties)); |
548 | 548 |
549 if (emitter.compiler.enableMinification) targetBuffer.add(';'); | 549 if (emitter.compiler.enableMinification) targetBuffer.add(';'); |
550 targetBuffer.add(jsAst.prettyPrint( | 550 targetBuffer.add(jsAst.prettyPrint( |
551 new jsAst.ExpressionStatement(init), compiler)); | 551 new jsAst.ExpressionStatement(init), compiler)); |
552 targetBuffer.add('\n'); | 552 targetBuffer.add('\n'); |
553 } | 553 } |
554 | 554 |
555 targetBuffer.add(nativeBuffer); | 555 targetBuffer.add(nativeBuffer); |
556 targetBuffer.add('\n'); | 556 targetBuffer.add('\n'); |
557 } | 557 } |
558 } | 558 } |
OLD | NEW |