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

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

2008-10-23 Gavin Barraclough <[email protected]>

Reviewed by Oliver Hunt.

Fix hideous pathological case performance when looking up repatch info, bug #21727.

When repatching JIT code to optimize we look up records providing information about
the generated code (also used to track recsources used in linking to be later released).
The lookup was being performed using a linear scan of all such records.

(1) Split up the different types of reptach information. This means we can search them

separately, and in some cases should reduce their size.

(2) In the case of property accesses, search with a binary chop over the data.
(3) In the case of calls, pass a pointer to the repatch info into the relink function.

  • VM/CTI.cpp: (JSC::CTI::CTI): (JSC::CTI::compileOpCall): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileSlowCases): (JSC::CTI::privateCompile): (JSC::CTI::unlinkCall): (JSC::CTI::linkCall):
  • VM/CTI.h:
  • VM/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::unlinkCallers): (JSC::CodeBlock::derefStructureIDs):
  • VM/CodeBlock.h: (JSC::StructureStubInfo::StructureStubInfo): (JSC::CallLinkInfo::CallLinkInfo): (JSC::CallLinkInfo::setUnlinked): (JSC::CallLinkInfo::isLinked): (JSC::getStructureStubInfoReturnLocation): (JSC::binaryChop): (JSC::CodeBlock::addCaller): (JSC::CodeBlock::getStubInfo):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::emitResolve): (JSC::CodeGenerator::emitGetById): (JSC::CodeGenerator::emitPutById): (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct):
  • VM/Machine.cpp: (JSC::Machine::cti_vm_lazyLinkCall):
