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 |