OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 |
| 6 class MethodCallData { |
| 7 MethodData data; |
| 8 |
| 9 MethodMember method; |
| 10 |
| 11 MethodGenerator _methodGenerator; |
| 12 |
| 13 MethodCallData(this.data, this.method); |
| 14 |
| 15 bool matches(MethodCallData other) { |
| 16 return method == other.method; |
| 17 } |
| 18 |
| 19 void run() { |
| 20 if (_methodGenerator !== null) return; |
| 21 |
| 22 _methodGenerator = new MethodGenerator(method, data.context); |
| 23 _methodGenerator.run(); |
| 24 } |
| 25 } |
| 26 |
| 27 |
| 28 /** |
| 29 * Stores a reference to a single actual method body as well as |
| 30 * potential specializations for either concrete generic types or |
| 31 * optimizations for concrete argument types. |
| 32 */ |
| 33 class MethodData { |
| 34 MethodMember baseMethod; |
| 35 Statement body; |
| 36 bool needsTypeParams = false; |
| 37 |
| 38 CallingContext context; |
| 39 |
| 40 List<MethodCallData> _calls; |
| 41 |
| 42 MethodData(this.baseMethod, [this.context]): _calls = [] { |
| 43 body = baseMethod.definition.body; |
| 44 if (baseMethod.isConstructor) { |
| 45 needsTypeParams = true; |
| 46 } |
| 47 } |
| 48 |
| 49 void analyze() { |
| 50 // TODO(jimhug): Is there really no analysis to do for a missing body? |
| 51 if (body === null) return; |
| 52 var ma = new MethodAnalyzer(baseMethod, body); |
| 53 ma.analyze(context); |
| 54 // TODO(jimhug): Add support for specializing on type parameters. |
| 55 /* |
| 56 if (ma.hasTypeParams) { |
| 57 needsTypeParams = true; |
| 58 } |
| 59 */ |
| 60 } |
| 61 |
| 62 Value eval(MethodMember method, Value newObject, Arguments args) { |
| 63 if (method !== baseMethod) { |
| 64 if (!needsTypeParams) method = baseMethod; |
| 65 } |
| 66 |
| 67 // TODO(jimhug): Reconcile with run method below. |
| 68 var gen = new MethodGenerator(method, context); |
| 69 return gen.evalBody(newObject, args); |
| 70 } |
| 71 |
| 72 |
| 73 invokeCall(MethodCallData callData) { |
| 74 for (var cd in _calls) { |
| 75 if (cd.matches(callData)) { |
| 76 return cd.run(); |
| 77 } |
| 78 } |
| 79 _calls.add(callData); |
| 80 callData.run(); |
| 81 } |
| 82 |
| 83 void run(MethodMember method) { |
| 84 if (body === null && !method.isConstructor && !method.isNative) return; |
| 85 |
| 86 if (method !== baseMethod) { |
| 87 if (!needsTypeParams) method = baseMethod; |
| 88 } |
| 89 |
| 90 var callData = new MethodCallData(this, method); |
| 91 method.declaringType.genericType.markUsed(); |
| 92 |
| 93 invokeCall(callData); |
| 94 } |
| 95 |
| 96 bool writeDefinition(MethodMember method, CodeWriter writer) { |
| 97 var gen = null; |
| 98 // TODO(jimhug): Handle multiple matches. |
| 99 for (var cd in _calls) { |
| 100 if (cd.method == method) { |
| 101 gen = cd._methodGenerator; |
| 102 } |
| 103 } |
| 104 |
| 105 if (gen != null) { |
| 106 if (method.definition.nativeBody != null && method == baseMethod) { |
| 107 if (method.definition.nativeBody == '') return true; |
| 108 gen.writer = new CodeWriter(); |
| 109 gen.writer.write(method.definition.nativeBody); |
| 110 gen._paramCode = map(method.parameters, (p) => p.name); |
| 111 |
| 112 } |
| 113 gen.writeDefinition(writer, null); |
| 114 return true; |
| 115 } else { |
| 116 return false; |
| 117 } |
| 118 } |
| 119 |
| 120 void createFunction(CodeWriter writer) { |
| 121 this.run(baseMethod); |
| 122 writeDefinition(baseMethod, writer); |
| 123 } |
| 124 |
| 125 //TODO(jimhug): context belongs in constructor, not here. |
| 126 Value createLambda(LambdaExpression node, CallingContext context) { |
| 127 //TODO(jimhug): Only create the lambda if it is needed. |
| 128 final lambdaGen = new MethodGenerator(baseMethod, context); |
| 129 if (baseMethod.name != '') { |
| 130 // Note: we don't want to put this in our enclosing scope because the |
| 131 // name shouldn't be visible except inside the lambda. We also don't want |
| 132 // to put the name directly in the lambda's scope because parameters are |
| 133 // allowed to shadow it. So we create an extra scope for it to go into. |
| 134 lambdaGen._scope.create(baseMethod.name, baseMethod.functionType, |
| 135 baseMethod.definition.span, isFinal:true); |
| 136 lambdaGen._pushBlock(baseMethod.definition); |
| 137 } |
| 138 |
| 139 _calls.add(new MethodCallData(this, baseMethod)); |
| 140 |
| 141 lambdaGen.run(); |
| 142 if (baseMethod.name != '') { |
| 143 lambdaGen._popBlock(baseMethod.definition); |
| 144 } |
| 145 |
| 146 final writer = new CodeWriter(); |
| 147 lambdaGen.writeDefinition(writer, node); |
| 148 return new Value(baseMethod.functionType, writer.text, |
| 149 baseMethod.definition.span); |
| 150 } |
| 151 } |
OLD | NEW |