Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Design of V8 bindings | |
| 2 | |
| 3 This document explains key concepts in the V8 binding architecture | |
| 4 except the lifetime management of DOM wrappers. | |
| 5 See [V8GCController.md](V8GCController.md) to learn the lifetime management. | |
| 6 | |
| 7 [TOC] | |
| 8 | |
| 9 ## Isolate | |
| 10 | |
| 11 An isolate is a concept of a thread in V8. | |
| 12 Isolates and threads are in 1:1 relationship. | |
| 13 One isolate is associated with the main thread. | |
| 14 One isolate is associated with one worker thread. | |
| 15 | |
| 16 ## Context | |
| 17 | |
| 18 A context is a concept of a global variable scope in V8. | |
| 19 Roughly speaking, one window object corresponds to one context. | |
| 20 For example, `<iframe>` has a window object different from a window object | |
| 21 of its parent frame. So the context of the `<iframe>` is different from | |
| 22 the context of the parent frame. Since these contexts create their own | |
| 23 global variable scopes, global variables and prototype chains of the `<iframe>` | |
| 24 are isolated from the ones of the parent frame. | |
| 25 | |
| 26 Here is an example: | |
| 27 | |
| 28 ```html | |
| 29 // main.html | |
| 30 <html><body> | |
| 31 <iframe src="iframe.html"></iframe> | |
| 32 <script> | |
| 33 var foo = 1234; | |
| 34 String.prototype.substr = | |
| 35 function (position, length) { // Hijacks String.prototype.substr | |
| 36 console.log(length); | |
| 37 return "hijacked"; | |
| 38 }; | |
| 39 </script> | |
| 40 </body></html> | |
| 41 | |
| 42 // iframe.html | |
| 43 <script> | |
| 44 console.log(foo); // undefined | |
| 45 var bar = "aaaa".substr(0, 2); // Nothing is logged. | |
| 46 console.log(bar); // "aa" | |
| 47 </script> | |
| 48 ``` | |
| 49 | |
| 50 In summary, each frame has a window object. | |
| 51 Each window object has a context. | |
| 52 Each context has its own global variable scope and prototype chains. | |
| 53 | |
| 54 ## Entered context and current context | |
| 55 | |
| 56 A relationship between isolates and contexts is interesting. | |
| 57 One isolate has to execute JavaScripts in multiple frames, | |
| 58 each of which has its own context. This means that the context associated | |
| 59 with the isolate changes over time. In other words, the relationship between | |
| 60 isolates and contexts is 1:N over the lifetime of the isolate. | |
| 61 | |
| 62 Here we have a concept of an entered context and a current context. | |
| 63 To understand the difference, you need to understand two kinds of | |
| 64 runtime stacks. | |
| 65 | |
| 66 The first stack is a stack of JavaScript functions. | |
| 67 This stack is managed by V8. When one function calls another function, | |
| 68 the callee function is pushed onto the stack. When that function returns, | |
| 69 the function is popped from the stack and the control returns to the caller | |
| 70 function that is now on the top of the stack. Each function has | |
| 71 an associated context. We call the context of the function | |
| 72 that is currently running (i.e., the context of the function that is on the top | |
| 73 of the stack) a current context. | |
| 74 | |
| 75 Here is an example: | |
| 76 | |
| 77 ```html | |
| 78 // main.html | |
| 79 <html><body> | |
| 80 <iframe src="iframe.html"></iframe> | |
| 81 <script> | |
| 82 var iframe = document.querySelector("iframe"); | |
| 83 iframe.onload = function () { | |
| 84 iframe.contentWindow.func(); | |
| 85 } | |
| 86 </script> | |
| 87 </body></html> | |
| 88 | |
| 89 // iframe.html | |
| 90 <script> | |
| 91 function func() { | |
| 92 ...; | |
| 93 } | |
| 94 </script> | |
| 95 ``` | |
| 96 | |
| 97 In the above example, at the point when func() is running, | |
| 98 the current context is the context of the `<iframe>`. | |
| 99 | |
| 100 There is a second stack that operates on a much coarser granularity. | |
| 101 This stack is managed by V8 binding (not by V8). | |
| 102 When V8 binding invokes JavaScript, V8 binding creates a new context | |
|
Yuki
2015/12/24 07:15:15
Exactly speaking, this seems a little bit wrong.
haraken
2015/12/28 02:54:59
Reworded:
creates a new context => enters a con
| |
| 103 and pushes the context onto the stack. | |
| 104 The JavaScript starts running on the context. When the JavaScript finishes | |
| 105 and the control returns back to V8 binding, V8 binding pops the context | |
| 106 from the stack. Given that the control between V8 binding and V8 can be nested | |
| 107 (i.e., V8 binding invokes JavaScript, which calls into V8 binding, | |
| 108 which invokes another JavaScript etc), these contexts form a stack. | |
| 109 The pushing and popping are done by calling v8::Context::Enter() and | |
| 110 v8::Context::Exit() (or v8::Context::Scope). We call the most recently entered | |
| 111 context an entered context. | |
| 112 | |
| 113 In the above example, at the point when func() is running, | |
| 114 the entered context is the context of the main frame | |
| 115 (not the context of `<iframe>`). | |
| 116 | |
| 117 The entered context is a concept to implement the | |
| 118 [entry settings object](https://html.spec.whatwg.org/#entry-settings-object) | |
|
Yuki
2015/12/24 07:15:15
Let's link to the multipage version.
https://html.
haraken
2015/12/28 02:54:59
Done.
| |
| 119 of the HTML spec. The current context is a concept to implement the | |
| 120 [incumbent settings object](https://html.spec.whatwg.org/#incumbent-settings-obj ect) | |
|
Yuki
2015/12/24 07:15:15
Ditto.
https://html.spec.whatwg.org/multipage/weba
haraken
2015/12/28 02:54:59
Done.
| |
| 121 of the HTML spec. | |
| 122 | |
| 123 In summary, the entered context is a context from which the current JavaScript | |
| 124 execution was started. The current context is a context of | |
| 125 the JavaScript function that is currently running. | |
| 126 | |
| 127 ## World | |
| 128 | |
| 129 A world is a concept to sandbox DOM wrappers among content scripts of | |
| 130 Chrome extensions. There are three kinds of worlds: a main world, | |
| 131 an isolated world and a worker world. | |
| 132 A main world is a world where a normal JavaScript downloaded from the web | |
| 133 is executed. | |
| 134 An isolated world is a world where a content script of a Chrome extension. | |
| 135 An isolate of the main thread has 1 main world and N isolated worlds. | |
| 136 An isolate of a worker thread has 1 worker world and 0 isolated world. | |
| 137 [This diagram](https://drive.google.com/file/d/0B1obCOyvTnPKQmJEWkVtOEN2TmM/view ?usp=sharing) | |
| 138 will be helpful to understand the relationship. | |
| 139 | |
| 140 All worlds in one isolate share underlying C++ DOM objects, | |
| 141 but each world has its own DOM wrappers. That way the worlds in one isolate | |
| 142 can operate on the same C++ DOM object without sharing any DOM wrapper | |
| 143 among the worlds. | |
| 144 | |
| 145 Also each world has its own context. | |
| 146 This means that each world has its own global variable scope and | |
| 147 prototype chains. | |
| 148 | |
| 149 As a result of the sandboxing, the worlds in one isolate cannot share | |
| 150 any DOM wrappers or contexts but can share underlying C++ DOM objects. | |
| 151 The fact that no DOM wrappers or contexts are shared means that no JavaScript | |
| 152 objects are shared among the worlds. That way we guarantee the security model | |
| 153 that Chrome extensions doesn't share any JavaScript objects while sharing | |
| 154 the underlying C++ DOM objects. This sandbox allows the Chrome extensions to run | |
| 155 untrusted JavaScripts on a shared DOM structure. | |
| 156 | |
| 157 (Note: An isolated world is a concept of V8 binding, | |
| 158 whereas an isolate and a context are a concept of V8. | |
| 159 V8 does not know what isolated worlds are in an isolate.) | |
| 160 | |
| 161 In summary, an isolate of the main thread consists of 1 main world | |
| 162 and N isolated worlds. An isolate world of a worker thread consists of | |
|
Yuki
2015/12/24 07:15:15
s/An isolate world of/An isolate of/
haraken
2015/12/28 02:54:59
Done.
| |
| 163 1 worker world and 0 isolated world. All worlds in one isolate share the | |
| 164 underlying C++ DOM objects, but each world has its own DOM wrappers. | |
| 165 Each world has its own context and thus has its own global variable scope | |
| 166 and prototype chains. | |
| 167 | |
| 168 ## A relationship between isolates, contexts, worlds and frames | |
| 169 | |
| 170 Let's wrap up the relationship between isolates, contexts, worlds and frames. | |
| 171 | |
| 172 * As a requirement of the DOM side, one HTML page has N frames. | |
| 173 Each frame has its own context. | |
| 174 | |
| 175 * As a requirement of the JavaScript side, one isolate has M worlds. | |
| 176 Each world has its own context. | |
| 177 | |
| 178 As a result, when we execute the main thread where N frames and M worlds | |
| 179 are involved, there exists N * M contexts. In other words, one context is | |
| 180 created for each pair of (frame, world). | |
| 181 [This diagram](https://drive.google.com/file/d/0B1obCOyvTnPKSERSMmpRVjVKQWc/view ?usp=sharing) | |
| 182 will be helpful to understand the relationship. | |
| 183 | |
| 184 The main thread can have only one current context at one time, | |
| 185 but the main thread can have the N * M contexts over its lifetime. | |
| 186 For example, when the main thread is operating on a frame X using a JavaScript | |
| 187 in a world Y, the current context is set to a context for the pair of (X, Y). | |
| 188 The current context of the main thread changes over its lifetime. | |
| 189 | |
| 190 On the other hand, a worker thread has 0 frame and 1 world. | |
| 191 Thus a worker thread has only 1 context. | |
| 192 The current context of the worker thread never changes. | |
| 193 | |
| 194 ## DOM wrappers and worlds | |
| 195 | |
| 196 For compatibility reasons (although this is not speced), | |
| 197 we need to make sure that the same DOM wrapper is returned to JavaScript | |
| 198 as long as the underlying C++ DOM object is alive. | |
| 199 We should not return different DOM wrappers for the same C++ DOM object. | |
| 200 | |
| 201 Here is an example: | |
| 202 | |
| 203 ```html | |
| 204 var div = document.createElement("div"); | |
| 205 div.foo = 1234; // expando | |
| 206 var p = document.createElement("p"); | |
| 207 p.appendChild(div); | |
| 208 div = null; | |
| 209 gc(); | |
| 210 console.log(p.firstChild.foo); // This should be 1234, not undefined | |
| 211 ``` | |
| 212 | |
| 213 To accomplish the semantics that the same DOM wrapper is returned to JavaScript | |
| 214 as long as the underlying C++ DOM object is alive, we need a mapping | |
| 215 from the C++ DOM objects to the DOM wrappers. | |
| 216 In addition, we need to sandbox DOM wrappers in each world. | |
| 217 To meet the requirements, we make each world hold a DOM wrapper storage | |
| 218 that stores a mapping from the C++ DOM objects to the DOM wrappers in that world . | |
| 219 | |
| 220 As a result, we have multiple DOM wrapper storages in one isolate. | |
| 221 The mapping of the main world is written in ScriptWrappable. | |
| 222 If ScriptWrappable::m_wrapper has a non-empty value, it is a DOM wrapper of | |
| 223 the C++ DOM object of the main world. | |
| 224 The mapping of other worlds are written in DOMWrapperMap. | |
| 225 | |
| 226 ## DOM wrappers and contexts | |
| 227 | |
| 228 When you create a new DOM wrapper, you need to choose a correct context | |
| 229 on which the DOM wrapper is created. If you create a new DOM wrapper in a | |
| 230 wrong context, you will end up with leaking JavaScript objects to other | |
| 231 contexts, which is very likely to cause security issues. | |
| 232 | |
| 233 Here is an example: | |
| 234 | |
| 235 ```html | |
| 236 // main.html | |
| 237 <html><body> | |
| 238 <iframe src="iframe.html"></iframe> | |
| 239 <script> | |
| 240 var iframe = document.querySelector("iframe"); | |
| 241 iframe; // The wrapper of the iframe should be created in the context of the ma in frame. | |
| 242 iframe.contentDocument; // The wrapper of the document should be created in the context of the iframe. | |
| 243 iframe.contentDocument.addEventListener("click", | |
| 244 function (event) { // The wrapper of the event should be created in the con text of the iframe. | |
| 245 event.target; | |
| 246 }); | |
| 247 </script> | |
| 248 </body></html> | |
| 249 | |
| 250 // iframe.html | |
| 251 <script> | |
| 252 </script> | |
| 253 ``` | |
| 254 | |
| 255 To make sure that a DOM wrapper is created in a correct context, you need to | |
| 256 make sure that the current context must be set to the correct context | |
| 257 whenever you call toV8(). If you're not sure what context to use, | |
| 258 ask haraken@chromium.org. | |
| 259 | |
| OLD | NEW |