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

Unified Diff: frog/leg/emitter.dart

Issue 9418045: Support for native in leg, and start moving native tests to a specific test suite. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: frog/leg/emitter.dart
===================================================================
--- frog/leg/emitter.dart (revision 4354)
+++ frog/leg/emitter.dart (working copy)
@@ -21,13 +21,87 @@
}
}''';
+ static final String TYPE_NAME_OF_FUNCTION = '''
+function(obj) {
ahe 2012/02/19 14:38:02 Could you add a documentation comment for this fun
ngeoffray 2012/02/20 09:09:37 Sure. For the reference, this code is a pure copy
+ var constructor = obj.constructor;
ahe 2012/02/19 14:38:02 What happens if obj is undefined?
ngeoffray 2012/02/20 09:09:37 boom? :)
floitsch 2012/02/21 13:11:15 Note that this function is called on the prototype
+ if (typeof(constructor) == 'function') {
floitsch 2012/02/19 00:59:43 typeof is not a function: if (typeof constructor =
ngeoffray 2012/02/20 09:09:37 Copy/pasted code.
+ // The constructor isn't null or undefined at this point. Try
+ // to grab hold of its name.
+ var name = constructor.name;
+ // If the name is a non-empty string, we use that as the type
+ // name of this object. On Firefox, we often get 'Object' as
+ // the constructor name even for more specialized objects so
+ // we have to fall through to the toString() based implementation
+ // below in that case.
+ if (name && typeof(name) == 'string' && name != 'Object') return name;
floitsch 2012/02/19 00:59:43 exchange typeof and name-check. It probably does n
ngeoffray 2012/02/20 09:09:37 Copy-pasted code.
+ }
+ var string = Object.prototype.toString.call(obj);
+ var name = string.substring(8, string.length - 1);
ahe 2012/02/19 14:38:02 I'm getting a feeling that this is very similar to
ngeoffray 2012/02/20 09:09:37 Not on this code, which is copy-pasted.
+ if (name == 'Window') {
+ name = 'DOMWindow';
+ } else if (name == 'Document') {
+ name = 'HTMLDocument';
+ }
+ return name;
+}
+''';
+
+ static final String DEF_PROP_FUNCTION = '''
+function(obj, prop, value) {
+ Object.defineProperty(obj, prop,
+ {value: value, enumerable: false, writable: true, configurable: true});
+}''';
+
+ String get DYNAMIC_FUNCTION() => '''
floitsch 2012/02/19 00:59:43 this needs comments.
ahe 2012/02/19 14:38:02 Documentation comment, please.
ngeoffray 2012/02/20 09:09:37 As for TYPE_NAME_OF_FUNCTION, this method was take
ahe 2012/02/20 09:36:10 Whatever information you have about these function
+function(name) {
+ var f = Object.prototype[name];
+ if (f && f.methods) return f.methods;
+
+ var methods = {};
+ if (f) methods.Object = f;
+ function dynamicBind() {
+ // Find the target method
+ var obj = this;
+ var tag = $typeNameOfName(obj);
+ var method = methods[tag];
+ if (!method) {
+ var table = $dynamicMetadataName;
+ for (var i = 0; i < table.length; i++) {
+ var entry = table[i];
+ if (entry.map.hasOwnProperty(tag)) {
+ method = methods[entry.tag];
+ if (method) break;
+ }
+ }
+ }
+ method = method || methods.Object;
+ var proto = Object.getPrototypeOf(obj);
+ if (!proto.hasOwnProperty(name)) {
+ $defPropName(proto, name, method);
+ }
+
+ return method.apply(this, Array.prototype.slice.call(arguments));
+ };
+ dynamicBind.methods = methods;
+ $defPropName(Object.prototype, name, dynamicBind);
+ return methods;
+}
+if (typeof $dynamicMetadataName == 'undefined') $dynamicMetadataName = [];
ahe 2012/02/19 14:38:02 Extra code after function. Shouldn't this be in th
ngeoffray 2012/02/20 09:09:37 Code also comes from frog.
ahe 2012/02/20 09:36:10 You chose the word "DYNAMIC_FUNCTION". Clearly thi
+''';
+
bool addedInheritFunction = false;
+ bool addedDynamicFunction = false;
final Namer namer;
CodeEmitterTask(Compiler compiler) : namer = compiler.namer, super(compiler);
String get name() => 'CodeEmitter';
String get inheritsName() => '${compiler.namer.ISOLATE}.\$inherits';
ahe 2012/02/19 14:38:02 Why aren't these strings final values? Generating
ngeoffray 2012/02/20 09:09:37 They cannot be final because compiler.namer.ISOLAT
+ String get dynamicName() => '${compiler.namer.ISOLATE}.\$dynamic';
+ String get defPropName() => '${compiler.namer.ISOLATE}.\$defProp';
+ String get typeNameOfName() => '${compiler.namer.ISOLATE}.\$typeNameOf';
+ String get dynamicMetadataName() =>
+ '${compiler.namer.ISOLATE}.\$dynamicMetatada';
ahe 2012/02/19 14:38:02 How is this related to line 89?
ngeoffray 2012/02/20 09:09:37 Not sure I understand.
ahe 2012/02/20 09:36:10 I overlooked that the code on 89 wasn't in a raw s
void addInheritFunctionIfNecessary(StringBuffer buffer) {
if (addedInheritFunction) return;
@@ -37,8 +111,22 @@
buffer.add(';\n');
}
+ void addDynamicFunctionIfNecessary(StringBuffer buffer) {
+ if (addedDynamicFunction) return;
+ addedDynamicFunction = true;
+ buffer.add('$defPropName = ');
+ buffer.add(DEF_PROP_FUNCTION);
+ buffer.add('\n');
+ buffer.add('$typeNameOfName = ');
+ buffer.add(TYPE_NAME_OF_FUNCTION);
+ buffer.add('\n');
+ buffer.add('$dynamicName = ');
+ buffer.add(DYNAMIC_FUNCTION);
+ buffer.add(';\n');
+ }
+
void addParameterStub(FunctionElement member,
- String prototype,
+ String attachTo(String invocationName),
StringBuffer buffer,
Selector selector) {
FunctionParameters parameters = member.computeParameters(compiler);
@@ -52,7 +140,7 @@
String invocationName =
namer.instanceMethodInvocationName(member.name, selector);
- buffer.add('$prototype.$invocationName = function(');
+ buffer.add('${attachTo(invocationName)} = function(');
ahe 2012/02/19 14:38:02 How about turning this into a streaming API, that
// The parameters that this stub takes.
List<String> parametersBuffer = new List<String>(selector.argumentCount);
@@ -121,13 +209,13 @@
}
void addParameterStubs(FunctionElement member,
- String prototype,
+ String attachTo(String invocationName),
StringBuffer buffer) {
Set<Selector> selectors = compiler.universe.invokedNames[member.name];
if (selectors == null) return;
for (Selector selector in selectors) {
if (!selector.applies(compiler, member)) continue;
- addParameterStub(member, prototype, buffer, selector);
+ addParameterStub(member, attachTo, buffer, selector);
}
}
@@ -150,7 +238,7 @@
}
FunctionElement function = member;
if (!function.computeParameters(compiler).optionalParameters.isEmpty()) {
- addParameterStubs(member, prototype, buffer);
+ addParameterStubs(member, (name) => '$prototype.$name', buffer);
}
} else if (member.kind === ElementKind.FIELD) {
// TODO(ngeoffray): Have another class generate the code for the
@@ -186,7 +274,7 @@
String memberName = namer.instanceFieldName(member.name);
argumentsBuffer.add('${className}_$memberName');
bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n');
- }
+ }
}
for (Element element in classElement.members) {
@@ -200,6 +288,55 @@
} while(classElement !== null);
}
+ void generateNativeClass(ClassElement classElement, StringBuffer buffer) {
+ addDynamicFunctionIfNecessary(buffer);
+ assert(classElement.backendMembers.isEmpty());
+ String nativeName = classElement.nativeName.substring(
+ 2, classElement.nativeName.length - 1);
+ for (Element member in classElement.members) {
+ if (member.isInstanceMember()) {
+ String memberName = namer.getName(member);
+ if (member.kind === ElementKind.FUNCTION
+ || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY
+ || member.kind === ElementKind.GETTER
+ || member.kind === ElementKind.SETTER) {
+ String codeBlock = compiler.universe.generatedCode[member];
+ if (codeBlock !== null) {
+ buffer.add(
+ "$dynamicName('$memberName').$nativeName = $codeBlock;\n");
+ }
+ codeBlock = compiler.universe.generatedBailoutCode[member];
+ if (codeBlock !== null) {
floitsch 2012/02/19 00:59:43 Maybe we should consider making our bailout functi
+ String name = namer.getBailoutName(member);
+ buffer.add("$dynamicName('$name').$nativeName = $codeBlock;\n");
+ }
+ FunctionElement function = member;
+ FunctionParameters parameters = function.computeParameters(compiler);
+ if (!parameters.optionalParameters.isEmpty()) {
ahe 2012/02/19 14:38:02 Is this necessary if there is no code generated?
ngeoffray 2012/02/20 09:09:37 Very good catch. Will remove it.
+ addParameterStubs(
+ member, (name) => "$dynamicName('$name').$nativeName", buffer);
+ }
+ } else if (member.kind === ElementKind.FIELD) {
+ if (compiler.universe.invokedSetters.contains(member.name)) {
+ String setterName = namer.setterName(member.name);
+ buffer.add(
+ "$dynamicName('$setterName').$nativeName = function(v){\n" +
+ ' this.${member.name} = v;\n};\n');
+ }
+ if (compiler.universe.invokedGetters.contains(member.name)) {
+ String getterName = namer.getterName(member.name);
+ buffer.add(
+ "$dynamicName('$getterName').$nativeName = function(){\n" +
+ ' return this.${member.name};\n};\n');
+ }
+ } else {
+ compiler.internalError('unexpected kind: "${member.kind}"',
+ element: member);
+ }
+ }
+ }
+ }
+
void generateClass(ClassElement classElement,
StringBuffer buffer,
Set<ClassElement> seenClasses) {
@@ -210,6 +347,9 @@
generateClass(classElement.superclass, buffer, seenClasses);
}
+ if (classElement.isNative()) {
+ return generateNativeClass(classElement, buffer);
floitsch 2012/02/19 00:59:43 don't use 'return val' to leave a void function.
+ }
String className = namer.isolatePropertyAccess(classElement);
buffer.add('$className = function ${classElement.name}(');
StringBuffer bodyBuffer = new StringBuffer();
@@ -290,7 +430,7 @@
String invocationName =
namer.instanceMethodName(callElement.name, parameterCount);
buffer.add("$staticName.$invocationName = $staticName;\n");
- addParameterStubs(callElement, staticName, buffer);
+ addParameterStubs(callElement, (name) => '$staticName.$name', buffer);
}
}
@@ -343,7 +483,7 @@
buffer.add("$prototype.$invocationName = function($joinedArgs) {\n");
buffer.add(" return this.self.$targetName($joinedArgs);\n");
buffer.add("};\n");
- addParameterStubs(callElement, prototype, buffer);
+ addParameterStubs(callElement, (name) => '$prototype.$name', buffer);
// And finally the getter.
String enclosingClassAccess = namer.isolatePropertyAccess(enclosingClass);

Powered by Google App Engine
This is Rietveld 408576698