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

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

JavaScriptCore:

2008-10-20 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.


Fixed https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

22.2% speedup on empty function call benchmark.
2.9% speedup on v8 benchmark.
0.7% speedup on SunSpider.


Lesser but similar speedups in bytecode.

  • VM/CTI.cpp: (JSC::CTI::compileOpCall): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileSlowCases): Nixed JITed profiler hooks. Profiler hooks now have their own opcodes. Added support for compiling profiler hook opcodes.


(JSC::CodeBlock::dump): Dump support for the new profiling opcodes.

  • VM/CodeGenerator.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::CodeGenerator): (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct): Conditionally emit profiling hooks around call and construct, at the call site. (It's easier to get things right this way, if you have profiled code calling non-profiled code. Also, you get a slightly more accurate profile, since you charge the full cost of the call / construct operation to the callee.)


Also, fixed a bug where construct would fetch the ".prototype" property
from the constructor before evaluating the arguments to the constructor,
incorrectly allowing an "invalid constructor" exception to short-circuit
argument evaluation. I encountered this bug when trying to make
constructor exceptions work with profiling.

  • VM/Machine.cpp: (JSC::Machine::callEval): Removed obsolete profiler hooks.

(JSC::Machine::throwException): Added a check for an exception thrown
within a call instruction. We didn't need this before because the call
instruction would check for a valid call before involing the profiler.
(JSC::Machine::execute): Added a didExecute hook at the end of top-level
function invocation, since op_ret no longer does this for us.

(JSC::Machine::privateExecute): Removed obsolete profiler hooks. Added
profiler opcodes. Changed some ++vPC to vPC[x] notation, since the
latter is better for performance, and it makes reasoning about the
current opcode in exception handling much simpler.

(JSC::Machine::cti_op_call_NotJSFunction): Removed obsolete profiler
hooks.

(JSC::Machine::cti_op_create_arguments_no_params): Added missing
CTI_STACK_HACK that I noticed when adding CTI_STACK_HACK to the new
profiler opcode functions.

(JSC::Machine::cti_op_profile_will_call):
(JSC::Machine::cti_op_profile_did_call): The new profiler opcode
functions.

(JSC::Machine::cti_op_construct_NotJSConstruct): Removed obsolete profiler
hooks.

  • VM/Machine.h: (JSC::Machine::isCallOpcode): Helper for exception handling.
  • VM/Opcode.h: Declare new opcodes.
  • kjs/JSGlobalObject.h: (JSC::JSGlobalObject::supportsProfiling): Added virtual interface that allows WebCore to specify whether the target global object has the Web Inspector's profiling feature enabled.
  • profiler/Profiler.cpp: (JSC::Profiler::willExecute): (JSC::Profiler::didExecute): (JSC::Profiler::createCallIdentifier):
  • profiler/Profiler.h: Added support for invoking the profiler with an arbitrary JSValue*, and not a known object. We didn't need this before because the call instruction would check for a valid call before involing the profiler.

WebCore:

2008-10-18 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

Fixed https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::supportsProfiling):
  • bindings/js/JSDOMWindowBase.h: Implemented the interface for specifying whether a target global object has the Web Inspector's profiling feature enabled.
  • inspector/JavaScriptDebugServer.cpp: (WebCore::JavaScriptDebugServer::recompileAllJSFunctionsSoon): (WebCore::JavaScriptDebugServer::didAddListener): (WebCore::JavaScriptDebugServer::didRemoveListener):
  • inspector/JavaScriptDebugServer.h: Exported an API for recompiling, used by the Settings object.
  • page/Settings.cpp: (WebCore::Settings::Settings): (WebCore::Settings::setDeveloperExtrasEnabled):
  • page/Settings.h: Recompile when the developer menu is enabled/disabled for the first time, to add/remove profiling hooks. In the future, with better Web Inspector UI, we can do this on a page-by-page basis, instead of a global basis.

LayoutTests:

2008-10-18 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

Test for bugs fixed while working on https://bugs.webkit.org/show_bug.cgi?id=21735
Emit profiling instrumentation only if the Web Inspector's profiling
feature is enabled

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