| 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 |