source: webkit/trunk/JavaScriptCore/bytecode/CodeBlock.cpp@ 38652

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

2008-11-19 Gavin Barraclough <[email protected]>

Reviewed by Darin Adler.

Add support for (really) polymorphic caching of prototype accesses.


If a cached prototype access misses, cti_op_get_by_id_proto_list is called.
When this occurs the Structure pointers from the instruction stream are copied
off into a new ProtoStubInfo object. A second prototype access trampoline is
generated, and chained onto the first. Subsequent missed call to
cti_op_get_by_id_proto_list_append, which append futher new trampolines, up to
PROTOTYPE_LIST_CACHE_SIZE (currently 4). If any of the misses result in an
access other than to a direct prototype property, list formation is halted (or
for the initial miss, does not take place at all).

Separate fail case functions are provided for each access since this contributes
to the performance progression (enables better processor branch prediction).

Overall this is a near 5% progression on v8, with around 10% wins on richards
and deltablue.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures):
  • bytecode/Instruction.h: (JSC::ProtoStructureList::ProtoStubInfo::set): (JSC::ProtoStructureList::ProtoStructureList): (JSC::Instruction::Instruction): (JSC::Instruction::):
  • bytecode/Opcode.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): (JSC::Interpreter::tryCTICacheGetByID): (JSC::Interpreter::cti_op_put_by_id_fail): (JSC::Interpreter::cti_op_get_by_id_self_fail): (JSC::Interpreter::cti_op_get_by_id_proto_list): (JSC::Interpreter::cti_op_get_by_id_proto_list_append): (JSC::Interpreter::cti_op_get_by_id_proto_list_full): (JSC::Interpreter::cti_op_get_by_id_proto_fail): (JSC::Interpreter::cti_op_get_by_id_chain_fail): (JSC::Interpreter::cti_op_get_by_id_array_fail): (JSC::Interpreter::cti_op_get_by_id_string_fail):
  • interpreter/Interpreter.h:
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileGetByIdSelf): (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChain): (JSC::JIT::privateCompileCTIMachineTrampolines): (JSC::JIT::privateCompilePatchGetArrayLength):
  • jit/JIT.h: (JSC::JIT::compileGetByIdProtoList):
