Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(391)

Side by Side Diff: frog/var_member.dart

Issue 10548047: Remove frog from the repository. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Move test and update apidoc.gyp. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « frog/value.dart ('k') | frog/world.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011, 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 /** A dynamic member stub. */
6 class VarMember {
7 final String name;
8 bool isGenerated = false;
9
10 VarMember(this.name);
11
12 abstract void generate(CodeWriter code);
13
14 String get body() => null;
15
16 Type get returnType() => world.varType;
17
18 Value invoke(CallingContext context, Node node, Value target, Arguments args) {
19 return new Value(returnType,
20 '${target.code}.$name(${args.getCode()})', node.span);
21 }
22 }
23
24 /**
25 * This function generates a dynamic call stub for functions. It's part of a
26 * series of steps described below. Most of the code is generated by
27 * gen.dart, with some helpers in core.js
28 *
29 * Given a call site in Dart like:
30 * f(1, 2, capture:true);
31 *
32 * We compile to JS like:
33 * f.call$2$capture(1, 2, true);
34 *
35 * And then generate this function:
36 * Function.prototype.call$2$capture = function($0, $1, capture) {
37 * this.call$2$capture = this.$genStub(3, ['capture']);
38 * return this.call$2$capture($0, $1, capture);
39 * }
40 *
41 * Or for a fixed-arity function, generate this:
42 * Function.prototype.call$2 = function($0, $1) {
43 * return this.to$call$2()($0, $1);
44 * }
45 * Function.prototype.to$call$2 = function() {
46 * this.call$2 = this.$genStub(2);
47 * this.to$call$2 = function() { return this.call$2; }
48 * return this.to$call$2();
49 * }
50 * We use .to$call$2 to convert to a typed function.
51 *
52 * For each method that can be passed as a function, such as a "get" on the
53 * method or is a lambda, generate optional argument info. Given a function
54 * like:
55 * class SomeType {
56 * void add(x, y, [bubbles = true, capture = false]) { ... }
57 * ... }
58 *
59 * The generated argument info looks like:
60 * SomeType.prototype.add.$optional = ['bubbles','capture', 'true','false'];
61 */
62 // TODO(jmesserly): we don't currently put $optional on lambdas.
63 // Also, maybe a string encoding would perform better?
64 // TODO(jmesserly): _genStub is a hole in the run-time type checker.
65 // It bypasses the checks we would do at the callsite for methods.
66 // Also, it won't work properly for native JS functions (those don't have
67 // an accurate .length)
68 class VarFunctionStub extends VarMember {
69 final Arguments args;
70
71 VarFunctionStub(String name, Arguments callArgs)
72 : super(name), args = callArgs.toCallStubArgs() {
73 // Ensure dependency is generated
74 world.functionImplType.markUsed();
75 world.gen.genMethod(world.functionImplType.getMember('_genStub'));
76 }
77
78 Value invoke(CallingContext context, Node node, Value target,
79 Arguments args) {
80 return super.invoke(context, node, target, args);
81 }
82
83 void generate(CodeWriter code) {
84 isGenerated = true;
85 if (args.hasNames) {
86 generateNamed(code);
87 } else {
88 generatePositional(code);
89 }
90 }
91
92 void generatePositional(CodeWriter w) {
93 // Positional arg functions can be converted from "var" to a fixed arity
94 // function type. So emit a to$N stub as well as the call$N stub.
95 int arity = args.length;
96 w.enterBlock('Function.prototype.to\$$name = function() {');
97 w.writeln('this.$name = this._genStub($arity);');
98 w.writeln('this.to\$$name = function() { return this.$name; };');
99 w.writeln('return this.$name;');
100 w.exitBlock('};');
101 var argsCode = args.getCode();
102 w.enterBlock('Function.prototype.$name = function(${argsCode}) {');
103 w.writeln('return this.to\$$name()($argsCode);');
104 w.exitBlock('};');
105
106 // TODO(jmesserly): HACK, we couldn't allocate temps from Value, so we
107 // needed this stub to check for null.
108 w.writeln('function to\$$name(f) { return f && f.to\$$name(); }');
109 }
110
111 void generateNamed(CodeWriter w) {
112 // Named functions use simpler stubs, because we never convert to a named
113 // stub type.
114 var named = Strings.join(args.getNames(), '", "');
115 var argsCode = args.getCode();
116 w.enterBlock('Function.prototype.$name = function(${argsCode}) {');
117 w.writeln('this.$name = this._genStub(${args.length}, ["$named"]);');
118 w.writeln('return this.$name($argsCode);');
119 w.exitBlock('}');
120 }
121 }
122
123 class VarMethodStub extends VarMember {
124 final Member member;
125 final Arguments args;
126 final String body;
127
128 VarMethodStub(String name, this.member, this.args, this.body): super(name);
129
130 bool get isHidden() =>
131 member != null ? member.declaringType.isHiddenNativeType : false;
132
133 Type get returnType() =>
134 member != null ? member.returnType : world.varType;
135
136 Type get declaringType() =>
137 member != null ? member.declaringType : world.objectType;
138
139 void generate(CodeWriter code) {
140 isGenerated = true;
141 if (!isHidden && _useDirectCall(args)) {
142 world.gen._writePrototypePatch(declaringType, name,
143 world.gen._prototypeOf(declaringType, member.jsname), code);
144 } else {
145 String suffix = world.gen._writePrototypePatch(declaringType, name,
146 'function(${args.getCode()}) {', code, false);
147 if (!suffix.endsWith(';')) {
148 suffix += ';';
149 }
150 if (_needsExactTypeCheck()) {
151 code.enterBlock(
152 'if (Object.getPrototypeOf(this).hasOwnProperty("$name")) {');
153 code.writeln('$body;');
154 code.exitBlock('}');
155 String argsCode = args.getCode();
156 if (argsCode != '') argsCode = ', ' + argsCode;
157 code.writeln('return Object.prototype.$name.call(this$argsCode);');
158 code.exitBlock(suffix);
159 } else {
160 code.writeln('$body;');
161 code.exitBlock(suffix);
162 }
163 }
164 }
165
166 /**
167 * If we have a native method overridden by a hidden native method, we need to
168 * make sure the base one has an exact type test. Otherwise we don't need
169 * this.
170 */
171 bool _needsExactTypeCheck() {
172 if (member == null || member.declaringType.isObject) return false;
173
174 var members = member.potentialMemberSet.members;
175 return members.filter((m) => m != member
176 && m.declaringType.isHiddenNativeType).length >= 1;
177 }
178
179 bool _useDirectCall(Arguments args) {
180 // Create direct stubs when we can. We don't do this in some cases, such as
181 // types that have native subtypes (like Object), otherwise things like
182 // Object.prototype.toString$0 end up calling the toString on Object instead
183 // of on the derived type.
184 if (member is MethodMember && !member.declaringType.hasNativeSubtypes) {
185 MethodMember method = member;
186 if (method.needsArgumentConversion(args)) {
187 return false;
188 }
189
190 // If we have the right number of parameters, or all defaults would be
191 // filled in as "undefined" anyway, we can just call the method directly.
192 for (int i = args.length; i < method.parameters.length; i++) {
193 if (method.parameters[i].value.code != 'null') {
194 return false;
195 }
196 }
197 return method.namesInHomePositions(args);
198 } else {
199 return false;
200 }
201 }
202 }
203
204 /**
205 * A special member with a mangled name that represents a dynamic call
206 * (i.e. a call with multiple valid targets). We generate this if we have
207 * a dynamic call that needs different implementation methods for different
208 * members.
209 */
210 class VarMethodSet extends VarMember {
211 final String baseName;
212 final List<Member> members;
213 final Type returnType;
214 final Arguments args;
215
216 bool invoked = false;
217
218 VarMethodSet(this.baseName, String name, this.members, Arguments callArgs,
219 this.returnType)
220 : super(name), args = callArgs.toCallStubArgs() {
221 }
222
223 Value invoke(CallingContext context, Node node, Value target,
224 Arguments args) {
225 _invokeMembers(context, node);
226 return super.invoke(context, node, target, args);
227 }
228
229 /** Invokes members to ensure they're generated. */
230 _invokeMembers(CallingContext context, Node node) {
231 if (invoked) return;
232 invoked = true;
233
234 bool hasObjectType = false;
235 for (var member in members) {
236 // Invoke the member with the stub args (this gives us the method body),
237 // then create the stub method.
238 final type = member.declaringType;
239 final target = new Value(type, 'this', node.span);
240 var result = member.invoke(context, node, target, args);
241 var stub = new VarMethodStub(name, member, args, 'return ${result.code}');
242 type.varStubs[stub.name] = stub;
243 if (type.isObject) hasObjectType = true;
244 }
245
246 // Create a noSuchMethod fallback on Object if needed.
247 // Some methods, like toString and == already have a fallback on Object.
248 if (!hasObjectType) {
249 final target = new Value(world.objectType, 'this', node.span);
250 var result = target.invokeNoSuchMethod(context, baseName, node, args);
251 var stub = new VarMethodStub(name, null, args, 'return ${result.code}');
252 world.objectType.varStubs[stub.name] = stub;
253 }
254 }
255
256 // TODO(jmesserly): get rid of this as it's unused now
257 void generate(CodeWriter code) {}
258 }
259
260 String _getCallStubName(String name, Arguments args) {
261 // The stub name should not collide with any user declared method name since
262 // the '$'s in the stub name are always alone and world.toJsIdentifier doubles
263 // up those in a user declared method name.
264 final nameBuilder = new StringBuffer('${name}\$${args.bareCount}');
265 for (int i = args.bareCount; i < args.length; i++) {
266 var argName = args.getName(i);
267 nameBuilder.add('\$');
268 if (argName.contains('\$')) {
269 // Disambiguate "a:b:" from "a$b:". Prefixing the length works because
270 // parameter names can't start with digits.
271 nameBuilder.add('${argName.length}');
272 }
273 nameBuilder.add(argName);
274 }
275 return nameBuilder.toString();
276 }
OLDNEW
« no previous file with comments | « frog/value.dart ('k') | frog/world.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698