-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
271 lines (258 loc) · 14.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>fork()
</title>
<link rel="alternate" href="http://ripsawridge.github.io//feed.xml" type="application/rss+xml" title="Notes from my endeavors">
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic|Anonymous+Pro:400,700,400italic,700italic|Merriweather:400,700,300">
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<header class="header">
<div class="content-wrap">
<div class="logo">
<h1><a href="http://ripsawridge.github.io/">fork()</a></h1>
<p class="description">Notes from my endeavors</p>
</div>
</div>
</header>
<div id="content">
<div class="content-wrap">
<article class="article intro">
<header>
<p class="date"><span>14. November 2019</span></p>
<h2><a href="/articles/exceptions/">Exceptions in v8</a></h2>
</header>
<section class="content"><p>How do exceptions work in v8? Let’s see.
<img src="images/peppermint.jpg" width=200 align="right"></p>
<p>I’ll use a little program to motivate our<span class="widont"> </span>discussion:</p>
<pre><code class="language-javascript"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">a</span>) </span>{
<span class="keyword">if</span> (a === <span class="literal">true</span>) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"Oh no."</span>);
}
<span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params">a</span>) </span>{
<span class="keyword">try</span> {
foo(a);
} <span class="keyword">catch</span>(e) {
print(e);
}
}
bar(<span class="literal">true</span>);</code></pre>
<p>The bytecode for <code>foo</code> looks like this (I cleaned up the output from <code>--print-bytecode</code> slightly):</p>
<pre><code>Generated bytecode for function: foo
Parameter count 2
Register count 2
Frame size 8
0 StackCheck
1 LdaTrue
2 TestEqualStrict a0, [0]
5 JumpIfFalse [19] (@ 24)
7 LdaGlobal [0], [1]
10 Star r0
12 LdaConstant [1]
14 Star r1
16 Ldar r0
18 Construct r0, r1-r1, [3]
23 Throw
24 LdaUndefined
25 Return
Constant pool (size = 2)
0: <String[#5]: Error>
1: <String[#6]: Oh no.>
Handler Table (size = 0)</code></pre><p>The important thing here is that if the <code>JumpIfFalse</code> isn’t taken, then we create an Error object, leaving it in the accumulator
for the <code>Throw</code> bytecode. We don’t expect to ever return from that bytecode.
How strange and<span class="widont"> </span>interesting…</p>
<p>We’ll get right into that, but first let me show you the bytecode for <code>bar</code> as
well, because it has a catch handler that’ll be a point of interest for<span class="widont"> </span>us:</p>
<pre><code>Generated bytecode for function: bar
Parameter count 2
Register count 4
Frame size 16
0 StackCheck
1 Mov <context>, r0
4 LdaGlobal [0], [0]
7 Star r1
9 CallUndefinedReceiver1 r1, a0, [2]
13 Jump [30] (@ 43)
15 Star r1
17 CreateCatchContext r1, [1]
20 Star r0
22 LdaTheHole
23 SetPendingMessage
24 Ldar r0
26 PushContext r1
28 LdaGlobal [2], [4]
31 Star r2
33 LdaImmutableCurrentContextSlot [2]
35 Star r3
37 CallUndefinedReceiver1 r2, r3, [6]
41 PopContext r1
43 LdaUndefined
44 Return
Constant pool (size = 3)
0: <String[#3]: foo>
1: <ScopeInfo CATCH_SCOPE [5]>
2: <String[#5]: print>
Handler Table (size = 16)
from to hdlr (prediction, data)
( 4, 13) -> 15 (prediction=1, data=0)</code></pre><p>Here you can see the call to <code>foo</code> at offset 9, then a jump down to offset 43
where we return undefined (how boring). Offsets 15 to 41 are the catch handler.
The <code>Handler Table</code> at the bottom lays this out. It shows the try region goes
from offsets 4 to 13, and the handler that corresponds to it starts at offset<span class="widont"> </span>15.</p>
<p>Very nice.</p>
<p>So what does the <code>Throw</code> bytecode do? Like all bytecodes, the implementation
is provided in file <a href="https://cs.chromium.org/chromium/src/v8/src/interpreter/interpreter-generator.cc">interpreter-generator.cc</a>:</p>
<pre><code class="language-cpp"><span class="comment">// Throws the exception in the accumulator.</span>
IGNITION_HANDLER(Throw, InterpreterAssembler) {
TNode<Object> exception = GetAccumulator();
TNode<Context> context = GetContext();
CallRuntime(Runtime::kThrow, context, exception);
<span class="comment">// We shouldn't ever return from a throw.</span>
Abort(AbortReason::kUnexpectedReturnFromThrow);
Unreachable();
}</code></pre>
<p>Okay, that’s easy, we just call a runtime function. It’s nice to see the abort
in here that documents our expectations. The runtime function (in
<a href="https://cs.chromium.org/chromium/src/v8/src/runtime/runtime-internal.cc">runtime-internal.cc</a>) is also simple, just returning the result of Isolate::Throw() back from C++
to the world of generated<span class="widont"> </span>code:</p>
<pre><code class="language-cpp">RUNTIME_FUNCTION(Runtime_Throw) {
<span class="function">HandleScope <span class="title">scope</span><span class="params">(isolate)</span></span>;
DCHECK_EQ(<span class="number">1</span>, args.length());
<span class="keyword">return</span> isolate->Throw(args[<span class="number">0</span>]);
}</code></pre>
<p>You’d <em>never suspect</em> that we just skipped over something absolutely breathtaking,
but we did. Let’s return to it after a look at the end of the road, <code>Isolate::Throw</code>:</p>
<pre><code class="language-cpp">
Object Isolate::Throw(Object raw_exception, MessageLocation* location) {
DCHECK(!has_pending_exception());
<span class="function">HandleScope <span class="title">scope</span><span class="params">(<span class="keyword">this</span>)</span></span>;
Handle<Object> exception(raw_exception, <span class="keyword">this</span>);
...
... skipping over some interesting stuff to focus on the <span class="string">"bones"</span> of
... the function.
...
<span class="comment">// Set the exception being thrown.</span>
set_pending_exception(*exception);
<span class="keyword">return</span> ReadOnlyRoots(heap()).exception();
}</code></pre>
<p>The main thing that happens here is that we save the exception object in
the isolate, and return a curious sentinel value in the global root set,
<code>exception()</code>. We only indicate that there is an exception pending in the
system by saving this value, and don’t do anything exotic. The crazy stuff
is yet to come, awakened into hideous life by that innocuous sentinel<span class="widont"> </span>value.</p>
<p>Here’s what happens now. When the runtime function returns this value to
generated code, it comes into some tricky platform dependent code we call
<code>CEntryStub</code>. This code is responsible for building a frame and calling
into C++. It also recognizes pending exceptions and (gasp!) drops frames
from the stack in order to call the topmost handler. Let’s have a look, now in
<a href="https://cs.chromium.org/chromium/src/v8/src/builtins/ia32/builtins-ia32.cc">builtins-ia32.cc</a>,
method <code>Builtins::Generate_CEntry</code>:</p>
<pre><code class="language-cpp"> ...
__ call(kRuntimeCallFunctionRegister);
<span class="comment">// Result is in eax or edx:eax - do not destroy these registers!</span>
<span class="comment">// Check result for exception sentinel.</span>
Label exception_returned;
__ CompareRoot(eax, RootIndex::kException);
__ j(equal, &exception_returned);
...
<span class="comment">// Exit the JavaScript to C++ exit frame.</span>
__ LeaveExitFrame(save_doubles == kSaveFPRegs, argv_mode == kArgvOnStack);
__ ret(<span class="number">0</span>);
...
<span class="comment">// Handling of exception.</span>
__ bind(&exception_returned);</code></pre>
<p>The code above is dutifully calling the runtime function requested. In our
case, it was <code>Runtime_Throw</code>, but this body of code is used for the many
dozens of runtime functions we have. After the call, you can see we are
comparing the return value with that magic <code>exception</code> sentinel (here it
has a different name, <code>RootIndex::kException</code>. We’ve often got a few ways
to refer to something, depending on what kind of code you’re in. All part
of the fun…). If we don’t see it, we can return to the bytecode handler,
builtin or stub, getting somewhat closer to user code. Otherwise, we do
interesting<span class="widont"> </span>things:</p>
<pre><code class="language-cpp"> <span class="comment">// Ask the runtime for help to determine the handler. This will set eax to</span>
<span class="comment">// contain the current pending exception, don't clobber it.</span>
ExternalReference find_handler =
ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler);
{
<span class="function">FrameScope <span class="title">scope</span><span class="params">(masm, StackFrame::<span class="caps">MANUAL</span>)</span></span>;
__ PrepareCallCFunction(<span class="number">3</span>, eax);
__ mov(Operand(esp, <span class="number">0</span> * kSystemPointerSize), Immediate(<span class="number">0</span>)); <span class="comment">// argc.</span>
__ mov(Operand(esp, <span class="number">1</span> * kSystemPointerSize), Immediate(<span class="number">0</span>)); <span class="comment">// argv.</span>
__ Move(esi,
Immediate(ExternalReference::isolate_address(masm->isolate())));
__ mov(Operand(esp, <span class="number">2</span> * kSystemPointerSize), esi);
__ CallCFunction(find_handler, <span class="number">3</span>);
}
<span class="comment">// Retrieve the handler context, <span class="caps">SP</span> and <span class="caps">FP</span>.</span>
__ mov(esp, __ ExternalReferenceAsOperand(pending_handler_sp_address, esi));
__ mov(ebp, __ ExternalReferenceAsOperand(pending_handler_fp_address, esi));
__ mov(esi,
__ ExternalReferenceAsOperand(pending_handler_context_address, esi));</code></pre>
<p>First we call back into C++, searching for an exception handler. We’ll
definitely have one. I skipped over a section of code in <code>Isolate::Throw</code> that
would abort execution if there is no handler. I really enjoy what’s next:
we simply set the stack pointer and the frame pointer to the appropriate values
for a handler somewhere below us on the stack. What about dutifully
returning from all the functions we may have between here and<span class="widont"> </span>there?</p>
<p>Nope!</p>
<p>A few lines later we begin executing that handler like<span class="widont"> </span>this:</p>
<pre><code class="language-cpp"> <span class="comment">// Compute the handler entry address and jump to it.</span>
__ mov(edi, __ ExternalReferenceAsOperand(pending_handler_entrypoint_address,
edi));
__ jmp(edi);
}</code></pre>
<p>That final curly brace is just showing that these are the last lines of the
CEntry stub. What a way to go, am I<span class="widont"> </span>right?</p>
<p>Now it’s a good time to remember that we have a catch handler. It’s in
function <code>bar()</code>, and it’s address is at offset 15 in the bytecode. So
whatever <code>Runtime_UnwindAndFindExceptionHandler</code> does, it better return
precisely that information to the CEntryStub so that the stack, frame and
instruction pointer can be set<span class="widont"> </span>appropriately.</p>
<p class="more"><a href="/articles/exceptions/">more</a></p>
</section>
</article>
<article class="article intro">
<header>
<p class="date"><span>25. April 2017</span></p>
<h2><a href="/articles/blink-mysterium/">Poking around in Speedometer</a></h2>
</header>
<section class="content"><p>My marching orders today<span class="widont"> </span>were:</p>
<pre><code>OPPORTUNITIES FOR SMALL IMPROVEMENT IN JQUERY SPEEDOMETER BNCHMRK. STOP.
WHY CALLS TO RUNTIME KEYED LOAD? WHY CALLS TO HANDLEAPICALL? WHY? STOP.</code></pre><p>These days I’m a manager type, more comfortable droning on in sonorous tones
with made up words like “leveraging” and “embiggen,” but p’raps I can saddle
up and look at the code<span class="widont"> </span>again.</p>
<p class="more"><a href="/articles/blink-mysterium/">more</a></p>
</section>
</article>
<article class="article intro">
<header>
<p class="date"><span>21. February 2015</span></p>
<h2><a href="/articles/stack-changes/">Altering JavaScript frames</a></h2>
</header>
<section class="content"><p>For a while I’ve been working on a project in <a href="https://code.google.com/p/v8/">V8</a> to encode type feedback into
simple data structures rather than embedding it in compiled<span class="widont"> </span>code.</p>
<p class="more"><a href="/articles/stack-changes/">more</a></p>
</section>
</article>
</div>
</div>
<footer>
<div class="content-wrap">
<div class="nav"><a href="/archive.html">« Archives</a>
</div>
<section class="about"><p>The views expressed here are simply my own and not my employers or anything
wierd.</p>
<p>Also, I am often mistaken and in the process of bumbling about in order
to learn things.</p>
<p><a href="https://app.wercker.com/project/bykey/f7ee9d19a46e8c2f8440b6af414a2acf"><img src="https://app.wercker.com/status/f7ee9d19a46e8c2f8440b6af414a2acf/m/master" alt="wercker status" title="wercker status"></a></p>
</section>
<section class="copy">
<p>© 2019 Michael Stanton — powered by <a href="https://github.com/jnordberg/wintersmith">Wintersmith</a></p>
</section>
</div>
</footer>
</body>
</html>