File size: 44.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 "JIT.h"
34#include "JSValue.h"
35#include "Interpreter.h"
36#include "Debugger.h"
37#include <stdio.h>
38#include <wtf/StringExtras.h>
39
40namespace JSC {
41
42#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
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, JSValue* 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, JSValue* 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::printStructure(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.structure).UTF8String().c_str());
180}
181
182void CodeBlock::printStructures(const Instruction* vPC) const
183{
184 Interpreter* interpreter = globalData->interpreter;
185 unsigned instructionOffset = vPC - instructions.begin();
186
187 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
188 printStructure("get_by_id", vPC, 4);
189 return;
190 }
191 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
192 printStructure("get_by_id_self", vPC, 4);
193 return;
194 }
195 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
196 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str());
197 return;
198 }
199 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
200 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_new", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().c_str());
201 return;
202 }
203 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
204 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureChain).UTF8String().c_str());
205 return;
206 }
207 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
208 printStructure("put_by_id", vPC, 4);
209 return;
210 }
211 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
212 printStructure("put_by_id_replace", vPC, 4);
213 return;
214 }
215 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
216 printStructure("resolve_global", vPC, 4);
217 return;
218 }
219
220 // These instructions doesn't ref Structures.
221 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->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->interpreter()->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 unsigned registerIndex = numVars;
254 size_t i = 0;
255 do {
256 printf(" r%u = %s\n", registerIndex, valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
257 ++i;
258 ++registerIndex;
259 } while (i < constantRegisters.size());
260 }
261
262 if (unexpectedConstants.size()) {
263 printf("\nUnexpected Constants:\n");
264 size_t i = 0;
265 do {
266 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, unexpectedConstants[i]).ascii());
267 ++i;
268 } while (i < unexpectedConstants.size());
269 }
270
271 if (regexps.size()) {
272 printf("\nRegExps:\n");
273 size_t i = 0;
274 do {
275 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(regexps[i].get()).ascii());
276 ++i;
277 } while (i < regexps.size());
278 }
279
280 if (globalResolveInstructions.size() || propertyAccessInstructions.size())
281 printf("\nStructures:\n");
282
283 if (globalResolveInstructions.size()) {
284 size_t i = 0;
285 do {
286 printStructures(&instructions[globalResolveInstructions[i]]);
287 ++i;
288 } while (i < globalResolveInstructions.size());
289 }
290 if (propertyAccessInstructions.size()) {
291 size_t i = 0;
292 do {
293 printStructures(&instructions[propertyAccessInstructions[i].bytecodeIndex]);
294 ++i;
295 } while (i < propertyAccessInstructions.size());
296 }
297
298 if (exceptionHandlers.size()) {
299 printf("\nException Handlers:\n");
300 unsigned i = 0;
301 do {
302 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
303 ++i;
304 } while (i < exceptionHandlers.size());
305 }
306
307 if (immediateSwitchJumpTables.size()) {
308 printf("Immediate Switch Jump Tables:\n");
309 unsigned i = 0;
310 do {
311 printf(" %1d = {\n", i);
312 int entry = 0;
313 Vector<int32_t>::const_iterator end = immediateSwitchJumpTables[i].branchOffsets.end();
314 for (Vector<int32_t>::const_iterator iter = immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
315 if (!*iter)
316 continue;
317 printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
318 }
319 printf(" }\n");
320 ++i;
321 } while (i < immediateSwitchJumpTables.size());
322 }
323
324 if (characterSwitchJumpTables.size()) {
325 printf("\nCharacter Switch Jump Tables:\n");
326 unsigned i = 0;
327 do {
328 printf(" %1d = {\n", i);
329 int entry = 0;
330 Vector<int32_t>::const_iterator end = characterSwitchJumpTables[i].branchOffsets.end();
331 for (Vector<int32_t>::const_iterator iter = characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
332 if (!*iter)
333 continue;
334 ASSERT(!((i + characterSwitchJumpTables[i].min) & ~0xFFFF));
335 UChar ch = static_cast<UChar>(entry + characterSwitchJumpTables[i].min);
336 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
337 }
338 printf(" }\n");
339 ++i;
340 } while (i < characterSwitchJumpTables.size());
341 }
342
343 if (stringSwitchJumpTables.size()) {
344 printf("\nString Switch Jump Tables:\n");
345 unsigned i = 0;
346 do {
347 printf(" %1d = {\n", i);
348 StringJumpTable::StringOffsetTable::const_iterator end = stringSwitchJumpTables[i].offsetTable.end();
349 for (StringJumpTable::StringOffsetTable::const_iterator iter = stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
350 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
351 printf(" }\n");
352 ++i;
353 } while (i < stringSwitchJumpTables.size());
354 }
355
356 printf("\n");
357}
358
359void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
360{
361 int location = it - begin;
362 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
363 case op_enter: {
364 printf("[%4d] enter\n", location);
365 break;
366 }
367 case op_enter_with_activation: {
368 int r0 = (++it)->u.operand;
369 printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str());
370 break;
371 }
372 case op_create_arguments: {
373 printf("[%4d] create_arguments\n", location);
374 break;
375 }
376 case op_convert_this: {
377 int r0 = (++it)->u.operand;
378 printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
379 break;
380 }
381 case op_unexpected_load: {
382 int r0 = (++it)->u.operand;
383 int k0 = (++it)->u.operand;
384 printf("[%4d] unexpected_load\t %s, %s\n", location, registerName(r0).c_str(), constantName(exec, k0, unexpectedConstants[k0]).c_str());
385 break;
386 }
387 case op_new_object: {
388 int r0 = (++it)->u.operand;
389 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
390 break;
391 }
392 case op_new_array: {
393 int dst = (++it)->u.operand;
394 int argv = (++it)->u.operand;
395 int argc = (++it)->u.operand;
396 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
397 break;
398 }
399 case op_new_regexp: {
400 int r0 = (++it)->u.operand;
401 int re0 = (++it)->u.operand;
402 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexps[re0].get()).c_str());
403 break;
404 }
405 case op_mov: {
406 int r0 = (++it)->u.operand;
407 int r1 = (++it)->u.operand;
408 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
409 break;
410 }
411 case op_not: {
412 printUnaryOp(location, it, "not");
413 break;
414 }
415 case op_eq: {
416 printBinaryOp(location, it, "eq");
417 break;
418 }
419 case op_eq_null: {
420 printUnaryOp(location, it, "eq_null");
421 break;
422 }
423 case op_neq: {
424 printBinaryOp(location, it, "neq");
425 break;
426 }
427 case op_neq_null: {
428 printUnaryOp(location, it, "neq_null");
429 break;
430 }
431 case op_stricteq: {
432 printBinaryOp(location, it, "stricteq");
433 break;
434 }
435 case op_nstricteq: {
436 printBinaryOp(location, it, "nstricteq");
437 break;
438 }
439 case op_less: {
440 printBinaryOp(location, it, "less");
441 break;
442 }
443 case op_lesseq: {
444 printBinaryOp(location, it, "lesseq");
445 break;
446 }
447 case op_pre_inc: {
448 int r0 = (++it)->u.operand;
449 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
450 break;
451 }
452 case op_pre_dec: {
453 int r0 = (++it)->u.operand;
454 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
455 break;
456 }
457 case op_post_inc: {
458 printUnaryOp(location, it, "post_inc");
459 break;
460 }
461 case op_post_dec: {
462 printUnaryOp(location, it, "post_dec");
463 break;
464 }
465 case op_to_jsnumber: {
466 printUnaryOp(location, it, "to_jsnumber");
467 break;
468 }
469 case op_negate: {
470 printUnaryOp(location, it, "negate");
471 ++it;
472 break;
473 }
474 case op_add: {
475 printBinaryOp(location, it, "add");
476 ++it;
477 break;
478 }
479 case op_mul: {
480 printBinaryOp(location, it, "mul");
481 ++it;
482 break;
483 }
484 case op_div: {
485 printBinaryOp(location, it, "div");
486 break;
487 }
488 case op_mod: {
489 printBinaryOp(location, it, "mod");
490 break;
491 }
492 case op_sub: {
493 printBinaryOp(location, it, "sub");
494 ++it;
495 break;
496 }
497 case op_lshift: {
498 printBinaryOp(location, it, "lshift");
499 break;
500 }
501 case op_rshift: {
502 printBinaryOp(location, it, "rshift");
503 break;
504 }
505 case op_urshift: {
506 printBinaryOp(location, it, "urshift");
507 break;
508 }
509 case op_bitand: {
510 printBinaryOp(location, it, "bitand");
511 ++it;
512 break;
513 }
514 case op_bitxor: {
515 printBinaryOp(location, it, "bitxor");
516 ++it;
517 break;
518 }
519 case op_bitor: {
520 printBinaryOp(location, it, "bitor");
521 ++it;
522 break;
523 }
524 case op_bitnot: {
525 printUnaryOp(location, it, "bitnot");
526 break;
527 }
528 case op_instanceof: {
529 int r0 = (++it)->u.operand;
530 int r1 = (++it)->u.operand;
531 int r2 = (++it)->u.operand;
532 int r3 = (++it)->u.operand;
533 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());
534 break;
535 }
536 case op_typeof: {
537 printUnaryOp(location, it, "typeof");
538 break;
539 }
540 case op_is_undefined: {
541 printUnaryOp(location, it, "is_undefined");
542 break;
543 }
544 case op_is_boolean: {
545 printUnaryOp(location, it, "is_boolean");
546 break;
547 }
548 case op_is_number: {
549 printUnaryOp(location, it, "is_number");
550 break;
551 }
552 case op_is_string: {
553 printUnaryOp(location, it, "is_string");
554 break;
555 }
556 case op_is_object: {
557 printUnaryOp(location, it, "is_object");
558 break;
559 }
560 case op_is_function: {
561 printUnaryOp(location, it, "is_function");
562 break;
563 }
564 case op_in: {
565 printBinaryOp(location, it, "in");
566 break;
567 }
568 case op_resolve: {
569 int r0 = (++it)->u.operand;
570 int id0 = (++it)->u.operand;
571 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
572 break;
573 }
574 case op_resolve_skip: {
575 int r0 = (++it)->u.operand;
576 int id0 = (++it)->u.operand;
577 int skipLevels = (++it)->u.operand;
578 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), skipLevels);
579 break;
580 }
581 case op_resolve_global: {
582 int r0 = (++it)->u.operand;
583 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
584 int id0 = (++it)->u.operand;
585 printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, identifiers[id0]).c_str());
586 it += 2;
587 break;
588 }
589 case op_get_scoped_var: {
590 int r0 = (++it)->u.operand;
591 int index = (++it)->u.operand;
592 int skipLevels = (++it)->u.operand;
593 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
594 break;
595 }
596 case op_put_scoped_var: {
597 int index = (++it)->u.operand;
598 int skipLevels = (++it)->u.operand;
599 int r0 = (++it)->u.operand;
600 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
601 break;
602 }
603 case op_get_global_var: {
604 int r0 = (++it)->u.operand;
605 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
606 int index = (++it)->u.operand;
607 printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
608 break;
609 }
610 case op_put_global_var: {
611 JSValue* scope = static_cast<JSValue*>((++it)->u.jsCell);
612 int index = (++it)->u.operand;
613 int r0 = (++it)->u.operand;
614 printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
615 break;
616 }
617 case op_resolve_base: {
618 int r0 = (++it)->u.operand;
619 int id0 = (++it)->u.operand;
620 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str());
621 break;
622 }
623 case op_resolve_with_base: {
624 int r0 = (++it)->u.operand;
625 int r1 = (++it)->u.operand;
626 int id0 = (++it)->u.operand;
627 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
628 break;
629 }
630 case op_resolve_func: {
631 int r0 = (++it)->u.operand;
632 int r1 = (++it)->u.operand;
633 int id0 = (++it)->u.operand;
634 printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, identifiers[id0]).c_str());
635 break;
636 }
637 case op_get_by_id: {
638 printGetByIdOp(location, it, identifiers, "get_by_id");
639 break;
640 }
641 case op_get_by_id_self: {
642 printGetByIdOp(location, it, identifiers, "get_by_id_self");
643 break;
644 }
645 case op_get_by_id_proto: {
646 printGetByIdOp(location, it, identifiers, "get_by_id_proto");
647 break;
648 }
649 case op_get_by_id_proto_list: {
650 printGetByIdOp(location, it, identifiers, "op_get_by_id_proto_list");
651 break;
652 }
653 case op_get_by_id_chain: {
654 printGetByIdOp(location, it, identifiers, "get_by_id_chain");
655 break;
656 }
657 case op_get_by_id_generic: {
658 printGetByIdOp(location, it, identifiers, "get_by_id_generic");
659 break;
660 }
661 case op_get_array_length: {
662 printGetByIdOp(location, it, identifiers, "get_array_length");
663 break;
664 }
665 case op_get_string_length: {
666 printGetByIdOp(location, it, identifiers, "get_string_length");
667 break;
668 }
669 case op_put_by_id: {
670 printPutByIdOp(location, it, identifiers, "put_by_id");
671 break;
672 }
673 case op_put_by_id_replace: {
674 printPutByIdOp(location, it, identifiers, "put_by_id_replace");
675 break;
676 }
677 case op_put_by_id_transition: {
678 printPutByIdOp(location, it, identifiers, "put_by_id_transition");
679 break;
680 }
681 case op_put_by_id_generic: {
682 printPutByIdOp(location, it, identifiers, "put_by_id_generic");
683 break;
684 }
685 case op_put_getter: {
686 int r0 = (++it)->u.operand;
687 int id0 = (++it)->u.operand;
688 int r1 = (++it)->u.operand;
689 printf("[%4d] put_getter\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_put_setter: {
693 int r0 = (++it)->u.operand;
694 int id0 = (++it)->u.operand;
695 int r1 = (++it)->u.operand;
696 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, identifiers[id0]).c_str(), registerName(r1).c_str());
697 break;
698 }
699 case op_del_by_id: {
700 int r0 = (++it)->u.operand;
701 int r1 = (++it)->u.operand;
702 int id0 = (++it)->u.operand;
703 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());
704 break;
705 }
706 case op_get_by_val: {
707 int r0 = (++it)->u.operand;
708 int r1 = (++it)->u.operand;
709 int r2 = (++it)->u.operand;
710 printf("[%4d] get_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_put_by_val: {
714 int r0 = (++it)->u.operand;
715 int r1 = (++it)->u.operand;
716 int r2 = (++it)->u.operand;
717 printf("[%4d] put_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_del_by_val: {
721 int r0 = (++it)->u.operand;
722 int r1 = (++it)->u.operand;
723 int r2 = (++it)->u.operand;
724 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
725 break;
726 }
727 case op_put_by_index: {
728 int r0 = (++it)->u.operand;
729 unsigned n0 = (++it)->u.operand;
730 int r1 = (++it)->u.operand;
731 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
732 break;
733 }
734 case op_jmp: {
735 int offset = (++it)->u.operand;
736 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
737 break;
738 }
739 case op_loop: {
740 int offset = (++it)->u.operand;
741 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
742 break;
743 }
744 case op_jtrue: {
745 printConditionalJump(begin, it, location, "jtrue");
746 break;
747 }
748 case op_loop_if_true: {
749 printConditionalJump(begin, it, location, "loop_if_true");
750 break;
751 }
752 case op_jfalse: {
753 printConditionalJump(begin, it, location, "jfalse");
754 break;
755 }
756 case op_jeq_null: {
757 printConditionalJump(begin, it, location, "jeq_null");
758 break;
759 }
760 case op_jneq_null: {
761 printConditionalJump(begin, it, location, "jneq_null");
762 break;
763 }
764 case op_jnless: {
765 int r0 = (++it)->u.operand;
766 int r1 = (++it)->u.operand;
767 int offset = (++it)->u.operand;
768 printf("[%4d] jnless\t\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_less: {
772 int r0 = (++it)->u.operand;
773 int r1 = (++it)->u.operand;
774 int offset = (++it)->u.operand;
775 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));
776 break;
777 }
778 case op_loop_if_lesseq: {
779 int r0 = (++it)->u.operand;
780 int r1 = (++it)->u.operand;
781 int offset = (++it)->u.operand;
782 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));
783 break;
784 }
785 case op_switch_imm: {
786 int tableIndex = (++it)->u.operand;
787 int defaultTarget = (++it)->u.operand;
788 int scrutineeRegister = (++it)->u.operand;
789 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
790 break;
791 }
792 case op_switch_char: {
793 int tableIndex = (++it)->u.operand;
794 int defaultTarget = (++it)->u.operand;
795 int scrutineeRegister = (++it)->u.operand;
796 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
797 break;
798 }
799 case op_switch_string: {
800 int tableIndex = (++it)->u.operand;
801 int defaultTarget = (++it)->u.operand;
802 int scrutineeRegister = (++it)->u.operand;
803 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
804 break;
805 }
806 case op_new_func: {
807 int r0 = (++it)->u.operand;
808 int f0 = (++it)->u.operand;
809 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
810 break;
811 }
812 case op_new_func_exp: {
813 int r0 = (++it)->u.operand;
814 int f0 = (++it)->u.operand;
815 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
816 break;
817 }
818 case op_call: {
819 int dst = (++it)->u.operand;
820 int func = (++it)->u.operand;
821 int argCount = (++it)->u.operand;
822 int registerOffset = (++it)->u.operand;
823 printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
824 break;
825 }
826 case op_call_eval: {
827 int dst = (++it)->u.operand;
828 int func = (++it)->u.operand;
829 int argCount = (++it)->u.operand;
830 int registerOffset = (++it)->u.operand;
831 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
832 break;
833 }
834 case op_tear_off_activation: {
835 int r0 = (++it)->u.operand;
836 printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
837 break;
838 }
839 case op_tear_off_arguments: {
840 printf("[%4d] tear_off_arguments\n", location);
841 break;
842 }
843 case op_ret: {
844 int r0 = (++it)->u.operand;
845 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
846 break;
847 }
848 case op_construct: {
849 int dst = (++it)->u.operand;
850 int func = (++it)->u.operand;
851 int argCount = (++it)->u.operand;
852 int registerOffset = (++it)->u.operand;
853 int proto = (++it)->u.operand;
854 int thisRegister = (++it)->u.operand;
855 printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset, registerName(proto).c_str(), registerName(thisRegister).c_str());
856 break;
857 }
858 case op_construct_verify: {
859 int r0 = (++it)->u.operand;
860 int r1 = (++it)->u.operand;
861 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
862 break;
863 }
864 case op_get_pnames: {
865 int r0 = (++it)->u.operand;
866 int r1 = (++it)->u.operand;
867 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
868 break;
869 }
870 case op_next_pname: {
871 int dest = (++it)->u.operand;
872 int iter = (++it)->u.operand;
873 int offset = (++it)->u.operand;
874 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, jumpTarget(begin, it, offset));
875 break;
876 }
877 case op_push_scope: {
878 int r0 = (++it)->u.operand;
879 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
880 break;
881 }
882 case op_pop_scope: {
883 printf("[%4d] pop_scope\n", location);
884 break;
885 }
886 case op_push_new_scope: {
887 int r0 = (++it)->u.operand;
888 int id0 = (++it)->u.operand;
889 int r1 = (++it)->u.operand;
890 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());
891 break;
892 }
893 case op_jmp_scopes: {
894 int scopeDelta = (++it)->u.operand;
895 int offset = (++it)->u.operand;
896 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, jumpTarget(begin, it, offset));
897 break;
898 }
899 case op_catch: {
900 int r0 = (++it)->u.operand;
901 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
902 break;
903 }
904 case op_throw: {
905 int r0 = (++it)->u.operand;
906 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
907 break;
908 }
909 case op_new_error: {
910 int r0 = (++it)->u.operand;
911 int errorType = (++it)->u.operand;
912 int k0 = (++it)->u.operand;
913 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstants[k0]).c_str());
914 break;
915 }
916 case op_jsr: {
917 int retAddrDst = (++it)->u.operand;
918 int offset = (++it)->u.operand;
919 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, jumpTarget(begin, it, offset));
920 break;
921 }
922 case op_sret: {
923 int retAddrSrc = (++it)->u.operand;
924 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
925 break;
926 }
927 case op_debug: {
928 int debugHookID = (++it)->u.operand;
929 int firstLine = (++it)->u.operand;
930 int lastLine = (++it)->u.operand;
931 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
932 break;
933 }
934 case op_profile_will_call: {
935 int function = (++it)->u.operand;
936 printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
937 break;
938 }
939 case op_profile_did_call: {
940 int function = (++it)->u.operand;
941 printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
942 break;
943 }
944 case op_end: {
945 int r0 = (++it)->u.operand;
946 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
947 break;
948 }
949 }
950}
951
952#endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
953
954CodeBlock::~CodeBlock()
955{
956 for (size_t size = globalResolveInstructions.size(), i = 0; i < size; ++i) {
957 derefStructures(&instructions[globalResolveInstructions[i]]);
958 }
959
960 for (size_t size = propertyAccessInstructions.size(), i = 0; i < size; ++i) {
961 derefStructures(&instructions[propertyAccessInstructions[i].bytecodeIndex]);
962 if (propertyAccessInstructions[i].stubRoutine)
963 WTF::fastFreeExecutable(propertyAccessInstructions[i].stubRoutine);
964 }
965
966 for (size_t size = callLinkInfos.size(), i = 0; i < size; ++i) {
967 CallLinkInfo* callLinkInfo = &callLinkInfos[i];
968 if (callLinkInfo->isLinked())
969 callLinkInfo->callee->removeCaller(callLinkInfo);
970 }
971
972#if ENABLE(JIT)
973 unlinkCallers();
974
975 if (ctiCode)
976 WTF::fastFreeExecutable(ctiCode);
977#endif
978}
979
980#if ENABLE(JIT)
981void CodeBlock::unlinkCallers()
982{
983 size_t size = linkedCallerList.size();
984 for (size_t i = 0; i < size; ++i) {
985 CallLinkInfo* currentCaller = linkedCallerList[i];
986 JIT::unlinkCall(currentCaller);
987 currentCaller->setUnlinked();
988 }
989 linkedCallerList.clear();
990}
991#endif
992
993void CodeBlock::derefStructures(Instruction* vPC) const
994{
995 Interpreter* interpreter = globalData->interpreter;
996
997 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
998 vPC[4].u.structure->deref();
999 return;
1000 }
1001 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1002 vPC[4].u.structure->deref();
1003 vPC[5].u.structure->deref();
1004 return;
1005 }
1006 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1007 vPC[4].u.structure->deref();
1008 vPC[5].u.structureChain->deref();
1009 return;
1010 }
1011 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1012 vPC[4].u.structure->deref();
1013 vPC[5].u.structure->deref();
1014 vPC[6].u.structureChain->deref();
1015 return;
1016 }
1017 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1018 vPC[4].u.structure->deref();
1019 return;
1020 }
1021 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
1022 if(vPC[4].u.structure)
1023 vPC[4].u.structure->deref();
1024 return;
1025 }
1026 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list)) {
1027 PrototypeStructureList* prototypeStructures = vPC[4].u.prototypeStructure;
1028 int count = vPC[5].u.operand;
1029 for (int i = 0; i < count; ++i) {
1030 PrototypeStructureList::ProtoStubInfo& info = prototypeStructures->list[i];
1031 ASSERT(info.base);
1032 ASSERT(info.proto);
1033 ASSERT(info.stubRoutine);
1034 info.base->deref();
1035 info.proto->deref();
1036 WTF::fastFreeExecutable(info.stubRoutine);
1037 }
1038 return;
1039 }
1040
1041 // These instructions don't ref their Structures.
1042 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
1043}
1044
1045void CodeBlock::refStructures(Instruction* vPC) const
1046{
1047 Interpreter* interpreter = globalData->interpreter;
1048
1049 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1050 vPC[4].u.structure->ref();
1051 return;
1052 }
1053 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1054 vPC[4].u.structure->ref();
1055 vPC[5].u.structure->ref();
1056 return;
1057 }
1058 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1059 vPC[4].u.structure->ref();
1060 vPC[5].u.structureChain->ref();
1061 return;
1062 }
1063 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1064 vPC[4].u.structure->ref();
1065 vPC[5].u.structure->ref();
1066 vPC[6].u.structureChain->ref();
1067 return;
1068 }
1069 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1070 vPC[4].u.structure->ref();
1071 return;
1072 }
1073
1074 // These instructions don't ref their Structures.
1075 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic));
1076}
1077
1078void CodeBlock::mark()
1079{
1080 for (size_t i = 0; i < constantRegisters.size(); ++i)
1081 if (!constantRegisters[i].marked())
1082 constantRegisters[i].mark();
1083
1084 for (size_t i = 0; i < unexpectedConstants.size(); ++i)
1085 if (!unexpectedConstants[i]->marked())
1086 unexpectedConstants[i]->mark();
1087
1088 for (size_t i = 0; i < functions.size(); ++i)
1089 functions[i]->body()->mark();
1090
1091 for (size_t i = 0; i < functionExpressions.size(); ++i)
1092 functionExpressions[i]->body()->mark();
1093}
1094
1095bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth)
1096{
1097 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1098 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1099 unsigned addressOffset = vPC - instructions.begin();
1100 ASSERT(addressOffset < instructions.size());
1101
1102 for (; ptr != end; ++ptr) {
1103 // Handlers are ordered innermost first, so the first handler we encounter
1104 // that contains the source address is the correct handler to use.
1105 if (ptr->start <= addressOffset && ptr->end >= addressOffset) {
1106 scopeDepth = ptr->scopeDepth;
1107 target = instructions.begin() + ptr->target;
1108 return true;
1109 }
1110 }
1111 return false;
1112}
1113
1114void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
1115{
1116 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1117 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1118
1119 for (; ptr != end; ++ptr) {
1120 Instruction*target = instructions.begin() + ptr->target;
1121 if (handlerVPC == target)
1122 return ptr->nativeCode;
1123 }
1124
1125 return 0;
1126}
1127
1128int CodeBlock::lineNumberForVPC(const Instruction* vPC)
1129{
1130 unsigned instructionOffset = vPC - instructions.begin();
1131 ASSERT(instructionOffset < instructions.size());
1132
1133 if (!lineInfo.size())
1134 return ownerNode->source().firstLine(); // Empty function
1135
1136 int low = 0;
1137 int high = lineInfo.size();
1138 while (low < high) {
1139 int mid = low + (high - low) / 2;
1140 if (lineInfo[mid].instructionOffset <= instructionOffset)
1141 low = mid + 1;
1142 else
1143 high = mid;
1144 }
1145
1146 if (!low)
1147 return ownerNode->source().firstLine();
1148 return lineInfo[low - 1].lineNumber;
1149}
1150
1151int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
1152{
1153 unsigned instructionOffset = vPC - instructions.begin();
1154 ASSERT(instructionOffset < instructions.size());
1155
1156 if (!expressionInfo.size()) {
1157 // We didn't think anything could throw. Apparently we were wrong.
1158 startOffset = 0;
1159 endOffset = 0;
1160 divot = 0;
1161 return lineNumberForVPC(vPC);
1162 }
1163
1164 int low = 0;
1165 int high = expressionInfo.size();
1166 while (low < high) {
1167 int mid = low + (high - low) / 2;
1168 if (expressionInfo[mid].instructionOffset <= instructionOffset)
1169 low = mid + 1;
1170 else
1171 high = mid;
1172 }
1173
1174 ASSERT(low);
1175 if (!low) {
1176 startOffset = 0;
1177 endOffset = 0;
1178 divot = 0;
1179 return lineNumberForVPC(vPC);
1180 }
1181
1182 startOffset = expressionInfo[low - 1].startOffset;
1183 endOffset = expressionInfo[low - 1].endOffset;
1184 divot = expressionInfo[low - 1].divotPoint + sourceOffset;
1185 return lineNumberForVPC(vPC);
1186}
1187
1188int32_t SimpleJumpTable::offsetForValue(int32_t value, int32_t defaultOffset)
1189{
1190 if (value >= min && static_cast<uint32_t>(value - min) < branchOffsets.size()) {
1191 int32_t offset = branchOffsets[value - min];
1192 if (offset)
1193 return offset;
1194 }
1195 return defaultOffset;
1196}
1197
1198} // namespace JSC
Note: See TracBrowser for help on using the repository browser.