File size: 43.4 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 "CTI.h"
34#include "JSValue.h"
35#include "Machine.h"
36#include "debugger.h"
37#include <stdio.h>
38#include <wtf/StringExtras.h>
39
40namespace JSC {
41
42#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
43
44static UString escapeQuotes(const UString& str)
45{
46 UString result = str;
47 int pos = 0;
48 while ((pos = result.find('\"', pos)) >= 0) {
49 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
50 pos += 4;
51 }
52 return result;
53}
54
55static UString valueToSourceString(ExecState* exec, JSValuePtr val)
56{
57 if (val->isString()) {
58 UString result("\"");
59 result += escapeQuotes(val->toString(exec)) + "\"";
60 return result;
61 }
62
63 return val->toString(exec);
64}
65
66static CString registerName(int r)
67{
68 if (r == missingThisObjectMarker())
69 return "<null>";
70
71 return (UString("r") + UString::from(r)).UTF8String();
72}
73
74static CString constantName(ExecState* exec, int k, JSValuePtr value)
75{
76 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
77}
78
79static CString idName(int id0, const Identifier& ident)
80{
81 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
82}
83
84static UString regexpToSourceString(RegExp* regExp)
85{
86 UString pattern = UString("/") + regExp->pattern() + "/";
87 if (regExp->global())
88 pattern += "g";
89 if (regExp->ignoreCase())
90 pattern += "i";
91 if (regExp->multiline())
92 pattern += "m";
93
94 return pattern;
95}
96
97static CString regexpName(int re, RegExp* regexp)
98{
99 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
100}
101
102static UString pointerToSourceString(void* p)
103{
104 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
105 snprintf(buffer, sizeof(buffer), "%p", p);
106 return buffer;
107}
108
109NEVER_INLINE static const char* debugHookName(int debugHookID)
110{
111 switch (static_cast<DebugHookID>(debugHookID)) {
112 case DidEnterCallFrame:
113 return "didEnterCallFrame";
114 case WillLeaveCallFrame:
115 return "willLeaveCallFrame";
116 case WillExecuteStatement:
117 return "willExecuteStatement";
118 case WillExecuteProgram:
119 return "willExecuteProgram";
120 case DidExecuteProgram:
121 return "didExecuteProgram";
122 case DidReachBreakpoint:
123 return "didReachBreakpoint";
124 }
125
126 ASSERT_NOT_REACHED();
127 return "";
128}
129
130static int jumpTarget(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
131{
132 return it - begin + offset;
133}
134
135static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
136{
137 int r0 = (++it)->u.operand;
138 int r1 = (++it)->u.operand;
139
140 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
141}
142
143static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
144{
145 int r0 = (++it)->u.operand;
146 int r1 = (++it)->u.operand;
147 int r2 = (++it)->u.operand;
148 printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
149}
150
151static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
152{
153 int r0 = (++it)->u.operand;
154 int offset = (++it)->u.operand;
155 printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, jumpTarget(begin, it, offset));
156}
157
158static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
159{
160 int r0 = (++it)->u.operand;
161 int r1 = (++it)->u.operand;
162 int id0 = (++it)->u.operand;
163 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
164 it += 4;
165}
166
167static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
168{
169 int r0 = (++it)->u.operand;
170 int id0 = (++it)->u.operand;
171 int r1 = (++it)->u.operand;
172 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
173 it += 4;
174}
175
176void CodeBlock::printStructureID(const char* name, const Instruction* vPC, int operand) const
177{
178 unsigned instructionOffset = vPC - instructions.begin();
179 printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structureID).UTF8String().c_str());
180}
181
182void CodeBlock::printStructureIDs(const Instruction* vPC) const
183{
184 Machine* machine = globalData->machine;
185 unsigned instructionOffset = vPC - instructions.begin();
186
187 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id)) {
188 printStructureID("get_by_id", vPC, 4);
189 return;
190 }
191 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
192 printStructureID("get_by_id_self", vPC, 4);
193 return;
194 }
195 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
196 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str());
197 return;
198 }
199 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
200 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_new", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureIDChain).UTF8String().c_str());
201 return;
202 }
203 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
204 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structureID).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureIDChain).UTF8String().c_str());
205 return;
206 }
207 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id)) {
208 printStructureID("put_by_id", vPC, 4);
209 return;
210 }
211 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
212 printStructureID("put_by_id_replace", vPC, 4);
213 return;
214 }
215 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
216 printStructureID("resolve_global", vPC, 4);
217 return;
218 }
219
220 // These instructions doesn't ref StructureIDs.
221 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_call) || vPC[0].u.opcode == machine->getOpcode(op_call_eval) || vPC[0].u.opcode == machine->getOpcode(op_construct));
222}
223
224void CodeBlock::dump(ExecState* exec) const
225{
226 Vector<Instruction>::const_iterator begin = instructions.begin();
227 Vector<Instruction>::const_iterator end = instructions.end();
228
229 size_t instructionCount = 0;
230 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
231 if (exec->machine()->isOpcode(it->u.opcode))
232 ++instructionCount;
233
234 printf("%lu instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
235 static_cast<unsigned long>(instructionCount),
236 static_cast<unsigned long>(instructions.size() * sizeof(Instruction)),
237 this, numParameters, numCalleeRegisters);
238
239 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
240 dump(exec, begin, it);
241
242 if (identifiers.size()) {
243 printf("\nIdentifiers:\n");
244 size_t i = 0;
245 do {
246 printf(" id%u = %s\n", static_cast<unsigned>(i), identifiers[i].ascii());
247 ++i;
248 } while (i != identifiers.size());
249 }
250
251 if (constantRegisters.size()) {
252 printf("\nConstants:\n");
253 size_t i = 0;
254 do {
255 printf(" r%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
256 ++i;
257 } while (i < constantRegisters.size());
258 }
259
260 if (unexpectedConstants.size()) {
261 printf("\nUnexpected Constants:\n");
262 size_t i = 0;
263 do {
264 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, unexpectedConstants[i]).ascii());
265 ++i;
266 } while (i < unexpectedConstants.size());
267 }
268
269 if (regexps.size()) {
270 printf("\nRegExps:\n");
271 size_t i = 0;
272 do {
273 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(regexps[i].get()).ascii());
274 ++i;
275 } while (i < regexps.size());
276 }
277
278 if (globalResolveInstructions.size() || propertyAccessInstructions.size())
279 printf("\nStructureIDs:\n");
280
281 if (globalResolveInstructions.size()) {
282 size_t i = 0;
283 do {
284 printStructureIDs(&instructions[globalResolveInstructions[i]]);
285 ++i;
286 } while (i < globalResolveInstructions.size());
287 }
288 if (propertyAccessInstructions.size()) {
289 size_t i = 0;
290 do {
291 printStructureIDs(&instructions[propertyAccessInstructions[i].opcodeIndex]);
292 ++i;
293 } while (i < propertyAccessInstructions.size());
294 }
295
296 if (exceptionHandlers.size()) {
297 printf("\nException Handlers:\n");
298 unsigned i = 0;
299 do {
300 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
301 ++i;
302 } while (i < exceptionHandlers.size());
303 }
304
305 if (immediateSwitchJumpTables.size()) {
306 printf("Immediate Switch Jump Tables:\n");
307 unsigned i = 0;
308 do {
309 printf(" %1d = {\n", i);
310 int entry = 0;
311 Vector<int32_t>::const_iterator end = immediateSwitchJumpTables[i].branchOffsets.end();
312 for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
313 if (!*iter)
314 continue;
315 printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
316 }
317 printf(" }\n");
318 ++i;
319 } while (i < immediateSwitchJumpTables.size());
320 }
321
322 if (characterSwitchJumpTables.size()) {
323 printf("\nCharacter Switch Jump Tables:\n");
324 unsigned i = 0;
325 do {
326 printf(" %1d = {\n", i);
327 int entry = 0;
328 Vector<int32_t>::const_iterator end = characterSwitchJumpTables[i].branchOffsets.end();
329 for (Vector<int32_t>::const_iterator iter = characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
330 if (!*iter)
331 continue;
332 ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
333 UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
334 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
335 }
336 printf(" }\n");
337 ++i;
338 } while (i < characterSwitchJumpTables.size());
339 }
340
341 if (stringSwitchJumpTables.size()) {
342 printf("\nString Switch Jump Tables:\n");
343 unsigned i = 0;
344 do {
345 printf(" %1d = {\n", i);
346 StringJumpTable::StringOffsetTable::const_iterator end = stringSwitchJumpTables[i].offsetTable.end();
347 for (StringJumpTable::StringOffsetTable::const_iterator iter = stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
348 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
349 printf(" }\n");
350 ++i;
351 } while (i < stringSwitchJumpTables.size());
352 }
353
354 printf("\n");
355}
356
357void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
358{
359 int location = it - begin;
360 switch (exec->machine()->getOpcodeID(it->u.opcode)) {
361 case op_enter: {
362 printf("[%4d] enter\n", location);
363 break;
364 }
365 case op_enter_with_activation: {
366 int r0 = (++it)->u.operand;
367 printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str());
368 break;
369 }
370 case op_create_arguments: {
371 printf("[%4d] create_arguments\n", location);
372 break;
373 }
374 case op_convert_this: {
375 int r0 = (++it)->u.operand;
376 printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
377 break;
378 }
379 case op_unexpected_load: {
380 int r0 = (++it)->u.operand;
381 int k0 = (++it)->u.operand;
382 printf("[%4d] unexpected_load\t %s, %s\n", location, registerName(r0).c_str(), constantName(exec, k0, unexpectedConstants[k0]).c_str());
383 break;
384 }
385 case op_new_object: {
386 int r0 = (++it)->u.operand;
387 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
388 break;
389 }
390 case op_new_array: {
391 int dst = (++it)->u.operand;
392 int argv = (++it)->u.operand;
393 int argc = (++it)->u.operand;
394 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
395 break;
396 }
397 case op_new_regexp: {
398 int r0 = (++it)->u.operand;
399 int re0 = (++it)->u.operand;
400 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexps[re0].get()).c_str());
401 break;
402 }
403 case op_mov: {
404 int r0 = (++it)->u.operand;
405 int r1 = (++it)->u.operand;
406 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
407 break;
408 }
409 case op_not: {
410 printUnaryOp(location, it, "not");
411 break;
412 }
413 case op_eq: {
414 printBinaryOp(location, it, "eq");
415 break;
416 }
417 case op_eq_null: {
418 printUnaryOp(location, it, "eq_null");
419 break;
420 }
421 case op_neq: {
422 printBinaryOp(location, it, "neq");
423 break;
424 }
425 case op_neq_null: {
426 printUnaryOp(location, it, "neq_null");
427 break;
428 }
429 case op_stricteq: {
430 printBinaryOp(location, it, "stricteq");
431 break;
432 }
433 case op_nstricteq: {
434 printBinaryOp(location, it, "nstricteq");
435 break;
436 }
437 case op_less: {
438 printBinaryOp(location, it, "less");
439 break;
440 }
441 case op_lesseq: {
442 printBinaryOp(location, it, "lesseq");
443 break;
444 }
445 case op_pre_inc: {
446 int r0 = (++it)->u.operand;
447 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
448 break;
449 }
450 case op_pre_dec: {
451 int r0 = (++it)->u.operand;
452 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
453 break;
454 }
455 case op_post_inc: {
456 printUnaryOp(location, it, "post_inc");
457 break;
458 }
459 case op_post_dec: {
460 printUnaryOp(location, it, "post_dec");
461 break;
462 }
463 case op_to_jsnumber: {
464 printUnaryOp(location, it, "to_jsnumber");
465 break;
466 }
467 case op_negate: {
468 printUnaryOp(location, it, "negate");
469 break;
470 }
471 case op_add: {
472 printBinaryOp(location, it, "add");
473 ++it;
474 break;
475 }
476 case op_mul: {
477 printBinaryOp(location, it, "mul");
478 ++it;
479 break;
480 }
481 case op_div: {
482 printBinaryOp(location, it, "div");
483 break;
484 }
485 case op_mod: {
486 printBinaryOp(location, it, "mod");
487 break;
488 }
489 case op_sub: {
490 printBinaryOp(location, it, "sub");
491 ++it;
492 break;
493 }
494 case op_lshift: {
495 printBinaryOp(location, it, "lshift");
496 break;
497 }
498 case op_rshift: {
499 printBinaryOp(location, it, "rshift");
500 break;
501 }
502 case op_urshift: {
503 printBinaryOp(location, it, "urshift");
504 break;
505 }
506 case op_bitand: {
507 printBinaryOp(location, it, "bitand");
508 ++it;
509 break;
510 }
511 case op_bitxor: {
512 printBinaryOp(location, it, "bitxor");
513 ++it;
514 break;
515 }
516 case op_bitor: {
517 printBinaryOp(location, it, "bitor");
518 ++it;
519 break;
520 }
521 case op_bitnot: {
522 printUnaryOp(location, it, "bitnot");
523 break;
524 }
525 case op_instanceof: {
526 int r0 = (++it)->u.operand;
527 int r1 = (++it)->u.operand;
528 int r2 = (++it)->u.operand;
529 int r3 = (++it)->u.operand;
530 printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str());
531 break;
532 }
533 case op_typeof: {
534 printUnaryOp(location, it, "typeof");
535 break;
536 }
537 case op_is_undefined: {
538 printUnaryOp(location, it, "is_undefined");
539 break;
540 }
541 case op_is_boolean: {
542 printUnaryOp(location, it, "is_boolean");
543 break;
544 }
545 case op_is_number: {
546 printUnaryOp(location, it, "is_number");
547 break;
548 }
549 case op_is_string: {
550 printUnaryOp(location, it, "is_string");
551 break;
552 }
553 case op_is_object: {
554 printUnaryOp(location, it, "is_object");
555 break;
556 }
557 case op_is_function: {
558 printUnaryOp(location, it, "is_function");
559 break;
560 }
561 case op_in: {
562 printBinaryOp(location, it, "in");
563 break;
564 }
565 case op_resolve: {
566 int r0 = (++it)->u.operand;
567 int id0 = (++it)->u.operand;
568 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
569 break;
570 }
571 case op_resolve_skip: {
572 int r0 = (++it)->u.operand;
573 int id0 = (++it)->u.operand;
574 int skipLevels = (++it)->u.operand;
575 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), skipLevels);
576 break;
577 }
578 case op_resolve_global: {
579 int r0 = (++it)->u.operand;
580 JSValuePtr scope = static_cast<JSValuePtr>((++it)->u.jsCell);
581 int id0 = (++it)->u.operand;
582 printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, identifiers[id0]).c_str());
583 it += 2;
584 break;
585 }
586 case op_get_scoped_var: {
587 int r0 = (++it)->u.operand;
588 int index = (++it)->u.operand;
589 int skipLevels = (++it)->u.operand;
590 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
591 break;
592 }
593 case op_put_scoped_var: {
594 int index = (++it)->u.operand;
595 int skipLevels = (++it)->u.operand;
596 int r0 = (++it)->u.operand;
597 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
598 break;
599 }
600 case op_get_global_var: {
601 int r0 = (++it)->u.operand;
602 JSValuePtr scope = static_cast<JSValuePtr>((++it)->u.jsCell);
603 int index = (++it)->u.operand;
604 printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
605 break;
606 }
607 case op_put_global_var: {
608 JSValuePtr scope = static_cast<JSValuePtr>((++it)->u.jsCell);
609 int index = (++it)->u.operand;
610 int r0 = (++it)->u.operand;
611 printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
612 break;
613 }
614 case op_resolve_base: {
615 int r0 = (++it)->u.operand;
616 int id0 = (++it)->u.operand;
617 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
618 break;
619 }
620 case op_resolve_with_base: {
621 int r0 = (++it)->u.operand;
622 int r1 = (++it)->u.operand;
623 int id0 = (++it)->u.operand;
624 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
625 break;
626 }
627 case op_resolve_func: {
628 int r0 = (++it)->u.operand;
629 int r1 = (++it)->u.operand;
630 int id0 = (++it)->u.operand;
631 printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
632 break;
633 }
634 case op_get_by_id: {
635 printGetByIdOp(location, it, identifiers, "get_by_id");
636 break;
637 }
638 case op_get_by_id_self: {
639 printGetByIdOp(location, it, identifiers, "get_by_id_self");
640 break;
641 }
642 case op_get_by_id_proto: {
643 printGetByIdOp(location, it, identifiers, "get_by_id_proto");
644 break;
645 }
646 case op_get_by_id_chain: {
647 printGetByIdOp(location, it, identifiers, "get_by_id_chain");
648 break;
649 }
650 case op_get_by_id_generic: {
651 printGetByIdOp(location, it, identifiers, "get_by_id_generic");
652 break;
653 }
654 case op_get_array_length: {
655 printGetByIdOp(location, it, identifiers, "get_array_length");
656 break;
657 }
658 case op_get_string_length: {
659 printGetByIdOp(location, it, identifiers, "get_string_length");
660 break;
661 }
662 case op_put_by_id: {
663 printPutByIdOp(location, it, identifiers, "put_by_id");
664 break;
665 }
666 case op_put_by_id_replace: {
667 printPutByIdOp(location, it, identifiers, "put_by_id_replace");
668 break;
669 }
670 case op_put_by_id_transition: {
671 printPutByIdOp(location, it, identifiers, "put_by_id_transition");
672 break;
673 }
674 case op_put_by_id_generic: {
675 printPutByIdOp(location, it, identifiers, "put_by_id_generic");
676 break;
677 }
678 case op_put_getter: {
679 int r0 = (++it)->u.operand;
680 int id0 = (++it)->u.operand;
681 int r1 = (++it)->u.operand;
682 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
683 break;
684 }
685 case op_put_setter: {
686 int r0 = (++it)->u.operand;
687 int id0 = (++it)->u.operand;
688 int r1 = (++it)->u.operand;
689 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
690 break;
691 }
692 case op_del_by_id: {
693 int r0 = (++it)->u.operand;
694 int r1 = (++it)->u.operand;
695 int id0 = (++it)->u.operand;
696 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());
697 break;
698 }
699 case op_get_by_val: {
700 int r0 = (++it)->u.operand;
701 int r1 = (++it)->u.operand;
702 int r2 = (++it)->u.operand;
703 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
704 break;
705 }
706 case op_put_by_val: {
707 int r0 = (++it)->u.operand;
708 int r1 = (++it)->u.operand;
709 int r2 = (++it)->u.operand;
710 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
711 break;
712 }
713 case op_del_by_val: {
714 int r0 = (++it)->u.operand;
715 int r1 = (++it)->u.operand;
716 int r2 = (++it)->u.operand;
717 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
718 break;
719 }
720 case op_put_by_index: {
721 int r0 = (++it)->u.operand;
722 unsigned n0 = (++it)->u.operand;
723 int r1 = (++it)->u.operand;
724 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
725 break;
726 }
727 case op_jmp: {
728 int offset = (++it)->u.operand;
729 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
730 break;
731 }
732 case op_loop: {
733 int offset = (++it)->u.operand;
734 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
735 break;
736 }
737 case op_jtrue: {
738 printConditionalJump(begin, it, location, "jtrue");
739 break;
740 }
741 case op_loop_if_true: {
742 printConditionalJump(begin, it, location, "loop_if_true");
743 break;
744 }
745 case op_jfalse: {
746 printConditionalJump(begin, it, location, "jfalse");
747 break;
748 }
749 case op_jeq_null: {
750 printConditionalJump(begin, it, location, "jeq_null");
751 break;
752 }
753 case op_jneq_null: {
754 printConditionalJump(begin, it, location, "jneq_null");
755 break;
756 }
757 case op_jnless: {
758 int r0 = (++it)->u.operand;
759 int r1 = (++it)->u.operand;
760 int offset = (++it)->u.operand;
761 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
762 break;
763 }
764 case op_loop_if_less: {
765 int r0 = (++it)->u.operand;
766 int r1 = (++it)->u.operand;
767 int offset = (++it)->u.operand;
768 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
769 break;
770 }
771 case op_loop_if_lesseq: {
772 int r0 = (++it)->u.operand;
773 int r1 = (++it)->u.operand;
774 int offset = (++it)->u.operand;
775 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
776 break;
777 }
778 case op_switch_imm: {
779 int tableIndex = (++it)->u.operand;
780 int defaultTarget = (++it)->u.operand;
781 int scrutineeRegister = (++it)->u.operand;
782 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
783 break;
784 }
785 case op_switch_char: {
786 int tableIndex = (++it)->u.operand;
787 int defaultTarget = (++it)->u.operand;
788 int scrutineeRegister = (++it)->u.operand;
789 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
790 break;
791 }
792 case op_switch_string: {
793 int tableIndex = (++it)->u.operand;
794 int defaultTarget = (++it)->u.operand;
795 int scrutineeRegister = (++it)->u.operand;
796 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
797 break;
798 }
799 case op_new_func: {
800 int r0 = (++it)->u.operand;
801 int f0 = (++it)->u.operand;
802 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
803 break;
804 }
805 case op_new_func_exp: {
806 int r0 = (++it)->u.operand;
807 int f0 = (++it)->u.operand;
808 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
809 break;
810 }
811 case op_call: {
812 int r0 = (++it)->u.operand;
813 int r1 = (++it)->u.operand;
814 int r2 = (++it)->u.operand;
815 int tempCount = (++it)->u.operand;
816 int argCount = (++it)->u.operand;
817 int registerOffset = (++it)->u.operand;
818 printf("[%4d] call\t\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
819 break;
820 }
821 case op_call_eval: {
822 int r0 = (++it)->u.operand;
823 int r1 = (++it)->u.operand;
824 int r2 = (++it)->u.operand;
825 int tempCount = (++it)->u.operand;
826 int argCount = (++it)->u.operand;
827 int registerOffset = (++it)->u.operand;
828 printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
829 break;
830 }
831 case op_tear_off_activation: {
832 int r0 = (++it)->u.operand;
833 printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
834 break;
835 }
836 case op_tear_off_arguments: {
837 printf("[%4d] tear_off_arguments\n", location);
838 break;
839 }
840 case op_ret: {
841 int r0 = (++it)->u.operand;
842 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
843 break;
844 }
845 case op_construct: {
846 int r0 = (++it)->u.operand;
847 int r1 = (++it)->u.operand;
848 int r2 = (++it)->u.operand;
849 int tempCount = (++it)->u.operand;
850 int argCount = (++it)->u.operand;
851 int registerOffset = (++it)->u.operand;
852 printf("[%4d] construct\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
853 break;
854 }
855 case op_construct_verify: {
856 int r0 = (++it)->u.operand;
857 int r1 = (++it)->u.operand;
858 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
859 break;
860 }
861 case op_get_pnames: {
862 int r0 = (++it)->u.operand;
863 int r1 = (++it)->u.operand;
864 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
865 break;
866 }
867 case op_next_pname: {
868 int dest = (++it)->u.operand;
869 int iter = (++it)->u.operand;
870 int offset = (++it)->u.operand;
871 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, jumpTarget(begin, it, offset));
872 break;
873 }
874 case op_push_scope: {
875 int r0 = (++it)->u.operand;
876 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
877 break;
878 }
879 case op_pop_scope: {
880 printf("[%4d] pop_scope\n", location);
881 break;
882 }
883 case op_push_new_scope: {
884 int r0 = (++it)->u.operand;
885 int id0 = (++it)->u.operand;
886 int r1 = (++it)->u.operand;
887 printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
888 break;
889 }
890 case op_jmp_scopes: {
891 int scopeDelta = (++it)->u.operand;
892 int offset = (++it)->u.operand;
893 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, jumpTarget(begin, it, offset));
894 break;
895 }
896 case op_catch: {
897 int r0 = (++it)->u.operand;
898 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
899 break;
900 }
901 case op_throw: {
902 int r0 = (++it)->u.operand;
903 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
904 break;
905 }
906 case op_new_error: {
907 int r0 = (++it)->u.operand;
908 int errorType = (++it)->u.operand;
909 int k0 = (++it)->u.operand;
910 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstants[k0]).c_str());
911 break;
912 }
913 case op_jsr: {
914 int retAddrDst = (++it)->u.operand;
915 int offset = (++it)->u.operand;
916 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, jumpTarget(begin, it, offset));
917 break;
918 }
919 case op_sret: {
920 int retAddrSrc = (++it)->u.operand;
921 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
922 break;
923 }
924 case op_debug: {
925 int debugHookID = (++it)->u.operand;
926 int firstLine = (++it)->u.operand;
927 int lastLine = (++it)->u.operand;
928 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
929 break;
930 }
931 case op_profile_will_call: {
932 int function = (++it)->u.operand;
933 printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
934 break;
935 }
936 case op_profile_did_call: {
937 int function = (++it)->u.operand;
938 printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
939 break;
940 }
941 case op_end: {
942 int r0 = (++it)->u.operand;
943 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
944 break;
945 }
946 }
947}
948
949#endif // !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
950
951CodeBlock::~CodeBlock()
952{
953 for (size_t size = globalResolveInstructions.size(), i = 0; i < size; ++i) {
954 derefStructureIDs(&instructions[globalResolveInstructions[i]]);
955 }
956
957 for (size_t size = propertyAccessInstructions.size(), i = 0; i < size; ++i) {
958 derefStructureIDs(&instructions[propertyAccessInstructions[i].opcodeIndex]);
959 if (propertyAccessInstructions[i].stubRoutine)
960 WTF::fastFreeExecutable(propertyAccessInstructions[i].stubRoutine);
961 }
962
963 for (size_t size = callLinkInfos.size(), i = 0; i < size; ++i) {
964 CallLinkInfo* callLinkInfo = &callLinkInfos[i];
965 if (callLinkInfo->isLinked())
966 callLinkInfo->callee->removeCaller(callLinkInfo);
967 }
968
969#if ENABLE(CTI)
970 unlinkCallers();
971
972 if (ctiCode)
973 WTF::fastFreeExecutable(ctiCode);
974#endif
975}
976
977#if ENABLE(CTI)
978void CodeBlock::unlinkCallers()
979{
980 size_t size = linkedCallerList.size();
981 for (size_t i = 0; i < size; ++i) {
982 CallLinkInfo* currentCaller = linkedCallerList[i];
983 CTI::unlinkCall(currentCaller);
984 currentCaller->setUnlinked();
985 }
986 linkedCallerList.clear();
987}
988#endif
989
990void CodeBlock::derefStructureIDs(Instruction* vPC) const
991{
992 Machine* machine = globalData->machine;
993
994 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
995 vPC[4].u.structureID->deref();
996 return;
997 }
998 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
999 vPC[4].u.structureID->deref();
1000 vPC[5].u.structureID->deref();
1001 return;
1002 }
1003 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
1004 vPC[4].u.structureID->deref();
1005 vPC[5].u.structureIDChain->deref();
1006 return;
1007 }
1008 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
1009 vPC[4].u.structureID->deref();
1010 vPC[5].u.structureID->deref();
1011 vPC[6].u.structureIDChain->deref();
1012 return;
1013 }
1014 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
1015 vPC[4].u.structureID->deref();
1016 return;
1017 }
1018 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
1019 if(vPC[4].u.structureID)
1020 vPC[4].u.structureID->deref();
1021 return;
1022 }
1023
1024 // These instructions don't ref their StructureIDs.
1025 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_get_array_length) || vPC[0].u.opcode == machine->getOpcode(op_get_string_length));
1026}
1027
1028void CodeBlock::refStructureIDs(Instruction* vPC) const
1029{
1030 Machine* machine = globalData->machine;
1031
1032 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
1033 vPC[4].u.structureID->ref();
1034 return;
1035 }
1036 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
1037 vPC[4].u.structureID->ref();
1038 vPC[5].u.structureID->ref();
1039 return;
1040 }
1041 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
1042 vPC[4].u.structureID->ref();
1043 vPC[5].u.structureIDChain->ref();
1044 return;
1045 }
1046 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
1047 vPC[4].u.structureID->ref();
1048 vPC[5].u.structureID->ref();
1049 vPC[6].u.structureIDChain->ref();
1050 return;
1051 }
1052 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
1053 vPC[4].u.structureID->ref();
1054 return;
1055 }
1056
1057 // These instructions don't ref their StructureIDs.
1058 ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic));
1059}
1060
1061void CodeBlock::mark()
1062{
1063 for (size_t i = 0; i < constantRegisters.size(); ++i)
1064 if (!constantRegisters[i].marked())
1065 constantRegisters[i].mark();
1066
1067 for (size_t i = 0; i < unexpectedConstants.size(); ++i)
1068 if (!unexpectedConstants[i]->marked())
1069 unexpectedConstants[i]->mark();
1070
1071 for (size_t i = 0; i < functions.size(); ++i)
1072 functions[i]->body()->mark();
1073
1074 for (size_t i = 0; i < functionExpressions.size(); ++i)
1075 functionExpressions[i]->body()->mark();
1076}
1077
1078bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth)
1079{
1080 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1081 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1082 unsigned addressOffset = vPC - instructions.begin();
1083 ASSERT(addressOffset < instructions.size());
1084
1085 for (; ptr != end; ++ptr) {
1086 // Handlers are ordered innermost first, so the first handler we encounter
1087 // that contains the source address is the correct handler to use.
1088 if (ptr->start <= addressOffset && ptr->end >= addressOffset) {
1089 scopeDepth = ptr->scopeDepth;
1090 target = instructions.begin() + ptr->target;
1091 return true;
1092 }
1093 }
1094 return false;
1095}
1096
1097void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
1098{
1099 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1100 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1101
1102 for (; ptr != end; ++ptr) {
1103 Instruction*target = instructions.begin() + ptr->target;
1104 if (handlerVPC == target)
1105 return ptr->nativeCode;
1106 }
1107
1108 return 0;
1109}
1110
1111int CodeBlock::lineNumberForVPC(const Instruction* vPC)
1112{
1113 ASSERT(lineInfo.size());
1114 unsigned instructionOffset = vPC - instructions.begin();
1115 ASSERT(instructionOffset < instructions.size());
1116
1117 if (!lineInfo.size())
1118 return 1; // Empty function
1119
1120 int low = 0;
1121 int high = lineInfo.size();
1122 while (low < high) {
1123 int mid = low + (high - low) / 2;
1124 if (lineInfo[mid].instructionOffset <= instructionOffset)
1125 low = mid + 1;
1126 else
1127 high = mid;
1128 }
1129 return lineInfo[low - 1].lineNumber;
1130}
1131
1132int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
1133{
1134 unsigned instructionOffset = vPC - instructions.begin();
1135 ASSERT(instructionOffset < instructions.size());
1136
1137 if (!expressionInfo.size()) {
1138 // We didn't think anything could throw. Apparently we were wrong.
1139 startOffset = 0;
1140 endOffset = 0;
1141 divot = 0;
1142 return lineNumberForVPC(vPC);
1143 }
1144
1145 int low = 0;
1146 int high = expressionInfo.size();
1147 while (low < high) {
1148 int mid = low + (high - low) / 2;
1149 if (expressionInfo[mid].instructionOffset <= instructionOffset)
1150 low = mid + 1;
1151 else
1152 high = mid;
1153 }
1154
1155 ASSERT(low);
1156 if (!low) {
1157 startOffset = 0;
1158 endOffset = 0;
1159 divot = 0;
1160 return lineNumberForVPC(vPC);
1161 }
1162
1163 startOffset = expressionInfo[low - 1].startOffset;
1164 endOffset = expressionInfo[low - 1].endOffset;
1165 divot = expressionInfo[low - 1].divotPoint + sourceOffset;
1166 return lineNumberForVPC(vPC);
1167}
1168
1169int32_t SimpleJumpTable::offsetForValue(int32_t value, int32_t defaultOffset)
1170{
1171 if (value >= min && static_cast<uint32_t>(value - min) < branchOffsets.size()) {
1172 int32_t offset = branchOffsets[value - min];
1173 if (offset)
1174 return offset;
1175 }
1176 return defaultOffset;
1177}
1178
1179} // namespace JSC
Note: See TracBrowser for help on using the repository browser.