2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "CodeBlock.h"
38 #include <wtf/StringExtras.h>
42 #if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
44 static UString escapeQuotes(const UString& str)
48 while ((pos = result.find('\"', pos)) >= 0) {
49 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
55 static UString valueToSourceString(ExecState* exec, JSValuePtr val)
57 if (val->isString()) {
59 result += escapeQuotes(val->toString(exec)) + "\"";
63 return val->toString(exec);
66 static CString registerName(int r)
68 if (r == missingThisObjectMarker())
71 return (UString("r") + UString::from(r)).UTF8String();
74 static CString constantName(ExecState* exec, int k, JSValuePtr value)
76 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
79 static CString idName(int id0, const Identifier& ident)
81 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
84 static UString regexpToSourceString(RegExp* regExp)
86 UString pattern = UString("/") + regExp->pattern() + "/";
89 if (regExp->ignoreCase())
91 if (regExp->multiline())
97 static CString regexpName(int re, RegExp* regexp)
99 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
102 static UString pointerToSourceString(void* p)
104 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
105 snprintf(buffer, sizeof(buffer), "%p", p);
109 NEVER_INLINE static const char* debugHookName(int debugHookID)
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";
126 ASSERT_NOT_REACHED();
130 static int jumpTarget(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
132 return it - begin + offset;
135 static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
137 int r0 = (++it)->u.operand;
138 int r1 = (++it)->u.operand;
140 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
143 static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
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());
151 static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
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));
158 static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
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());
167 static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& identifiers, const char* op)
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());
176 void CodeBlock::printStructureID(const char* name, const Instruction* vPC, int operand) const
178 unsigned instructionOffset = vPC - instructions.begin();
179 printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structureID).UTF8String().c_str());
182 void CodeBlock::printStructureIDs(const Instruction* vPC) const
184 Machine* machine = globalData->machine;
185 unsigned instructionOffset = vPC - instructions.begin();
187 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id)) {
188 printStructureID("get_by_id", vPC, 4);
191 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
192 printStructureID("get_by_id_self", vPC, 4);
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());
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());
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());
207 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id)) {
208 printStructureID("put_by_id", vPC, 4);
211 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
212 printStructureID("put_by_id_replace", vPC, 4);
215 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
216 printStructureID("resolve_global", vPC, 4);
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));
224 void CodeBlock::dump(ExecState* exec) const
226 Vector<Instruction>::const_iterator begin = instructions.begin();
227 Vector<Instruction>::const_iterator end = instructions.end();
229 size_t instructionCount = 0;
230 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
231 if (exec->machine()->isOpcode(it->u.opcode))
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);
239 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
240 dump(exec, begin, it);
242 if (identifiers.size()) {
243 printf("\nIdentifiers:\n");
246 printf(" id%u = %s\n", static_cast<unsigned>(i), identifiers[i].ascii());
248 } while (i != identifiers.size());
251 if (constantRegisters.size()) {
252 printf("\nConstants:\n");
255 printf(" r%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
257 } while (i < constantRegisters.size());
260 if (unexpectedConstants.size()) {
261 printf("\nUnexpected Constants:\n");
264 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, unexpectedConstants[i]).ascii());
266 } while (i < unexpectedConstants.size());
269 if (regexps.size()) {
270 printf("\nRegExps:\n");
273 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(regexps[i].get()).ascii());
275 } while (i < regexps.size());
278 if (structureIDInstructions.size()) {
279 printf("\nStructureIDs:\n");
282 printStructureIDs(&instructions[structureIDInstructions[i].opcodeIndex]);
284 } while (i < structureIDInstructions.size());
287 if (exceptionHandlers.size()) {
288 printf("\nException Handlers:\n");
291 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, exceptionHandlers[i].start, exceptionHandlers[i].end, exceptionHandlers[i].target);
293 } while (i < exceptionHandlers.size());
296 if (immediateSwitchJumpTables.size()) {
297 printf("Immediate Switch Jump Tables:\n");
300 printf(" %1d = {\n", i);
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) {
306 printf("\t\t%4d => %04d\n", entry + immediateSwitchJumpTables[i].min, *iter);
310 } while (i < immediateSwitchJumpTables.size());
313 if (characterSwitchJumpTables.size()) {
314 printf("\nCharacter Switch Jump Tables:\n");
317 printf(" %1d = {\n", i);
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) {
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);
329 } while (i < characterSwitchJumpTables.size());
332 if (stringSwitchJumpTables.size()) {
333 printf("\nString Switch Jump Tables:\n");
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);
342 } while (i < stringSwitchJumpTables.size());
348 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
350 int location = it - begin;
351 switch (exec->machine()->getOpcodeID(it->u.opcode)) {
353 printf("[%4d] enter\n", location);
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());
361 case op_create_arguments: {
362 printf("[%4d] create_arguments\n", location);
365 case op_convert_this: {
366 int r0 = (++it)->u.operand;
367 printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
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());
376 case op_new_object: {
377 int r0 = (++it)->u.operand;
378 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
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);
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());
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());
401 printUnaryOp(location, it, "not");
405 printBinaryOp(location, it, "eq");
409 printUnaryOp(location, it, "eq_null");
413 printBinaryOp(location, it, "neq");
417 printUnaryOp(location, it, "neq_null");
421 printBinaryOp(location, it, "stricteq");
425 printBinaryOp(location, it, "nstricteq");
429 printBinaryOp(location, it, "less");
433 printBinaryOp(location, it, "lesseq");
437 int r0 = (++it)->u.operand;
438 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
442 int r0 = (++it)->u.operand;
443 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
447 printUnaryOp(location, it, "post_inc");
451 printUnaryOp(location, it, "post_dec");
454 case op_to_jsnumber: {
455 printUnaryOp(location, it, "to_jsnumber");
459 printUnaryOp(location, it, "negate");
463 printBinaryOp(location, it, "add");
468 printBinaryOp(location, it, "mul");
473 printBinaryOp(location, it, "div");
477 printBinaryOp(location, it, "mod");
481 printBinaryOp(location, it, "sub");
486 printBinaryOp(location, it, "lshift");
490 printBinaryOp(location, it, "rshift");
494 printBinaryOp(location, it, "urshift");
498 printBinaryOp(location, it, "bitand");
503 printBinaryOp(location, it, "bitxor");
508 printBinaryOp(location, it, "bitor");
513 printUnaryOp(location, it, "bitnot");
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());
525 printUnaryOp(location, it, "typeof");
528 case op_is_undefined: {
529 printUnaryOp(location, it, "is_undefined");
532 case op_is_boolean: {
533 printUnaryOp(location, it, "is_boolean");
537 printUnaryOp(location, it, "is_number");
541 printUnaryOp(location, it, "is_string");
545 printUnaryOp(location, it, "is_object");
548 case op_is_function: {
549 printUnaryOp(location, it, "is_function");
553 printBinaryOp(location, it, "in");
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());
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);
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());
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);
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());
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);
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());
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());
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());
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());
626 printGetByIdOp(location, it, identifiers, "get_by_id");
629 case op_get_by_id_self: {
630 printGetByIdOp(location, it, identifiers, "get_by_id_self");
633 case op_get_by_id_proto: {
634 printGetByIdOp(location, it, identifiers, "get_by_id_proto");
637 case op_get_by_id_chain: {
638 printGetByIdOp(location, it, identifiers, "get_by_id_chain");
641 case op_get_by_id_generic: {
642 printGetByIdOp(location, it, identifiers, "get_by_id_generic");
645 case op_get_array_length: {
646 printGetByIdOp(location, it, identifiers, "get_array_length");
649 case op_get_string_length: {
650 printGetByIdOp(location, it, identifiers, "get_string_length");
654 printPutByIdOp(location, it, identifiers, "put_by_id");
657 case op_put_by_id_replace: {
658 printPutByIdOp(location, it, identifiers, "put_by_id_replace");
661 case op_put_by_id_transition: {
662 printPutByIdOp(location, it, identifiers, "put_by_id_transition");
665 case op_put_by_id_generic: {
666 printPutByIdOp(location, it, identifiers, "put_by_id_generic");
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());
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());
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());
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());
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());
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());
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());
719 int offset = (++it)->u.operand;
720 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
724 int offset = (++it)->u.operand;
725 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset));
729 printConditionalJump(begin, it, location, "jtrue");
732 case op_loop_if_true: {
733 printConditionalJump(begin, it, location, "loop_if_true");
737 printConditionalJump(begin, it, location, "jfalse");
741 printConditionalJump(begin, it, location, "jeq_null");
745 printConditionalJump(begin, it, location, "jneq_null");
749 int r0 = (++it)->u.operand;
750 int r1 = (++it)->u.operand;
751 int offset = (++it)->u.operand;
752 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
755 case op_loop_if_less: {
756 int r0 = (++it)->u.operand;
757 int r1 = (++it)->u.operand;
758 int offset = (++it)->u.operand;
759 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));
762 case op_loop_if_lesseq: {
763 int r0 = (++it)->u.operand;
764 int r1 = (++it)->u.operand;
765 int offset = (++it)->u.operand;
766 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));
769 case op_switch_imm: {
770 int tableIndex = (++it)->u.operand;
771 int defaultTarget = (++it)->u.operand;
772 int scrutineeRegister = (++it)->u.operand;
773 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
776 case op_switch_char: {
777 int tableIndex = (++it)->u.operand;
778 int defaultTarget = (++it)->u.operand;
779 int scrutineeRegister = (++it)->u.operand;
780 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
783 case op_switch_string: {
784 int tableIndex = (++it)->u.operand;
785 int defaultTarget = (++it)->u.operand;
786 int scrutineeRegister = (++it)->u.operand;
787 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, jumpTarget(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
791 int r0 = (++it)->u.operand;
792 int f0 = (++it)->u.operand;
793 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
796 case op_new_func_exp: {
797 int r0 = (++it)->u.operand;
798 int f0 = (++it)->u.operand;
799 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
803 int r0 = (++it)->u.operand;
804 int r1 = (++it)->u.operand;
805 int r2 = (++it)->u.operand;
806 int tempCount = (++it)->u.operand;
807 int argCount = (++it)->u.operand;
808 int registerOffset = (++it)->u.operand;
809 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);
813 int r0 = (++it)->u.operand;
814 int r1 = (++it)->u.operand;
815 int r2 = (++it)->u.operand;
816 int tempCount = (++it)->u.operand;
817 int argCount = (++it)->u.operand;
818 int registerOffset = (++it)->u.operand;
819 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);
822 case op_tear_off_activation: {
823 int r0 = (++it)->u.operand;
824 printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
827 case op_tear_off_arguments: {
828 printf("[%4d] tear_off_arguments\n", location);
832 int r0 = (++it)->u.operand;
833 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
837 int r0 = (++it)->u.operand;
838 int r1 = (++it)->u.operand;
839 int r2 = (++it)->u.operand;
840 int tempCount = (++it)->u.operand;
841 int argCount = (++it)->u.operand;
842 int registerOffset = (++it)->u.operand;
843 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);
846 case op_construct_verify: {
847 int r0 = (++it)->u.operand;
848 int r1 = (++it)->u.operand;
849 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
852 case op_get_pnames: {
853 int r0 = (++it)->u.operand;
854 int r1 = (++it)->u.operand;
855 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
858 case op_next_pname: {
859 int dest = (++it)->u.operand;
860 int iter = (++it)->u.operand;
861 int offset = (++it)->u.operand;
862 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, jumpTarget(begin, it, offset));
865 case op_push_scope: {
866 int r0 = (++it)->u.operand;
867 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
871 printf("[%4d] pop_scope\n", location);
874 case op_push_new_scope: {
875 int r0 = (++it)->u.operand;
876 int id0 = (++it)->u.operand;
877 int r1 = (++it)->u.operand;
878 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());
881 case op_jmp_scopes: {
882 int scopeDelta = (++it)->u.operand;
883 int offset = (++it)->u.operand;
884 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, jumpTarget(begin, it, offset));
888 int r0 = (++it)->u.operand;
889 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
893 int r0 = (++it)->u.operand;
894 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
898 int r0 = (++it)->u.operand;
899 int errorType = (++it)->u.operand;
900 int k0 = (++it)->u.operand;
901 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstants[k0]).c_str());
905 int retAddrDst = (++it)->u.operand;
906 int offset = (++it)->u.operand;
907 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, jumpTarget(begin, it, offset));
911 int retAddrSrc = (++it)->u.operand;
912 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
916 int debugHookID = (++it)->u.operand;
917 int firstLine = (++it)->u.operand;
918 int lastLine = (++it)->u.operand;
919 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
922 case op_profile_will_call: {
923 int function = (++it)->u.operand;
924 printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
927 case op_profile_did_call: {
928 int function = (++it)->u.operand;
929 printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
933 int r0 = (++it)->u.operand;
934 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
940 #endif // !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
942 CodeBlock::~CodeBlock()
944 size_t size = structureIDInstructions.size();
945 for (size_t i = 0; i < size; ++i) {
946 derefStructureIDs(&instructions[structureIDInstructions[i].opcodeIndex]);
947 if (structureIDInstructions[i].stubRoutine)
948 fastFree(structureIDInstructions[i].stubRoutine);
949 if (CallLinkInfo* callLinkInfo = structureIDInstructions[i].linkInfoPtr) {
950 callLinkInfo->callee->removeCaller(callLinkInfo);
964 void CodeBlock::unlinkCallers()
966 size_t size = linkedCallerList.size();
967 for (size_t i = 0; i < size; ++i) {
968 CallLinkInfo* currentCaller = linkedCallerList[i];
969 CTI::unlinkCall(currentCaller->callerStructureStubInfo);
970 currentCaller->callerStructureStubInfo->linkInfoPtr = 0;
971 delete currentCaller;
973 linkedCallerList.clear();
977 void CodeBlock::derefStructureIDs(Instruction* vPC) const
979 Machine* machine = globalData->machine;
981 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
982 vPC[4].u.structureID->deref();
985 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
986 vPC[4].u.structureID->deref();
987 vPC[5].u.structureID->deref();
990 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
991 vPC[4].u.structureID->deref();
992 vPC[5].u.structureIDChain->deref();
995 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
996 vPC[4].u.structureID->deref();
997 vPC[5].u.structureID->deref();
998 vPC[6].u.structureIDChain->deref();
1001 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
1002 vPC[4].u.structureID->deref();
1005 if (vPC[0].u.opcode == machine->getOpcode(op_resolve_global)) {
1006 if(vPC[4].u.structureID)
1007 vPC[4].u.structureID->deref();
1011 // These instructions don't ref their StructureIDs.
1012 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)
1013 || 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));
1016 void CodeBlock::refStructureIDs(Instruction* vPC) const
1018 Machine* machine = globalData->machine;
1020 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_self)) {
1021 vPC[4].u.structureID->ref();
1024 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_proto)) {
1025 vPC[4].u.structureID->ref();
1026 vPC[5].u.structureID->ref();
1029 if (vPC[0].u.opcode == machine->getOpcode(op_get_by_id_chain)) {
1030 vPC[4].u.structureID->ref();
1031 vPC[5].u.structureIDChain->ref();
1034 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_transition)) {
1035 vPC[4].u.structureID->ref();
1036 vPC[5].u.structureID->ref();
1037 vPC[6].u.structureIDChain->ref();
1040 if (vPC[0].u.opcode == machine->getOpcode(op_put_by_id_replace)) {
1041 vPC[4].u.structureID->ref();
1045 // These instructions don't ref their StructureIDs.
1046 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));
1049 void CodeBlock::mark()
1051 for (size_t i = 0; i < constantRegisters.size(); ++i)
1052 if (!constantRegisters[i].marked())
1053 constantRegisters[i].mark();
1055 for (size_t i = 0; i < unexpectedConstants.size(); ++i)
1056 if (!unexpectedConstants[i]->marked())
1057 unexpectedConstants[i]->mark();
1059 for (size_t i = 0; i < functions.size(); ++i)
1060 functions[i]->body()->mark();
1062 for (size_t i = 0; i < functionExpressions.size(); ++i)
1063 functionExpressions[i]->body()->mark();
1066 bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth)
1068 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1069 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1070 unsigned addressOffset = vPC - instructions.begin();
1071 ASSERT(addressOffset < instructions.size());
1073 for (; ptr != end; ++ptr) {
1074 // Handlers are ordered innermost first, so the first handler we encounter
1075 // that contains the source address is the correct handler to use.
1076 if (ptr->start <= addressOffset && ptr->end >= addressOffset) {
1077 scopeDepth = ptr->scopeDepth;
1078 target = instructions.begin() + ptr->target;
1085 void* CodeBlock::nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC)
1087 Vector<HandlerInfo>::iterator ptr = exceptionHandlers.begin();
1088 Vector<HandlerInfo>::iterator end = exceptionHandlers.end();
1090 for (; ptr != end; ++ptr) {
1091 Instruction*target = instructions.begin() + ptr->target;
1092 if (handlerVPC == target)
1093 return ptr->nativeCode;
1099 int CodeBlock::lineNumberForVPC(const Instruction* vPC)
1101 ASSERT(lineInfo.size());
1102 unsigned instructionOffset = vPC - instructions.begin();
1103 ASSERT(instructionOffset < instructions.size());
1105 if (!lineInfo.size())
1106 return 1; // Empty function
1109 int high = lineInfo.size();
1110 while (low < high) {
1111 int mid = low + (high - low) / 2;
1112 if (lineInfo[mid].instructionOffset <= instructionOffset)
1117 return lineInfo[low - 1].lineNumber;
1120 int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
1122 unsigned instructionOffset = vPC - instructions.begin();
1123 ASSERT(instructionOffset < instructions.size());
1125 if (!expressionInfo.size()) {
1126 // We didn't think anything could throw. Apparently we were wrong.
1130 return lineNumberForVPC(vPC);
1134 int high = expressionInfo.size();
1135 while (low < high) {
1136 int mid = low + (high - low) / 2;
1137 if (expressionInfo[mid].instructionOffset <= instructionOffset)
1148 return lineNumberForVPC(vPC);
1151 startOffset = expressionInfo[low - 1].startOffset;
1152 endOffset = expressionInfo[low - 1].endOffset;
1153 divot = expressionInfo[low - 1].divotPoint + sourceOffset;
1154 return lineNumberForVPC(vPC);
1157 int32_t SimpleJumpTable::offsetForValue(int32_t value, int32_t defaultOffset)
1159 if (value >= min && static_cast<uint32_t>(value - min) < branchOffsets.size()) {
1160 int32_t offset = branchOffsets[value - min];
1164 return defaultOffset;