source: webkit/trunk/JavaScriptCore/VM/CodeBlock.cpp@ 34684

Last change on this file since 34684 was 34684, checked in by [email protected], 17 years ago

Reviewed by Geoff.

File size: 23.1 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "CodeBlock.h"
32
33#include "Machine.h"
34#include "debugger.h"
35#include "JSValue.h"
36#include <stdio.h>
37
38namespace KJS {
39
40static UString escapeQuotes(const UString& str)
41{
42 UString result = str;
43 int pos = 0;
44 while ((pos = result.find('\"', pos)) >= 0) {
45 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
46 pos += 4;
47 }
48 return result;
49}
50
51static UString valueToSourceString(ExecState* exec, JSValue* val)
52{
53 if (val->isString()) {
54 UString result("\"");
55 result += escapeQuotes(val->toString(exec)) + "\"";
56 return result;
57 }
58
59 return val->toString(exec);
60}
61
62static CString registerName(int r)
63{
64 if (r < 0)
65 return (UString("lr") + UString::from(-r)).UTF8String();
66
67 return (UString("tr") + UString::from(r)).UTF8String();
68}
69
70static CString constantName(ExecState* exec, int k, JSValue* value)
71{
72 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
73}
74
75static CString idName(int id0, const Identifier& ident)
76{
77 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
78}
79
80static UString regexpToSourceString(RegExp* regExp)
81{
82 UString pattern = UString("/") + regExp->pattern() + "/";
83 if (regExp->global())
84 pattern += "g";
85 if (regExp->ignoreCase())
86 pattern += "i";
87 if (regExp->multiline())
88 pattern += "m";
89
90 return pattern;
91}
92
93static CString regexpName(int re, RegExp* regexp)
94{
95 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
96}
97
98NEVER_INLINE static const char* debugHookName(int debugHookID)
99{
100 switch (static_cast<DebugHookID>(debugHookID)) {
101 case DidEnterCallFrame:
102 return "didEnterCallFrame";
103 case WillLeaveCallFrame:
104 return "willLeaveCallFrame";
105 case WillExecuteStatement:
106 return "willExecuteStatement";
107 case WillExecuteProgram:
108 return "willExecuteProgram";
109 case DidExecuteProgram:
110 return "didExecuteProgram";
111 case DidReachBreakpoint:
112 return "didReachBreakpoint";
113 }
114
115 ASSERT_NOT_REACHED();
116 return "";
117}
118
119static int jumpTarget(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
120{
121 return it - begin + offset;
122}
123
124static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
125{
126 int r0 = (++it)->u.operand;
127 int r1 = (++it)->u.operand;
128
129 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
130}
131
132static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
133{
134 int r0 = (++it)->u.operand;
135 int r1 = (++it)->u.operand;
136 int r2 = (++it)->u.operand;
137 printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
138}
139
140static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
141{
142 int r0 = (++it)->u.operand;
143 int offset = (++it)->u.operand;
144 printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, jumpTarget(begin, it, offset));
145}
146
147void CodeBlock::dump(ExecState* exec) const
148{
149 Vector<Instruction>::const_iterator begin = instructions.begin();
150 Vector<Instruction>::const_iterator end = instructions.end();
151
152 size_t instructionCount = 0;
153 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
154 if (exec->machine()->isOpcode(it->u.opcode))
155 ++instructionCount;
156
157 printf("%lu instructions; %lu bytes at %p; %d locals (%d parameters); %d temporaries\n\n",
158 static_cast<unsigned long>(instructionCount),
159 static_cast<unsigned long>(instructions.size() * sizeof(Instruction)),
160 this, numLocals, numParameters, numTemporaries);
161
162 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
163 dump(exec, begin, it);
164
165 if (identifiers.size()) {
166 printf("\nIdentifiers:\n");
167 size_t i = 0;
168 do {
169 printf(" id%u = %s\n", static_cast<unsigned>(i), identifiers[i].ascii());
170 ++i;
171 } while (i != identifiers.size());
172 }
173
174 if (jsValues.size()) {
175 printf("\nConstants:\n");
176 size_t i = 0;
177 do {
178 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, jsValues[i]).ascii());
179 ++i;
180 } while (i < jsValues.size());
181 }
182
183 if (regexps.size()) {
184 printf("\nRegExps:\n");
185 size_t i = 0;
186 do {
187 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(regexps[i].get()).ascii());
188 ++i;
189 } while (i < regexps.size());
190 }
191
192 if (exceptionHandlers.size()) {
193 printf("\nException Handlers:\n");
194 unsigned i = 0;
195 do {
196 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i+1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
197 ++i;
198 } while (i < exceptionHandlers.size());
199 }
200
201 printf("\n");
202}
203
204void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
205{
206 int location = it - begin;
207 switch (exec->machine()->getOpcodeID(it->u.opcode)) {
208 case op_load: {
209 int r0 = (++it)->u.operand;
210 int k0 = (++it)->u.operand;
211 printf("[%4d] load\t\t %s, %s\t\t\n", location, registerName(r0).c_str(), constantName(exec, k0, jsValues[k0]).c_str());
212 break;
213 }
214 case op_new_object: {
215 int r0 = (++it)->u.operand;
216 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
217 break;
218 }
219 case op_new_array: {
220 int r0 = (++it)->u.operand;
221 printf("[%4d] new_array\t %s\n", location, registerName(r0).c_str());
222 break;
223 }
224 case op_new_regexp: {
225 int r0 = (++it)->u.operand;
226 int re0 = (++it)->u.operand;
227 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexps[re0].get()).c_str());
228 break;
229 }
230 case op_mov: {
231 int r0 = (++it)->u.operand;
232 int r1 = (++it)->u.operand;
233 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
234 break;
235 }
236 case op_not: {
237 printUnaryOp(location, it, "not");
238 break;
239 }
240 case op_eq: {
241 printBinaryOp(location, it, "eq");
242 break;
243 }
244 case op_neq: {
245 printBinaryOp(location, it, "neq");
246 break;
247 }
248 case op_stricteq: {
249 printBinaryOp(location, it, "stricteq");
250 break;
251 }
252 case op_nstricteq: {
253 printBinaryOp(location, it, "nstricteq");
254 break;
255 }
256 case op_less: {
257 printBinaryOp(location, it, "less");
258 break;
259 }
260 case op_lesseq: {
261 printBinaryOp(location, it, "lesseq");
262 break;
263 }
264 case op_pre_inc: {
265 int r0 = (++it)->u.operand;
266 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
267 break;
268 }
269 case op_pre_dec: {
270 int r0 = (++it)->u.operand;
271 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
272 break;
273 }
274 case op_post_inc: {
275 printUnaryOp(location, it, "post_inc");
276 break;
277 }
278 case op_post_dec: {
279 printUnaryOp(location, it, "post_dec");
280 break;
281 }
282 case op_to_jsnumber: {
283 printUnaryOp(location, it, "to_jsnumber");
284 break;
285 }
286 case op_negate: {
287 printUnaryOp(location, it, "negate");
288 break;
289 }
290 case op_add: {
291 printBinaryOp(location, it, "add");
292 break;
293 }
294 case op_mul: {
295 printBinaryOp(location, it, "mul");
296 break;
297 }
298 case op_div: {
299 printBinaryOp(location, it, "div");
300 break;
301 }
302 case op_mod: {
303 printBinaryOp(location, it, "mod");
304 break;
305 }
306 case op_sub: {
307 printBinaryOp(location, it, "sub");
308 break;
309 }
310 case op_lshift: {
311 printBinaryOp(location, it, "lshift");
312 break;
313 }
314 case op_rshift: {
315 printBinaryOp(location, it, "rshift");
316 break;
317 }
318 case op_urshift: {
319 printBinaryOp(location, it, "urshift");
320 break;
321 }
322 case op_bitand: {
323 printBinaryOp(location, it, "bitand");
324 break;
325 }
326 case op_bitxor: {
327 printBinaryOp(location, it, "bitxor");
328 break;
329 }
330 case op_bitor: {
331 printBinaryOp(location, it, "bitor");
332 break;
333 }
334 case op_bitnot: {
335 printUnaryOp(location, it, "bitnot");
336 break;
337 }
338 case op_instanceof: {
339 printBinaryOp(location, it, "instanceof");
340 break;
341 }
342 case op_typeof: {
343 printUnaryOp(location, it, "typeof");
344 break;
345 }
346 case op_in: {
347 printBinaryOp(location, it, "in");
348 break;
349 }
350 case op_resolve: {
351 int r0 = (++it)->u.operand;
352 int id0 = (++it)->u.operand;
353 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
354 break;
355 }
356 case op_resolve_skip: {
357 int r0 = (++it)->u.operand;
358 int id0 = (++it)->u.operand;
359 int skipLevels = (++it)->u.operand;
360 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), skipLevels);
361 break;
362 }
363 case op_get_scoped_var: {
364 int r0 = (++it)->u.operand;
365 int index = (++it)->u.operand;
366 int skipLevels = (++it)->u.operand;
367 printf("[%4d] get_scoped_var\t\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
368 break;
369 }
370 case op_put_scoped_var: {
371 int index = (++it)->u.operand;
372 int skipLevels = (++it)->u.operand;
373 int r0 = (++it)->u.operand;
374 printf("[%4d] put_scoped_var\t\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
375 break;
376 }
377 case op_resolve_base: {
378 int r0 = (++it)->u.operand;
379 int id0 = (++it)->u.operand;
380 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
381 break;
382 }
383 case op_resolve_with_base: {
384 int r0 = (++it)->u.operand;
385 int r1 = (++it)->u.operand;
386 int id0 = (++it)->u.operand;
387 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
388 break;
389 }
390 case op_resolve_func: {
391 int r0 = (++it)->u.operand;
392 int r1 = (++it)->u.operand;
393 int id0 = (++it)->u.operand;
394 printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
395 break;
396 }
397 case op_get_by_id: {
398 int r0 = (++it)->u.operand;
399 int r1 = (++it)->u.operand;
400 int id0 = (++it)->u.operand;
401 printf("[%4d] get_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
402 break;
403 }
404 case op_put_by_id: {
405 int r0 = (++it)->u.operand;
406 int id0 = (++it)->u.operand;
407 int r1 = (++it)->u.operand;
408 printf("[%4d] put_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
409 break;
410 }
411 case op_put_getter: {
412 int r0 = (++it)->u.operand;
413 int id0 = (++it)->u.operand;
414 int r1 = (++it)->u.operand;
415 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
416 break;
417 }
418 case op_put_setter: {
419 int r0 = (++it)->u.operand;
420 int id0 = (++it)->u.operand;
421 int r1 = (++it)->u.operand;
422 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
423 break;
424 }
425 case op_del_by_id: {
426 int r0 = (++it)->u.operand;
427 int r1 = (++it)->u.operand;
428 int id0 = (++it)->u.operand;
429 printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
430 break;
431 }
432 case op_get_by_val: {
433 int r0 = (++it)->u.operand;
434 int r1 = (++it)->u.operand;
435 int r2 = (++it)->u.operand;
436 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
437 break;
438 }
439 case op_put_by_val: {
440 int r0 = (++it)->u.operand;
441 int r1 = (++it)->u.operand;
442 int r2 = (++it)->u.operand;
443 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
444 break;
445 }
446 case op_del_by_val: {
447 int r0 = (++it)->u.operand;
448 int r1 = (++it)->u.operand;
449 int r2 = (++it)->u.operand;
450 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
451 break;
452 }
453 case op_put_by_index: {
454 int r0 = (++it)->u.operand;
455 unsigned n0 = (++it)->u.operand;
456 int r1 = (++it)->u.operand;
457 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
458 break;
459 }
460 case op_jmp: {
461 int offset = (++it)->u.operand;
462 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
463 break;
464 }
465 case op_jtrue: {
466 printConditionalJump(begin, it, location, "jtrue");
467 break;
468 }
469 case op_jfalse: {
470 printConditionalJump(begin, it, location, "jfalse");
471 break;
472 }
473 case op_jless: {
474 int r0 = (++it)->u.operand;
475 int r1 = (++it)->u.operand;
476 int offset = (++it)->u.operand;
477 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
478 break;
479 }
480 case op_new_func: {
481 int r0 = (++it)->u.operand;
482 int f0 = (++it)->u.operand;
483 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
484 break;
485 }
486 case op_new_func_exp: {
487 int r0 = (++it)->u.operand;
488 int f0 = (++it)->u.operand;
489 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
490 break;
491 }
492 case op_call: {
493 int r0 = (++it)->u.operand;
494 int r1 = (++it)->u.operand;
495 int r2 = (++it)->u.operand;
496 int tempCount = (++it)->u.operand;
497 int argCount = (++it)->u.operand;
498 printf("[%4d] call\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
499 break;
500 }
501 case op_call_eval: {
502 int r0 = (++it)->u.operand;
503 int r1 = (++it)->u.operand;
504 int r2 = (++it)->u.operand;
505 int tempCount = (++it)->u.operand;
506 int argCount = (++it)->u.operand;
507 printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
508 break;
509 }
510 case op_ret: {
511 int r0 = (++it)->u.operand;
512 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
513 break;
514 }
515 case op_construct: {
516 int r0 = (++it)->u.operand;
517 int r1 = (++it)->u.operand;
518 int tempCount = (++it)->u.operand;
519 int argCount = (++it)->u.operand;
520 printf("[%4d] construct\t %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), tempCount, argCount);
521 break;
522 }
523 case op_get_pnames: {
524 int r0 = (++it)->u.operand;
525 int r1 = (++it)->u.operand;
526 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
527 break;
528 }
529 case op_next_pname: {
530 int dest = (++it)->u.operand;
531 int iter = (++it)->u.operand;
532 int offset = (++it)->u.operand;
533 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, jumpTarget(begin, it, offset));
534 break;
535 }
536 case op_push_scope: {
537 int r0 = (++it)->u.operand;
538 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
539 break;
540 }
541 case op_pop_scope: {
542 printf("[%4d] pop_scope\n", location);
543 break;
544 }
545 case op_jmp_scopes: {
546 int scopeDelta = (++it)->u.operand;
547 int offset = (++it)->u.operand;
548 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, jumpTarget(begin, it, offset));
549 break;
550 }
551 case op_catch: {
552 int r0 = (++it)->u.operand;
553 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
554 break;
555 }
556 case op_throw: {
557 int r0 = (++it)->u.operand;
558 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
559 break;
560 }
561 case op_new_error: {
562 int r0 = (++it)->u.operand;
563 int errorType = (++it)->u.operand;
564 int k0 = (++it)->u.operand;
565 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, jsValues[k0]).c_str());
566 break;
567 }
568 case op_jsr: {
569 int retAddrDst = (++it)->u.operand;
570 int offset = (++it)->u.operand;
571 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, jumpTarget(begin, it, offset));
572 break;
573 }
574 case op_sret: {
575 int retAddrSrc = (++it)->u.operand;
576 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
577 break;
578 }
579 case op_debug: {
580 int debugHookID = (++it)->u.operand;
581 int firstLine = (++it)->u.operand;
582 int lastLine = (++it)->u.operand;
583 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
584 break;
585 }
586 case op_end: {
587 int r0 = (++it)->u.operand;
588 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
589 break;
590 }
591 default: {
592 ASSERT_NOT_REACHED();
593 break;
594 }
595 }
596}
597
598void CodeBlock::mark()
599{
600 for (size_t i = 0; i < jsValues.size(); ++i)
601 if (!jsValues[i]->marked())
602 jsValues[i]->mark();
603
604 for (size_t i = 0; i < functions.size(); ++i)
605 functions[i]->body()->mark();
606
607 for (size_t i = 0; i < functionExpressions.size(); ++i)
608 functionExpressions[i]->body()->mark();
609}
610
611bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth)
612{
613 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
614 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
615 unsigned addressOffset = vPC - instructions.begin();
616 ASSERT(addressOffset < instructions.size());
617
618 for (; ptr != end; ++ptr) {
619 // Handlers are ordered innermost first, so the first handler we encounter
620 // that contains the source address is the correct handler to use.
621 if (ptr->start <= addressOffset && ptr->end >= addressOffset) {
622 scopeDepth = ptr->scopeDepth;
623 target = instructions.begin() + ptr->target;
624 return true;
625 }
626 }
627 return false;
628}
629
630int CodeBlock::lineNumberForVPC(const Instruction* vPC)
631{
632 unsigned instructionOffset = vPC - instructions.begin();
633 ASSERT(instructionOffset < instructions.size());
634
635 if (!lineInfo.size())
636 return 1; // Empty function
637
638 int low = 0;
639 int high = lineInfo.size();
640 while (low < high) {
641 int mid = low + (high - low) / 2;
642 if (lineInfo[mid].instructionOffset <= instructionOffset)
643 low = mid + 1;
644 else
645 high = mid;
646 }
647
648 return lineInfo[low - 1].lineNumber;
649}
650
651} // namespace KJS
Note: See TracBrowser for help on using the repository browser.