| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 part of dart2js.js_emitter; | |
| 6 | |
| 7 /// This class should morph into something that makes it easy to build | |
| 8 /// JavaScript representations of libraries, class-sides, and instance-sides. | |
| 9 /// Initially, it is just a placeholder for code that is moved from | |
| 10 /// [CodeEmitterTask]. | |
| 11 class ContainerBuilder extends CodeEmitterHelper { | |
| 12 | |
| 13 void addMemberMethod(DartMethod method, ClassBuilder builder) { | |
| 14 MethodElement member = method.element; | |
| 15 jsAst.Name name = method.name; | |
| 16 FunctionSignature parameters = member.functionSignature; | |
| 17 jsAst.Expression code = method.code; | |
| 18 bool needsStubs = method.parameterStubs.isNotEmpty; | |
| 19 bool canBeApplied = method.canBeApplied; | |
| 20 bool canBeReflected = method.canBeReflected; | |
| 21 bool canTearOff = method.needsTearOff; | |
| 22 jsAst.Name tearOffName = method.tearOffName; | |
| 23 bool isClosure = method is InstanceMethod && method.isClosure; | |
| 24 jsAst.Name superAlias = method is InstanceMethod ? method.aliasName : null; | |
| 25 bool hasSuperAlias = superAlias != null; | |
| 26 jsAst.Expression memberTypeExpression = method.functionType; | |
| 27 | |
| 28 bool needStructuredInfo = | |
| 29 canTearOff || canBeReflected || canBeApplied || hasSuperAlias; | |
| 30 | |
| 31 emitter.interceptorEmitter.recordMangledNameOfMemberMethod(member, name); | |
| 32 | |
| 33 if (!needStructuredInfo) { | |
| 34 compiler.dumpInfoTask.registerElementAst(member, | |
| 35 builder.addProperty(name, code)); | |
| 36 | |
| 37 for (ParameterStubMethod stub in method.parameterStubs) { | |
| 38 assert(stub.callName == null); | |
| 39 jsAst.Property property = builder.addProperty(stub.name, stub.code); | |
| 40 compiler.dumpInfoTask.registerElementAst(member, property); | |
| 41 emitter.interceptorEmitter | |
| 42 .recordMangledNameOfMemberMethod(member, stub.name); | |
| 43 } | |
| 44 return; | |
| 45 } | |
| 46 emitter.needsStructuredMemberInfo = true; | |
| 47 | |
| 48 // This element is needed for reflection or needs additional stubs or has a | |
| 49 // super alias. So we need to retain additional information. | |
| 50 | |
| 51 // The information is stored in an array with this format: | |
| 52 // | |
| 53 // 1. The alias name for this function (optional). | |
| 54 // 2. The JS function for this member. | |
| 55 // 3. First stub. | |
| 56 // 4. Name of first stub. | |
| 57 // ... | |
| 58 // M. Call name of this member. | |
| 59 // M+1. Call name of first stub. | |
| 60 // ... | |
| 61 // N. Getter name for tearOff. | |
| 62 // N+1. (Required parameter count << 1) + (member.isAccessor ? 1 : 0). | |
| 63 // N+2. (Optional parameter count << 1) + | |
| 64 // (parameters.optionalParametersAreNamed ? 1 : 0). | |
| 65 // N+3. Index to function type in constant pool. | |
| 66 // N+4. First default argument. | |
| 67 // ... | |
| 68 // O. First parameter name (if needed for reflection or Function.apply). | |
| 69 // ... | |
| 70 // P. Unmangled name (if reflectable). | |
| 71 // P+1. First metadata (if reflectable). | |
| 72 // ... | |
| 73 // TODO(ahe): Consider one of the parameter counts can be replaced by the | |
| 74 // length property of the JavaScript function object. | |
| 75 | |
| 76 List<jsAst.Expression> expressions = <jsAst.Expression>[]; | |
| 77 | |
| 78 // Create the optional aliasing entry if this method is called via super. | |
| 79 if (hasSuperAlias) { | |
| 80 expressions.add(js.quoteName(superAlias)); | |
| 81 } | |
| 82 | |
| 83 expressions.add(code); | |
| 84 | |
| 85 bool onlyNeedsSuperAlias = | |
| 86 !(canTearOff || canBeReflected || canBeApplied || needsStubs); | |
| 87 | |
| 88 if (onlyNeedsSuperAlias) { | |
| 89 jsAst.ArrayInitializer arrayInit = | |
| 90 new jsAst.ArrayInitializer(expressions); | |
| 91 compiler.dumpInfoTask.registerElementAst(member, | |
| 92 builder.addProperty(name, arrayInit)); | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 jsAst.Literal callSelectorString; | |
| 97 if (method.callName == null) { | |
| 98 callSelectorString = new jsAst.LiteralNull(); | |
| 99 } else { | |
| 100 callSelectorString = js.quoteName(method.callName); | |
| 101 } | |
| 102 | |
| 103 // On [requiredParameterCount], the lower bit is set if this method can be | |
| 104 // called reflectively. | |
| 105 int requiredParameterCount = parameters.requiredParameterCount << 1; | |
| 106 if (member.isAccessor) requiredParameterCount++; | |
| 107 | |
| 108 int optionalParameterCount = parameters.optionalParameterCount << 1; | |
| 109 if (parameters.optionalParametersAreNamed) optionalParameterCount++; | |
| 110 | |
| 111 List tearOffInfo = [callSelectorString]; | |
| 112 | |
| 113 for (ParameterStubMethod stub in method.parameterStubs) { | |
| 114 jsAst.Name invocationName = stub.name; | |
| 115 emitter.interceptorEmitter | |
| 116 .recordMangledNameOfMemberMethod(member, invocationName); | |
| 117 | |
| 118 expressions.add(stub.code); | |
| 119 if (member.isInstanceMember) { | |
| 120 expressions.add(js.quoteName(invocationName)); | |
| 121 } | |
| 122 jsAst.Name callName = stub.callName; | |
| 123 jsAst.Literal callSelectorString = | |
| 124 (callName == null) ? new jsAst.LiteralNull() : js.quoteName(callName); | |
| 125 tearOffInfo.add(callSelectorString); | |
| 126 } | |
| 127 | |
| 128 expressions | |
| 129 ..addAll(tearOffInfo) | |
| 130 ..add((tearOffName == null || member.isAccessor) | |
| 131 ? js("null") : js.quoteName(tearOffName)) | |
| 132 ..add(js.number(requiredParameterCount)) | |
| 133 ..add(js.number(optionalParameterCount)) | |
| 134 ..add(memberTypeExpression == null ? js("null") : memberTypeExpression) | |
| 135 ..addAll(task.metadataCollector.reifyDefaultArguments(member)); | |
| 136 | |
| 137 if (canBeReflected || canBeApplied) { | |
| 138 parameters.forEachParameter((Element parameter) { | |
| 139 expressions.add(task.metadataCollector.reifyName(parameter.name)); | |
| 140 if (backend.mustRetainMetadata) { | |
| 141 Iterable<jsAst.Expression> metadataIndices = | |
| 142 parameter.metadata.map((MetadataAnnotation annotation) { | |
| 143 ConstantValue constant = | |
| 144 backend.constants.getConstantValueForMetadata(annotation); | |
| 145 backend.constants.addCompileTimeConstantForEmission(constant); | |
| 146 return task.metadataCollector.reifyMetadata(annotation); | |
| 147 }); | |
| 148 expressions.add(new jsAst.ArrayInitializer(metadataIndices.toList())); | |
| 149 } | |
| 150 }); | |
| 151 } | |
| 152 if (canBeReflected) { | |
| 153 jsAst.LiteralString reflectionName; | |
| 154 if (member.isConstructor) { | |
| 155 // TODO(herhut): This registers name as a mangled name. Do we need this | |
| 156 // given that we use a different name below? | |
| 157 emitter.getReflectionName(member, name); | |
| 158 reflectionName = | |
| 159 new jsAst.LiteralString( | |
| 160 '"new ${Elements.reconstructConstructorName(member)}"'); | |
| 161 } else { | |
| 162 reflectionName = | |
| 163 js.string(namer.privateName(member.memberName)); | |
| 164 } | |
| 165 expressions | |
| 166 ..add(reflectionName) | |
| 167 ..addAll(task.metadataCollector.computeMetadata(member)); | |
| 168 } else if (isClosure && canBeApplied) { | |
| 169 expressions.add(js.string(namer.privateName(member.memberName))); | |
| 170 } | |
| 171 | |
| 172 jsAst.ArrayInitializer arrayInit = | |
| 173 new jsAst.ArrayInitializer(expressions.toList()); | |
| 174 compiler.dumpInfoTask.registerElementAst(member, | |
| 175 builder.addProperty(name, arrayInit)); | |
| 176 } | |
| 177 | |
| 178 void addMemberField(Field field, ClassBuilder builder) { | |
| 179 // For now, do nothing. | |
| 180 } | |
| 181 } | |
| OLD | NEW |