dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.26k stars 1.58k forks source link

postMessage and other cross-frame operations are broken in dart2js #3175

Closed vsmenon closed 9 years ago

vsmenon commented 12 years ago

Posting a message to another frame breaks today in dart2js. The problem is here in the generated code:

Isolate.$defineClass("_DOMWindowCrossFrameImpl", "Object", ["dartObjectLocalStorage", "_lib_window?"], {  postMessage$3: function(message, targetOrigin, messagePorts) {   if ($.eqNullB(messagePorts)) {     this._lib_window.postMessage$2(message, targetOrigin);   } else {     this._lib_window.postMessage$3(message, targetOrigin, messagePorts);   }  },

The object "this._lib_window" is a Window object in a different frame - which means it is not affected by any patching we need. In particularly, it has no "postMessage$2" object.

This happens to work in Frog since the frog optimizer replaces postMessage$2 with postMessage at compile time.

Marking high as this is coming up in Dromaeo benchmarks.

rakudrama commented 12 years ago

The cross-frame object can't really have any type since it is impossible to make an is-check work on it, or to have a type-checking.

We will have to generate code like (dart2js syntax):    JS("void", "#.postMessage(#, #)", this._window, targetOrigin, messagePorts);

An alternative would be to have a new kind of native class somewhat like GWT's overlay types. The type has no is-check, assignments just have to be believed, but it would permit simpler syntax for method calls, which would have to be always optimized like in frog.

peter-ahe-google commented 12 years ago

As far as I can tell, this is the source from lib/html/frog/html_frog.dart:

  void postMessage(Dynamic message,                    String targetOrigin,                    [List messagePorts = null]) {     if (messagePorts == null) {       _window.postMessage(message, targetOrigin);     } else {       _window.postMessage(message, targetOrigin, messagePorts);     }   }

If _window is from a different frame, then it needs to be treated as a native object.

I'm also suspecting that calling the method with two different arguments wouldn't be necessary if this was ordinary Dart code. So this is another hint to me that this may actually be native code.

Based on these observations, I wonder if this would work:

  void postMessage(Dynamic message,                    String targetOrigin,                    [List messagePorts = null]) {     if (messagePorts == null) {       _pm3(_window, message, targetOrigin);     } else {       _pm4(_window, message, targetOrigin, messagePorts);     }   }

  _pm3(w, m, t) native "return w.postMessage(m, t);";

  _pm4(w, m, t, p) native "return w.postMessage(m, t, p);";

rakudrama commented 12 years ago

Hi Peter,

That is what we are doing - we are treating _window like a handle without any members of its own. Small detail - _pm3 etc can be a static member.

We have a manually generated version for postMessage to get some basic Dromaeo tests unblocked, but we need to change the generator to emit the dozens of other methods to get full coverage.

vsmenon commented 12 years ago

We've checked in a temporary fix for postMessage along the lines Peter suggested to get that API working. We need to auto-generate something like this to enable other cross frame window / location / history methods.


Set owner to @vsmenon. Added Accepted label.

vsmenon commented 12 years ago

Added Duplicate label. Marked as being merged into #3836.