1

I was trying to learn the design of why V8 API is structured the way it is and found a helpful doc as to relationship between various things like isolates, contexts etc: Link to V8 Binding

There, I am confused by a certain paragraph:

For compatibility reasons, we need to make sure that the same DOM wrapper is returned to JavaScript as long as the underlying C++ DOM object is alive. We should not return different DOM wrappers for the same C++ DOM object.

Here is an example:

var div = document.createElement("div");
div.foo = 1234;  // expando
var p = document.createElement("p");
p.appendChild(div);
div = null;
gc();
console.log(p.firstChild.foo);  // This should be 1234, not undefined

To accomplish the semantics that the same DOM wrapper is returned to JavaScript as long as the underlying C++ DOM object is alive, we need a mapping from the C++ DOM objects to the DOM wrappers. In addition, we need to sandbox DOM wrappers in each world. To meet the requirements, we make each world hold a DOM wrapper storage that stores a mapping from the C++ DOM objects to the DOM wrappers in that world.

As a result, we have multiple DOM wrapper storages in one isolate. The mapping of the main world is written in ScriptWrappable. If ScriptWrappable::main_world_wrapper_ has a non-empty value, it is a DOM wrapper of the C++ DOM object of the main world. The mapping of other worlds are written in DOMDataStore.

I am still trying to understand the whole paragraph but the specific code example and the immediate explanation does not make sense to me. I never would have expected the code snippet to print undefined even if it was a purely JavaScript API.

I feel the example is not correct but then without a proper example, it is difficult for me to wrap my head around the concept.

Anurag Kalia
  • 4,668
  • 4
  • 21
  • 28

1 Answers1

1

The property foo is added on the JS object wrapper, not on the internal C++ DOM object.

So when gc() (garbage collection) is called, the JS object initially declared as div will be gone (the variable was set to null before GC) along with its foo property.

If the JS object DOM wrapper was not always the same object, retrieving the C++ DOM object through p.firstChild would return an other, new JS object DOM wrapper, without the foo property.

But since they ensure the wrappers are always the same, whatever the context that will call it, the property is still available.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 1
    In other words: re "I never would have expected the code snippet to print undefined even if it was a purely JavaScript API." --> that's precisely the point, if it did print `undefined` then that would be weird. To make sure that properties like `div.foo` stick around, the JS wrapper object has to be cached. You can also think of it as a linked pair of objects: a JS object and a DOM object. Internally they're not the same, but towards JS code they pretend to be just one object. – jmrk Jul 26 '20 at 13:42
  • The `div` is not a JS Object. DIVs don't get declared, they get created. And created they get by the DOM API. DOM Elements are passed by reference, not by content. The `div` variable is just a pointer to the DOM element.not a wrapper of any kind. – Bekim Bacaj Jul 26 '20 at 16:49
  • @BekimBacaj this article precisely explain that in this imolentation the js object you have (the one that the variable `div` points to), **is** a wrapper, and that DOM elements are first c++ objects before js wrappers are created... – Kaiido Jul 26 '20 at 21:38
  • @Kaiido there is no such thing as js object in dom elements. The wrapper is the P element. JS objects are Object object, Array object, Number object etc, and are fully unrelated to DOM objects. You cannot use JavaScript to create a DOM element. If V8 is trying to use JS objects as wrappers of DOM elements and write properties to their js local wrappers - they are wrong. ;) – Bekim Bacaj Jul 27 '20 at 12:48
  • @BekimBacaj what are you talking about? There is js and the DOM. The DOM can be implemented in many ways, but most browsers are not written in JS and thus DOM objects are not JS objects. Both Blink and for instance servo (FF) do use c++/rust to generate the DOM, not js. This means that both V8 and SpiderMonkey do need some kind of wrapping to link the internal c++/rust objects to the exposed JS objects. In v8 it's done as explained in the article, in [SpiderMonkey](https://doc.servo.org/script/dom/) a similar approach (Reflectors) is being used. – Kaiido Jul 27 '20 at 13:22
  • @BekimBacaj And unless you use a js DOM engine like jsdom, you don't have many other choices. – Kaiido Jul 27 '20 at 13:23