Index: lib/compiler/implementation/emitter.dart |
diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart |
index 61efdc0936603fe2684d30e0a7b8152654877182..9cd1ea2044529a829af5aefa152220de1cc04473 100644 |
--- a/lib/compiler/implementation/emitter.dart |
+++ b/lib/compiler/implementation/emitter.dart |
@@ -60,6 +60,8 @@ class CodeEmitterTask extends CompilerTask { |
=> '${namer.ISOLATE}.\$pendingClasses'; |
String get isolatePropertiesName() |
=> '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
+ String get supportsProtoName() |
+ => 'supportsProto'; |
final String GETTER_SUFFIX = "?"; |
final String SETTER_SUFFIX = "!"; |
@@ -75,6 +77,8 @@ function(field, prototype) { |
if (needsGetter || needsSetter) field = field.substring(0, len - 1); |
if (needsGetter) { |
var getterString = "return this." + field + ";"; |
+""" /* The supportsProtoCheck below depends on the getter/setter convention. |
+ When changing here, update the protoCheck too. */ """ |
prototype["get\$" + field] = new Function(getterString); |
} |
if (needsSetter) { |
@@ -100,7 +104,7 @@ function(field, prototype) { |
// }, |
// }); |
return """ |
-function(cls, superclass, fields, prototype) { |
+function(cls, fields, prototype) { |
var generateGetterSetter = $generateGetterSetterFunction; |
var constructor; |
if (typeof fields == 'function') { |
@@ -119,14 +123,30 @@ function(cls, superclass, fields, prototype) { |
str += "return " + cls + ";"; |
constructor = new Function(str)(); |
} |
- $isolatePropertiesName[cls] = constructor; |
constructor.prototype = prototype; |
- if (superclass !== "") { |
- $pendingClassesName[cls] = superclass; |
- } |
+ return constructor; |
}"""; |
} |
+ /** Needs defineClass to be defined. */ |
+ String get protoSupportCheck() { |
+ // On Firefox and Webkit browsers we can manipulate the __proto__ |
+ // directly. Opera claims to have __proto__ support, but it is buggy. |
+ // So we have to do more checks. |
+ // If the browser does not support __proto__ we need to instantiate an |
+ // object with the correct (internal) prototype set up correctly, and then |
+ // copy the members. |
+ |
+ return ''' |
+var $supportsProtoName = false; |
+var tmp = $defineClassName('c', ['f?'], {}).prototype; |
+if (tmp.__proto__) { |
+ tmp.__proto__ = {}; |
+ if (typeof tmp.get\$f !== "undefined") $supportsProtoName = true; |
+} |
+'''; |
+ } |
+ |
String get finishClassesFunction() { |
// 'defineClass' does not require the classes to be constructed in order. |
// Classes are initially just stored in the 'pendingClasses' field. |
@@ -142,10 +162,11 @@ function(cls, superclass, fields, prototype) { |
// object and copy over the members. |
return ''' |
function(collectedClasses) { |
- for (var collected in collectedClasses) { |
- if (Object.prototype.hasOwnProperty.call(collectedClasses, collected)) { |
- var desc = collectedClasses[collected]; |
- $defineClassName(collected, desc.super, desc[''], desc); |
+ for (var cls in collectedClasses) { |
+ if (Object.prototype.hasOwnProperty.call(collectedClasses, cls)) { |
+ var desc = collectedClasses[cls]; |
+ $isolatePropertiesName[cls] = $defineClassName(cls, desc[''], desc); |
+ if (desc['super'] !== "") $pendingClassesName[cls] = desc['super']; |
} |
} |
var pendingClasses = $pendingClassesName; |
@@ -163,15 +184,10 @@ function(collectedClasses) { |
var constructor = $isolatePropertiesName[cls]; |
var superConstructor = $isolatePropertiesName[superclass]; |
var prototype = constructor.prototype; |
- if (prototype.__proto__) { |
-'''/* On Firefox and Webkit browsers we can manipulate the __proto__ |
- directly. */''' |
+ if ($supportsProtoName) { |
prototype.__proto__ = superConstructor.prototype; |
prototype.constructor = constructor; |
} else { |
-'''/* On the remaining browsers we need to instantiate an object with the |
- correct (internal) prototype set up correctly, and then copy the |
- members. */''' |
function tmp() {}; |
tmp.prototype = superConstructor.prototype; |
var newPrototype = new tmp(); |
@@ -237,6 +253,7 @@ function(collectedClasses) { |
if (needsDefineClass) { |
String isolate = namer.ISOLATE; |
buffer.add("$defineClassName = $defineClassFunction;\n"); |
+ buffer.add(protoSupportCheck); |
buffer.add("$pendingClassesName = {};\n"); |
buffer.add("$finishClassesName = $finishClassesFunction;\n"); |
} |
@@ -711,9 +728,11 @@ function(collectedClasses) { |
// Define the constructor with a name so that Object.toString can |
// find the class name of the closure class. |
- boundClosureBuffer.add("$defineClassName('$mangledName', '$superName', "); |
- boundClosureBuffer.add("['self', 'target'], {\n"); |
- |
+ boundClosureBuffer.add(""" |
+$classesCollector.$mangledName = {'': |
+ ['self', 'target'], |
+ 'super': '$superName', |
+"""); |
// Now add the methods on the closure class. The instance method does not |
// have the correct name. Since [addParameterStubs] use the name to create |
// its stubs we simply create a fake element with the correct name. |
@@ -736,7 +755,7 @@ function(collectedClasses) { |
addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { |
boundClosureBuffer.add(',\n $stubName: $memberValue'); |
}); |
- boundClosureBuffer.add("\n});\n"); |
+ boundClosureBuffer.add("\n};\n"); |
closureClass = namer.isolateAccess(closureClassElement); |
@@ -1040,7 +1059,7 @@ if (typeof window != 'undefined' && typeof document != 'undefined' && |
nativeEmitter.assembleCode(mainBuffer); |
emitMain(mainBuffer); |
mainBuffer.add('function init() {\n'); |
- mainBuffer.add(' $isolateProperties = {};\n'); |
+ mainBuffer.add('$isolateProperties = {};\n'); |
addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
emitFinishIsolateConstructor(mainBuffer); |
mainBuffer.add('}\n'); |