Index: frog/var_member.dart |
diff --git a/frog/var_member.dart b/frog/var_member.dart |
deleted file mode 100644 |
index 8e2668ff775a1f549562bf08236a1358ed33717c..0000000000000000000000000000000000000000 |
--- a/frog/var_member.dart |
+++ /dev/null |
@@ -1,276 +0,0 @@ |
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-/** A dynamic member stub. */ |
-class VarMember { |
- final String name; |
- bool isGenerated = false; |
- |
- VarMember(this.name); |
- |
- abstract void generate(CodeWriter code); |
- |
- String get body() => null; |
- |
- Type get returnType() => world.varType; |
- |
- Value invoke(CallingContext context, Node node, Value target, Arguments args) { |
- return new Value(returnType, |
- '${target.code}.$name(${args.getCode()})', node.span); |
- } |
-} |
- |
-/** |
- * This function generates a dynamic call stub for functions. It's part of a |
- * series of steps described below. Most of the code is generated by |
- * gen.dart, with some helpers in core.js |
- * |
- * Given a call site in Dart like: |
- * f(1, 2, capture:true); |
- * |
- * We compile to JS like: |
- * f.call$2$capture(1, 2, true); |
- * |
- * And then generate this function: |
- * Function.prototype.call$2$capture = function($0, $1, capture) { |
- * this.call$2$capture = this.$genStub(3, ['capture']); |
- * return this.call$2$capture($0, $1, capture); |
- * } |
- * |
- * Or for a fixed-arity function, generate this: |
- * Function.prototype.call$2 = function($0, $1) { |
- * return this.to$call$2()($0, $1); |
- * } |
- * Function.prototype.to$call$2 = function() { |
- * this.call$2 = this.$genStub(2); |
- * this.to$call$2 = function() { return this.call$2; } |
- * return this.to$call$2(); |
- * } |
- * We use .to$call$2 to convert to a typed function. |
- * |
- * For each method that can be passed as a function, such as a "get" on the |
- * method or is a lambda, generate optional argument info. Given a function |
- * like: |
- * class SomeType { |
- * void add(x, y, [bubbles = true, capture = false]) { ... } |
- * ... } |
- * |
- * The generated argument info looks like: |
- * SomeType.prototype.add.$optional = ['bubbles','capture', 'true','false']; |
- */ |
-// TODO(jmesserly): we don't currently put $optional on lambdas. |
-// Also, maybe a string encoding would perform better? |
-// TODO(jmesserly): _genStub is a hole in the run-time type checker. |
-// It bypasses the checks we would do at the callsite for methods. |
-// Also, it won't work properly for native JS functions (those don't have |
-// an accurate .length) |
-class VarFunctionStub extends VarMember { |
- final Arguments args; |
- |
- VarFunctionStub(String name, Arguments callArgs) |
- : super(name), args = callArgs.toCallStubArgs() { |
- // Ensure dependency is generated |
- world.functionImplType.markUsed(); |
- world.gen.genMethod(world.functionImplType.getMember('_genStub')); |
- } |
- |
- Value invoke(CallingContext context, Node node, Value target, |
- Arguments args) { |
- return super.invoke(context, node, target, args); |
- } |
- |
- void generate(CodeWriter code) { |
- isGenerated = true; |
- if (args.hasNames) { |
- generateNamed(code); |
- } else { |
- generatePositional(code); |
- } |
- } |
- |
- void generatePositional(CodeWriter w) { |
- // Positional arg functions can be converted from "var" to a fixed arity |
- // function type. So emit a to$N stub as well as the call$N stub. |
- int arity = args.length; |
- w.enterBlock('Function.prototype.to\$$name = function() {'); |
- w.writeln('this.$name = this._genStub($arity);'); |
- w.writeln('this.to\$$name = function() { return this.$name; };'); |
- w.writeln('return this.$name;'); |
- w.exitBlock('};'); |
- var argsCode = args.getCode(); |
- w.enterBlock('Function.prototype.$name = function(${argsCode}) {'); |
- w.writeln('return this.to\$$name()($argsCode);'); |
- w.exitBlock('};'); |
- |
- // TODO(jmesserly): HACK, we couldn't allocate temps from Value, so we |
- // needed this stub to check for null. |
- w.writeln('function to\$$name(f) { return f && f.to\$$name(); }'); |
- } |
- |
- void generateNamed(CodeWriter w) { |
- // Named functions use simpler stubs, because we never convert to a named |
- // stub type. |
- var named = Strings.join(args.getNames(), '", "'); |
- var argsCode = args.getCode(); |
- w.enterBlock('Function.prototype.$name = function(${argsCode}) {'); |
- w.writeln('this.$name = this._genStub(${args.length}, ["$named"]);'); |
- w.writeln('return this.$name($argsCode);'); |
- w.exitBlock('}'); |
- } |
-} |
- |
-class VarMethodStub extends VarMember { |
- final Member member; |
- final Arguments args; |
- final String body; |
- |
- VarMethodStub(String name, this.member, this.args, this.body): super(name); |
- |
- bool get isHidden() => |
- member != null ? member.declaringType.isHiddenNativeType : false; |
- |
- Type get returnType() => |
- member != null ? member.returnType : world.varType; |
- |
- Type get declaringType() => |
- member != null ? member.declaringType : world.objectType; |
- |
- void generate(CodeWriter code) { |
- isGenerated = true; |
- if (!isHidden && _useDirectCall(args)) { |
- world.gen._writePrototypePatch(declaringType, name, |
- world.gen._prototypeOf(declaringType, member.jsname), code); |
- } else { |
- String suffix = world.gen._writePrototypePatch(declaringType, name, |
- 'function(${args.getCode()}) {', code, false); |
- if (!suffix.endsWith(';')) { |
- suffix += ';'; |
- } |
- if (_needsExactTypeCheck()) { |
- code.enterBlock( |
- 'if (Object.getPrototypeOf(this).hasOwnProperty("$name")) {'); |
- code.writeln('$body;'); |
- code.exitBlock('}'); |
- String argsCode = args.getCode(); |
- if (argsCode != '') argsCode = ', ' + argsCode; |
- code.writeln('return Object.prototype.$name.call(this$argsCode);'); |
- code.exitBlock(suffix); |
- } else { |
- code.writeln('$body;'); |
- code.exitBlock(suffix); |
- } |
- } |
- } |
- |
- /** |
- * If we have a native method overridden by a hidden native method, we need to |
- * make sure the base one has an exact type test. Otherwise we don't need |
- * this. |
- */ |
- bool _needsExactTypeCheck() { |
- if (member == null || member.declaringType.isObject) return false; |
- |
- var members = member.potentialMemberSet.members; |
- return members.filter((m) => m != member |
- && m.declaringType.isHiddenNativeType).length >= 1; |
- } |
- |
- bool _useDirectCall(Arguments args) { |
- // Create direct stubs when we can. We don't do this in some cases, such as |
- // types that have native subtypes (like Object), otherwise things like |
- // Object.prototype.toString$0 end up calling the toString on Object instead |
- // of on the derived type. |
- if (member is MethodMember && !member.declaringType.hasNativeSubtypes) { |
- MethodMember method = member; |
- if (method.needsArgumentConversion(args)) { |
- return false; |
- } |
- |
- // If we have the right number of parameters, or all defaults would be |
- // filled in as "undefined" anyway, we can just call the method directly. |
- for (int i = args.length; i < method.parameters.length; i++) { |
- if (method.parameters[i].value.code != 'null') { |
- return false; |
- } |
- } |
- return method.namesInHomePositions(args); |
- } else { |
- return false; |
- } |
- } |
-} |
- |
-/** |
- * A special member with a mangled name that represents a dynamic call |
- * (i.e. a call with multiple valid targets). We generate this if we have |
- * a dynamic call that needs different implementation methods for different |
- * members. |
- */ |
-class VarMethodSet extends VarMember { |
- final String baseName; |
- final List<Member> members; |
- final Type returnType; |
- final Arguments args; |
- |
- bool invoked = false; |
- |
- VarMethodSet(this.baseName, String name, this.members, Arguments callArgs, |
- this.returnType) |
- : super(name), args = callArgs.toCallStubArgs() { |
- } |
- |
- Value invoke(CallingContext context, Node node, Value target, |
- Arguments args) { |
- _invokeMembers(context, node); |
- return super.invoke(context, node, target, args); |
- } |
- |
- /** Invokes members to ensure they're generated. */ |
- _invokeMembers(CallingContext context, Node node) { |
- if (invoked) return; |
- invoked = true; |
- |
- bool hasObjectType = false; |
- for (var member in members) { |
- // Invoke the member with the stub args (this gives us the method body), |
- // then create the stub method. |
- final type = member.declaringType; |
- final target = new Value(type, 'this', node.span); |
- var result = member.invoke(context, node, target, args); |
- var stub = new VarMethodStub(name, member, args, 'return ${result.code}'); |
- type.varStubs[stub.name] = stub; |
- if (type.isObject) hasObjectType = true; |
- } |
- |
- // Create a noSuchMethod fallback on Object if needed. |
- // Some methods, like toString and == already have a fallback on Object. |
- if (!hasObjectType) { |
- final target = new Value(world.objectType, 'this', node.span); |
- var result = target.invokeNoSuchMethod(context, baseName, node, args); |
- var stub = new VarMethodStub(name, null, args, 'return ${result.code}'); |
- world.objectType.varStubs[stub.name] = stub; |
- } |
- } |
- |
- // TODO(jmesserly): get rid of this as it's unused now |
- void generate(CodeWriter code) {} |
-} |
- |
-String _getCallStubName(String name, Arguments args) { |
- // The stub name should not collide with any user declared method name since |
- // the '$'s in the stub name are always alone and world.toJsIdentifier doubles |
- // up those in a user declared method name. |
- final nameBuilder = new StringBuffer('${name}\$${args.bareCount}'); |
- for (int i = args.bareCount; i < args.length; i++) { |
- var argName = args.getName(i); |
- nameBuilder.add('\$'); |
- if (argName.contains('\$')) { |
- // Disambiguate "a:b:" from "a$b:". Prefixing the length works because |
- // parameter names can't start with digits. |
- nameBuilder.add('${argName.length}'); |
- } |
- nameBuilder.add(argName); |
- } |
- return nameBuilder.toString(); |
-} |