2 * Copyright (C) 2008, 2009 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"
35 #include "Interpreter.h"
37 #include "BytecodeGenerator.h"
39 #include <wtf/StringExtras.h>
41 #define DUMP_CODE_BLOCK_STATISTICS 0
45 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
47 static UString escapeQuotes(const UString& str)
51 while ((pos = result.find('\"', pos)) >= 0) {
52 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
58 static UString valueToSourceString(ExecState* exec, JSValuePtr val)
60 if (val->isString()) {
62 result += escapeQuotes(val->toString(exec)) + "\"";
66 return val->toString(exec);
69 static CString registerName(int r)
71 if (r == missingThisObjectMarker())
74 return (UString("r") + UString::from(r)).UTF8String();
77 static CString constantName(ExecState* exec, int k, JSValuePtr value)
79 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
82 static CString idName(int id0, const Identifier& ident)
84 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
87 static UString regexpToSourceString(RegExp* regExp)
89 UString pattern = UString("/") + regExp->pattern() + "/";
92 if (regExp->ignoreCase())
94 if (regExp->multiline())
100 static CString regexpName(int re, RegExp* regexp)
102 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
105 static UString pointerToSourceString(void* p)
107 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
108 snprintf(buffer, sizeof(buffer), "%p", p);
112 NEVER_INLINE static const char* debugHookName(int debugHookID)
114 switch (static_cast<DebugHookID>(debugHookID)) {
115 case DidEnterCallFrame:
116 return "didEnterCallFrame";
117 case WillLeaveCallFrame:
118 return "willLeaveCallFrame";
119 case WillExecuteStatement:
120 return "willExecuteStatement";
121 case WillExecuteProgram:
122 return "willExecuteProgram";
123 case DidExecuteProgram:
124 return "didExecuteProgram";
125 case DidReachBreakpoint:
126 return "didReachBreakpoint";
129 ASSERT_NOT_REACHED();
133 static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
135 return it - begin + offset;
138 static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
140 int r0 = (++it)->u.operand;
141 int r1 = (++it)->u.operand;
143 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
146 static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
148 int r0 = (++it)->u.operand;
149 int r1 = (++it)->u.operand;
150 int r2 = (++it)->u.operand;
151 printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
154 static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
156 int r0 = (++it)->u.operand;
157 int offset = (++it)->u.operand;
158 printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, locationForOffset(begin, it, offset));
161 static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
163 int r0 = (++it)->u.operand;
164 int r1 = (++it)->u.operand;
165 int id0 = (++it)->u.operand;
166 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
170 static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
172 int r0 = (++it)->u.operand;
173 int id0 = (++it)->u.operand;
174 int r1 = (++it)->u.operand;
175 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
180 static bool isGlobalResolve(OpcodeID opcodeID)
182 return opcodeID == op_resolve_global;
185 static bool isPropertyAccess(OpcodeID opcodeID)
188 case op_get_by_id_self:
189 case op_get_by_id_proto:
190 case op_get_by_id_chain:
191 case op_get_by_id_self_list:
192 case op_get_by_id_proto_list:
193 case op_put_by_id_transition:
194 case op_put_by_id_replace:
197 case op_get_by_id_generic:
198 case op_put_by_id_generic:
199 case op_get_array_length:
200 case op_get_string_length:
207 static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
210 while (i < instructions.size()) {
211 OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode);
212 if (predicate(currentOpcode)) {
216 i += opcodeLengths[currentOpcode];
219 ASSERT_NOT_REACHED();
223 static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
225 printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).UTF8String().c_str());
228 static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset)
230 switch (stubInfo.opcodeID) {
231 case op_get_by_id_self:
232 printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).UTF8String().c_str());
234 case op_get_by_id_proto:
235 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).UTF8String().c_str());
237 case op_get_by_id_chain:
238 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdChain.chain).UTF8String().c_str());
240 case op_get_by_id_self_list:
241 printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).UTF8String().c_str(), stubInfo.u.getByIdSelfList.listSize);
243 case op_get_by_id_proto_list:
244 printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).UTF8String().c_str(), stubInfo.u.getByIdProtoList.listSize);
246 case op_put_by_id_transition:
247 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).UTF8String().c_str());
249 case op_put_by_id_replace:
250 printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).UTF8String().c_str());
253 printf(" [%4d] %s\n", instructionOffset, "get_by_id");
256 printf(" [%4d] %s\n", instructionOffset, "put_by_id");
258 case op_get_by_id_generic:
259 printf(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic");
261 case op_put_by_id_generic:
262 printf(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic");
264 case op_get_array_length:
265 printf(" [%4d] %s\n", instructionOffset, "op_get_array_length");
267 case op_get_string_length:
268 printf(" [%4d] %s\n", instructionOffset, "op_get_string_length");
271 ASSERT_NOT_REACHED();
276 void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
278 unsigned instructionOffset = vPC - m_instructions.begin();
279 printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).UTF8String().c_str());
282 void CodeBlock::printStructures(const Instruction* vPC) const
284 Interpreter* interpreter = m_globalData->interpreter;
285 unsigned instructionOffset = vPC - m_instructions.begin();
287 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
288 printStructure("get_by_id", vPC, 4);
291 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
292 printStructure("get_by_id_self", vPC, 4);
295 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
296 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());
299 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
300 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().c_str());
303 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
304 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());
307 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
308 printStructure("put_by_id", vPC, 4);
311 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
312 printStructure("put_by_id_replace", vPC, 4);
315 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
316 printStructure("resolve_global", vPC, 4);
320 // These m_instructions doesn't ref Structures.
321 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));
324 void CodeBlock::dump(ExecState* exec) const
326 if (m_instructions.isEmpty()) {
327 printf("No instructions available.\n");
331 size_t instructionCount = 0;
333 for (size_t i = 0; i < m_instructions.size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(m_instructions[i].u.opcode)])
336 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
337 static_cast<unsigned long>(instructionCount),
338 static_cast<unsigned long>(m_instructions.size() * sizeof(Instruction)),
339 this, m_numParameters, m_numCalleeRegisters);
341 Vector<Instruction>::const_iterator begin = m_instructions.begin();
342 Vector<Instruction>::const_iterator end = m_instructions.end();
343 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
344 dump(exec, begin, it);
346 if (!m_identifiers.isEmpty()) {
347 printf("\nIdentifiers:\n");
350 printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ascii());
352 } while (i != m_identifiers.size());
355 if (!m_constantRegisters.isEmpty()) {
356 printf("\nConstants:\n");
357 unsigned registerIndex = m_numVars;
360 printf(" r%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue(exec)).ascii());
363 } while (i < m_constantRegisters.size());
366 if (m_rareData && !m_rareData->m_unexpectedConstants.isEmpty()) {
367 printf("\nUnexpected Constants:\n");
370 printf(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_rareData->m_unexpectedConstants[i]).ascii());
372 } while (i < m_rareData->m_unexpectedConstants.size());
375 if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
376 printf("\nm_regexps:\n");
379 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).ascii());
381 } while (i < m_rareData->m_regexps.size());
385 if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
386 printf("\nStructures:\n");
388 if (!m_globalResolveInfos.isEmpty()) {
391 printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isGlobalResolve));
393 } while (i < m_globalResolveInfos.size());
395 if (!m_structureStubInfos.isEmpty()) {
398 printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isPropertyAccess));
400 } while (i < m_structureStubInfos.size());
403 if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
404 printf("\nStructures:\n");
406 if (!m_globalResolveInstructions.isEmpty()) {
409 printStructures(&m_instructions[m_globalResolveInstructions[i]]);
411 } while (i < m_globalResolveInstructions.size());
413 if (!m_propertyAccessInstructions.isEmpty()) {
416 printStructures(&m_instructions[m_propertyAccessInstructions[i]]);
418 } while (i < m_propertyAccessInstructions.size());
422 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
423 printf("\nException Handlers:\n");
426 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
428 } while (i < m_rareData->m_exceptionHandlers.size());
431 if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
432 printf("Immediate Switch Jump Tables:\n");
435 printf(" %1d = {\n", i);
437 Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
438 for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
441 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
445 } while (i < m_rareData->m_immediateSwitchJumpTables.size());
448 if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
449 printf("\nCharacter Switch Jump Tables:\n");
452 printf(" %1d = {\n", i);
454 Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
455 for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
458 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
459 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
460 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
464 } while (i < m_rareData->m_characterSwitchJumpTables.size());
467 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
468 printf("\nString Switch Jump Tables:\n");
471 printf(" %1d = {\n", i);
472 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
473 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
474 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
477 } while (i < m_rareData->m_stringSwitchJumpTables.size());
483 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
485 int location = it - begin;
486 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
488 printf("[%4d] enter\n", location);
491 case op_enter_with_activation: {
492 int r0 = (++it)->u.operand;
493 printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str());
496 case op_create_arguments: {
497 printf("[%4d] create_arguments\n", location);
500 case op_convert_this: {
501 int r0 = (++it)->u.operand;
502 printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
505 case op_unexpected_load: {
506 int r0 = (++it)->u.operand;
507 int k0 = (++it)->u.operand;
508 printf("[%4d] unexpected_load\t %s, %s\n", location, registerName(r0).c_str(), constantName(exec, k0, unexpectedConstant(k0)).c_str());
511 case op_new_object: {
512 int r0 = (++it)->u.operand;
513 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
517 int dst = (++it)->u.operand;
518 int argv = (++it)->u.operand;
519 int argc = (++it)->u.operand;
520 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
523 case op_new_regexp: {
524 int r0 = (++it)->u.operand;
525 int re0 = (++it)->u.operand;
526 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexp(re0)).c_str());
530 int r0 = (++it)->u.operand;
531 int r1 = (++it)->u.operand;
532 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
536 printUnaryOp(location, it, "not");
540 printBinaryOp(location, it, "eq");
544 printUnaryOp(location, it, "eq_null");
548 printBinaryOp(location, it, "neq");
552 printUnaryOp(location, it, "neq_null");
556 printBinaryOp(location, it, "stricteq");
560 printBinaryOp(location, it, "nstricteq");
564 printBinaryOp(location, it, "less");
568 printBinaryOp(location, it, "lesseq");
572 int r0 = (++it)->u.operand;
573 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
577 int r0 = (++it)->u.operand;
578 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
582 printUnaryOp(location, it, "post_inc");
586 printUnaryOp(location, it, "post_dec");
589 case op_to_jsnumber: {
590 printUnaryOp(location, it, "to_jsnumber");
594 printUnaryOp(location, it, "negate");
598 printBinaryOp(location, it, "add");
603 printBinaryOp(location, it, "mul");
608 printBinaryOp(location, it, "div");
612 printBinaryOp(location, it, "mod");
616 printBinaryOp(location, it, "sub");
621 printBinaryOp(location, it, "lshift");
625 printBinaryOp(location, it, "rshift");
629 printBinaryOp(location, it, "urshift");
633 printBinaryOp(location, it, "bitand");
638 printBinaryOp(location, it, "bitxor");
643 printBinaryOp(location, it, "bitor");
648 printUnaryOp(location, it, "bitnot");
651 case op_instanceof: {
652 int r0 = (++it)->u.operand;
653 int r1 = (++it)->u.operand;
654 int r2 = (++it)->u.operand;
655 int r3 = (++it)->u.operand;
656 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());
660 printUnaryOp(location, it, "typeof");
663 case op_is_undefined: {
664 printUnaryOp(location, it, "is_undefined");
667 case op_is_boolean: {
668 printUnaryOp(location, it, "is_boolean");
672 printUnaryOp(location, it, "is_number");
676 printUnaryOp(location, it, "is_string");
680 printUnaryOp(location, it, "is_object");
683 case op_is_function: {
684 printUnaryOp(location, it, "is_function");
688 printBinaryOp(location, it, "in");
692 int r0 = (++it)->u.operand;
693 int id0 = (++it)->u.operand;
694 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
697 case op_resolve_skip: {
698 int r0 = (++it)->u.operand;
699 int id0 = (++it)->u.operand;
700 int skipLevels = (++it)->u.operand;
701 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), skipLevels);
704 case op_resolve_global: {
705 int r0 = (++it)->u.operand;
706 JSValuePtr scope = JSValuePtr((++it)->u.jsCell);
707 int id0 = (++it)->u.operand;
708 printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).c_str());
712 case op_get_scoped_var: {
713 int r0 = (++it)->u.operand;
714 int index = (++it)->u.operand;
715 int skipLevels = (++it)->u.operand;
716 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
719 case op_put_scoped_var: {
720 int index = (++it)->u.operand;
721 int skipLevels = (++it)->u.operand;
722 int r0 = (++it)->u.operand;
723 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
726 case op_get_global_var: {
727 int r0 = (++it)->u.operand;
728 JSValuePtr scope = JSValuePtr((++it)->u.jsCell);
729 int index = (++it)->u.operand;
730 printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
733 case op_put_global_var: {
734 JSValuePtr scope = JSValuePtr((++it)->u.jsCell);
735 int index = (++it)->u.operand;
736 int r0 = (++it)->u.operand;
737 printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
740 case op_resolve_base: {
741 int r0 = (++it)->u.operand;
742 int id0 = (++it)->u.operand;
743 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
746 case op_resolve_with_base: {
747 int r0 = (++it)->u.operand;
748 int r1 = (++it)->u.operand;
749 int id0 = (++it)->u.operand;
750 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
753 case op_resolve_func: {
754 int r0 = (++it)->u.operand;
755 int r1 = (++it)->u.operand;
756 int id0 = (++it)->u.operand;
757 printf("[%4d] resolve_func\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
761 printGetByIdOp(location, it, m_identifiers, "get_by_id");
764 case op_get_by_id_self: {
765 printGetByIdOp(location, it, m_identifiers, "get_by_id_self");
768 case op_get_by_id_self_list: {
769 printGetByIdOp(location, it, m_identifiers, "get_by_id_self_list");
772 case op_get_by_id_proto: {
773 printGetByIdOp(location, it, m_identifiers, "get_by_id_proto");
776 case op_get_by_id_proto_list: {
777 printGetByIdOp(location, it, m_identifiers, "op_get_by_id_proto_list");
780 case op_get_by_id_chain: {
781 printGetByIdOp(location, it, m_identifiers, "get_by_id_chain");
784 case op_get_by_id_generic: {
785 printGetByIdOp(location, it, m_identifiers, "get_by_id_generic");
788 case op_get_array_length: {
789 printGetByIdOp(location, it, m_identifiers, "get_array_length");
792 case op_get_string_length: {
793 printGetByIdOp(location, it, m_identifiers, "get_string_length");
797 printPutByIdOp(location, it, m_identifiers, "put_by_id");
800 case op_put_by_id_replace: {
801 printPutByIdOp(location, it, m_identifiers, "put_by_id_replace");
804 case op_put_by_id_transition: {
805 printPutByIdOp(location, it, m_identifiers, "put_by_id_transition");
808 case op_put_by_id_generic: {
809 printPutByIdOp(location, it, m_identifiers, "put_by_id_generic");
812 case op_put_getter: {
813 int r0 = (++it)->u.operand;
814 int id0 = (++it)->u.operand;
815 int r1 = (++it)->u.operand;
816 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
819 case op_put_setter: {
820 int r0 = (++it)->u.operand;
821 int id0 = (++it)->u.operand;
822 int r1 = (++it)->u.operand;
823 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
827 int r0 = (++it)->u.operand;
828 int r1 = (++it)->u.operand;
829 int id0 = (++it)->u.operand;
830 printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
833 case op_get_by_val: {
834 int r0 = (++it)->u.operand;
835 int r1 = (++it)->u.operand;
836 int r2 = (++it)->u.operand;
837 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
840 case op_put_by_val: {
841 int r0 = (++it)->u.operand;
842 int r1 = (++it)->u.operand;
843 int r2 = (++it)->u.operand;
844 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
847 case op_del_by_val: {
848 int r0 = (++it)->u.operand;
849 int r1 = (++it)->u.operand;
850 int r2 = (++it)->u.operand;
851 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
854 case op_put_by_index: {
855 int r0 = (++it)->u.operand;
856 unsigned n0 = (++it)->u.operand;
857 int r1 = (++it)->u.operand;
858 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
862 int offset = (++it)->u.operand;
863 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
867 int offset = (++it)->u.operand;
868 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
872 printConditionalJump(begin, it, location, "jtrue");
875 case op_loop_if_true: {
876 printConditionalJump(begin, it, location, "loop_if_true");
880 printConditionalJump(begin, it, location, "jfalse");
884 printConditionalJump(begin, it, location, "jeq_null");
888 printConditionalJump(begin, it, location, "jneq_null");
892 int r0 = (++it)->u.operand;
893 int r1 = (++it)->u.operand;
894 int offset = (++it)->u.operand;
895 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
898 case op_loop_if_less: {
899 int r0 = (++it)->u.operand;
900 int r1 = (++it)->u.operand;
901 int offset = (++it)->u.operand;
902 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
905 case op_loop_if_lesseq: {
906 int r0 = (++it)->u.operand;
907 int r1 = (++it)->u.operand;
908 int offset = (++it)->u.operand;
909 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
912 case op_switch_imm: {
913 int tableIndex = (++it)->u.operand;
914 int defaultTarget = (++it)->u.operand;
915 int scrutineeRegister = (++it)->u.operand;
916 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
919 case op_switch_char: {
920 int tableIndex = (++it)->u.operand;
921 int defaultTarget = (++it)->u.operand;
922 int scrutineeRegister = (++it)->u.operand;
923 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
926 case op_switch_string: {
927 int tableIndex = (++it)->u.operand;
928 int defaultTarget = (++it)->u.operand;
929 int scrutineeRegister = (++it)->u.operand;
930 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
934 int r0 = (++it)->u.operand;
935 int f0 = (++it)->u.operand;
936 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
939 case op_new_func_exp: {
940 int r0 = (++it)->u.operand;
941 int f0 = (++it)->u.operand;
942 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
946 int dst = (++it)->u.operand;
947 int func = (++it)->u.operand;
948 int argCount = (++it)->u.operand;
949 int registerOffset = (++it)->u.operand;
950 printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
954 int dst = (++it)->u.operand;
955 int func = (++it)->u.operand;
956 int argCount = (++it)->u.operand;
957 int registerOffset = (++it)->u.operand;
958 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
961 case op_tear_off_activation: {
962 int r0 = (++it)->u.operand;
963 printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
966 case op_tear_off_arguments: {
967 printf("[%4d] tear_off_arguments\n", location);
971 int r0 = (++it)->u.operand;
972 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
976 int dst = (++it)->u.operand;
977 int func = (++it)->u.operand;
978 int argCount = (++it)->u.operand;
979 int registerOffset = (++it)->u.operand;
980 int proto = (++it)->u.operand;
981 int thisRegister = (++it)->u.operand;
982 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());
985 case op_construct_verify: {
986 int r0 = (++it)->u.operand;
987 int r1 = (++it)->u.operand;
988 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
991 case op_get_pnames: {
992 int r0 = (++it)->u.operand;
993 int r1 = (++it)->u.operand;
994 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
997 case op_next_pname: {
998 int dest = (++it)->u.operand;
999 int iter = (++it)->u.operand;
1000 int offset = (++it)->u.operand;
1001 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, locationForOffset(begin, it, offset));
1004 case op_push_scope: {
1005 int r0 = (++it)->u.operand;
1006 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
1009 case op_pop_scope: {
1010 printf("[%4d] pop_scope\n", location);
1013 case op_push_new_scope: {
1014 int r0 = (++it)->u.operand;
1015 int id0 = (++it)->u.operand;
1016 int r1 = (++it)->u.operand;
1017 printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
1020 case op_jmp_scopes: {
1021 int scopeDelta = (++it)->u.operand;
1022 int offset = (++it)->u.operand;
1023 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, locationForOffset(begin, it, offset));
1027 int r0 = (++it)->u.operand;
1028 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
1032 int r0 = (++it)->u.operand;
1033 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
1036 case op_new_error: {
1037 int r0 = (++it)->u.operand;
1038 int errorType = (++it)->u.operand;
1039 int k0 = (++it)->u.operand;
1040 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, unexpectedConstant(k0)).c_str());
1044 int retAddrDst = (++it)->u.operand;
1045 int offset = (++it)->u.operand;
1046 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, locationForOffset(begin, it, offset));
1050 int retAddrSrc = (++it)->u.operand;
1051 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
1055 int debugHookID = (++it)->u.operand;
1056 int firstLine = (++it)->u.operand;
1057 int lastLine = (++it)->u.operand;
1058 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1061 case op_profile_will_call: {
1062 int function = (++it)->u.operand;
1063 printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
1066 case op_profile_did_call: {
1067 int function = (++it)->u.operand;
1068 printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
1072 int r0 = (++it)->u.operand;
1073 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
1079 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1081 #if DUMP_CODE_BLOCK_STATISTICS
1082 static HashSet<CodeBlock*> liveCodeBlockSet;
1085 #define FOR_EACH_MEMBER_VECTOR(macro) \
1086 macro(instructions) \
1087 macro(globalResolveInfos) \
1088 macro(structureStubInfos) \
1089 macro(callLinkInfos) \
1090 macro(linkedCallerList) \
1091 macro(identifiers) \
1092 macro(functionExpressions) \
1093 macro(constantRegisters)
1095 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1098 macro(unexpectedConstants) \
1099 macro(exceptionHandlers) \
1100 macro(immediateSwitchJumpTables) \
1101 macro(characterSwitchJumpTables) \
1102 macro(stringSwitchJumpTables) \
1103 macro(functionRegisterInfos)
1105 #define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1106 macro(expressionInfo) \
1108 macro(getByIdExceptionInfo) \
1111 template<typename T>
1112 static size_t sizeInBytes(const Vector<T>& vector)
1114 return vector.capacity() * sizeof(T);
1117 void CodeBlock::dumpStatistics()
1119 #if DUMP_CODE_BLOCK_STATISTICS
1120 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1121 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1122 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1123 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS)
1126 // Non-vector data members
1127 size_t evalCodeCacheIsNotEmpty = 0;
1129 size_t symbolTableIsNotEmpty = 0;
1130 size_t symbolTableTotalSize = 0;
1132 size_t hasExceptionInfo = 0;
1133 size_t hasRareData = 0;
1135 size_t isFunctionCode = 0;
1136 size_t isGlobalCode = 0;
1137 size_t isEvalCode = 0;
1139 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1140 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1141 CodeBlock* codeBlock = *it;
1143 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1144 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1147 if (!codeBlock->m_symbolTable.isEmpty()) {
1148 symbolTableIsNotEmpty++;
1149 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1152 if (codeBlock->m_exceptionInfo) {
1154 #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
1155 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS)
1159 if (codeBlock->m_rareData) {
1161 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1162 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1165 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1166 evalCodeCacheIsNotEmpty++;
1169 switch (codeBlock->codeType()) {
1182 size_t totalSize = 0;
1184 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1185 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1186 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1187 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE)
1188 #undef GET_TOTAL_SIZE
1190 totalSize += symbolTableTotalSize;
1191 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1193 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1194 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1195 printf("Size of all CodeBlocks: %zu\n", totalSize);
1196 printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1198 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1199 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1200 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1202 printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo, static_cast<double>(hasExceptionInfo) * 100.0 / liveCodeBlockSet.size());
1203 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1205 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1206 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1207 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1208 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS)
1211 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1212 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1214 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1217 printf("Dumping CodeBlock statistics is not enabled.\n");
1222 CodeBlock::CodeBlock(ScopeNode* ownerNode, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
1223 : m_numCalleeRegisters(0)
1226 , m_numParameters(0)
1227 , m_ownerNode(ownerNode)
1230 , m_instructionCount(0)
1232 , m_needsFullScopeChain(ownerNode->needsActivation())
1233 , m_usesEval(ownerNode->usesEval())
1234 , m_codeType(codeType)
1235 , m_source(sourceProvider)
1236 , m_sourceOffset(sourceOffset)
1237 , m_exceptionInfo(new ExceptionInfo)
1241 #if DUMP_CODE_BLOCK_STATISTICS
1242 liveCodeBlockSet.add(this);
1246 CodeBlock::~CodeBlock()
1249 for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
1250 derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
1252 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1253 derefStructures(&m_instructions[m_propertyAccessInstructions[i]]);
1255 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1256 if (m_globalResolveInfos[i].structure)
1257 m_globalResolveInfos[i].structure->deref();
1260 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1261 m_structureStubInfos[i].deref();
1263 for (size_t size = m_callLinkInfos.size(), i = 0; i < size; ++i) {
1264 CallLinkInfo* callLinkInfo = &m_callLinkInfos[i];
1265 if (callLinkInfo->isLinked())
1266 callLinkInfo->callee->removeCaller(callLinkInfo);
1272 #if DUMP_CODE_BLOCK_STATISTICS
1273 liveCodeBlockSet.remove(this);
1278 void CodeBlock::unlinkCallers()
1280 size_t size = m_linkedCallerList.size();
1281 for (size_t i = 0; i < size; ++i) {
1282 CallLinkInfo* currentCaller = m_linkedCallerList[i];
1283 JIT::unlinkCall(currentCaller);
1284 currentCaller->setUnlinked();
1286 m_linkedCallerList.clear();
1290 void CodeBlock::derefStructures(Instruction* vPC) const
1292 Interpreter* interpreter = m_globalData->interpreter;
1294 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1295 vPC[4].u.structure->deref();
1298 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1299 vPC[4].u.structure->deref();
1300 vPC[5].u.structure->deref();
1303 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1304 vPC[4].u.structure->deref();
1305 vPC[5].u.structureChain->deref();
1308 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1309 vPC[4].u.structure->deref();
1310 vPC[5].u.structure->deref();
1311 vPC[6].u.structureChain->deref();
1314 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1315 vPC[4].u.structure->deref();
1318 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
1319 if(vPC[4].u.structure)
1320 vPC[4].u.structure->deref();
1323 if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
1324 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))) {
1325 PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
1326 polymorphicStructures->derefStructures(vPC[5].u.operand);
1327 delete polymorphicStructures;
1331 // These instructions don't ref their Structures.
1332 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));
1335 void CodeBlock::refStructures(Instruction* vPC) const
1337 Interpreter* interpreter = m_globalData->interpreter;
1339 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1340 vPC[4].u.structure->ref();
1343 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1344 vPC[4].u.structure->ref();
1345 vPC[5].u.structure->ref();
1348 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1349 vPC[4].u.structure->ref();
1350 vPC[5].u.structureChain->ref();
1353 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1354 vPC[4].u.structure->ref();
1355 vPC[5].u.structure->ref();
1356 vPC[6].u.structureChain->ref();
1359 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1360 vPC[4].u.structure->ref();
1364 // These instructions don't ref their Structures.
1365 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));
1368 void CodeBlock::mark()
1370 for (size_t i = 0; i < m_constantRegisters.size(); ++i)
1371 if (!m_constantRegisters[i].marked())
1372 m_constantRegisters[i].mark();
1374 for (size_t i = 0; i < m_functionExpressions.size(); ++i)
1375 m_functionExpressions[i]->body()->mark();
1378 for (size_t i = 0; i < m_rareData->m_functions.size(); ++i)
1379 m_rareData->m_functions[i]->body()->mark();
1381 for (size_t i = 0; i < m_rareData->m_unexpectedConstants.size(); ++i) {
1382 if (!m_rareData->m_unexpectedConstants[i]->marked())
1383 m_rareData->m_unexpectedConstants[i]->mark();
1385 m_rareData->m_evalCodeCache.mark();
1389 void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
1391 if (m_exceptionInfo)
1394 ScopeChainNode* scopeChain = callFrame->scopeChain();
1395 if (m_needsFullScopeChain) {
1396 ScopeChain sc(scopeChain);
1397 int scopeDelta = sc.localDepth();
1398 if (m_codeType == EvalCode)
1399 scopeDelta -= static_cast<EvalCodeBlock*>(this)->baseScopeDepth();
1400 else if (m_codeType == FunctionCode)
1401 scopeDelta++; // Compilation of function code assumes activation is not on the scope chain yet.
1402 ASSERT(scopeDelta >= 0);
1403 while (scopeDelta--)
1404 scopeChain = scopeChain->next;
1407 switch (m_codeType) {
1408 case FunctionCode: {
1409 FunctionBodyNode* ownerFunctionBodyNode = static_cast<FunctionBodyNode*>(m_ownerNode);
1410 RefPtr<FunctionBodyNode> newFunctionBody = m_globalData->parser->reparse<FunctionBodyNode>(m_globalData, ownerFunctionBodyNode);
1411 newFunctionBody->finishParsing(ownerFunctionBodyNode->copyParameters(), ownerFunctionBodyNode->parameterCount());
1413 m_globalData->scopeNodeBeingReparsed = newFunctionBody.get();
1415 CodeBlock& newCodeBlock = newFunctionBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1416 ASSERT(newCodeBlock.m_exceptionInfo);
1417 ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1420 JIT::compile(m_globalData, &newCodeBlock);
1421 ASSERT(newCodeBlock.m_jitCode.codeSize == m_jitCode.codeSize);
1424 m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1426 m_globalData->scopeNodeBeingReparsed = 0;
1431 EvalNode* ownerEvalNode = static_cast<EvalNode*>(m_ownerNode);
1432 RefPtr<EvalNode> newEvalBody = m_globalData->parser->reparse<EvalNode>(m_globalData, ownerEvalNode);
1434 m_globalData->scopeNodeBeingReparsed = newEvalBody.get();
1436 EvalCodeBlock& newCodeBlock = newEvalBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1437 ASSERT(newCodeBlock.m_exceptionInfo);
1438 ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1441 JIT::compile(m_globalData, &newCodeBlock);
1442 ASSERT(newCodeBlock.m_jitCode.codeSize == m_jitCode.codeSize);
1445 m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1447 m_globalData->scopeNodeBeingReparsed = 0;
1452 // CodeBlocks for Global code blocks are transient and therefore to not gain from
1453 // from throwing out there exception information.
1454 ASSERT_NOT_REACHED();
1458 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1460 ASSERT(bytecodeOffset < m_instructionCount);
1465 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1466 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1467 // Handlers are ordered innermost first, so the first handler we encounter
1468 // that contains the source address is the correct handler to use.
1469 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1470 return &exceptionHandlers[i];
1476 int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset)
1478 ASSERT(bytecodeOffset < m_instructionCount);
1480 reparseForExceptionInfoIfNecessary(callFrame);
1481 ASSERT(m_exceptionInfo);
1483 if (!m_exceptionInfo->m_lineInfo.size())
1484 return m_ownerNode->source().firstLine(); // Empty function
1487 int high = m_exceptionInfo->m_lineInfo.size();
1488 while (low < high) {
1489 int mid = low + (high - low) / 2;
1490 if (m_exceptionInfo->m_lineInfo[mid].instructionOffset <= bytecodeOffset)
1497 return m_ownerNode->source().firstLine();
1498 return m_exceptionInfo->m_lineInfo[low - 1].lineNumber;
1501 int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1503 ASSERT(bytecodeOffset < m_instructionCount);
1505 reparseForExceptionInfoIfNecessary(callFrame);
1506 ASSERT(m_exceptionInfo);
1508 if (!m_exceptionInfo->m_expressionInfo.size()) {
1509 // We didn't think anything could throw. Apparently we were wrong.
1513 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1517 int high = m_exceptionInfo->m_expressionInfo.size();
1518 while (low < high) {
1519 int mid = low + (high - low) / 2;
1520 if (m_exceptionInfo->m_expressionInfo[mid].instructionOffset <= bytecodeOffset)
1531 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1534 startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset;
1535 endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset;
1536 divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
1537 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1540 bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID)
1542 ASSERT(bytecodeOffset < m_instructionCount);
1544 reparseForExceptionInfoIfNecessary(callFrame);
1545 ASSERT(m_exceptionInfo);
1547 if (!m_exceptionInfo->m_getByIdExceptionInfo.size())
1551 int high = m_exceptionInfo->m_getByIdExceptionInfo.size();
1552 while (low < high) {
1553 int mid = low + (high - low) / 2;
1554 if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset)
1560 if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset)
1563 opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpConstruct ? op_construct : op_instanceof;
1568 bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex)
1570 ASSERT(bytecodeOffset < m_instructionCount);
1572 if (!m_rareData || !m_rareData->m_functionRegisterInfos.size())
1576 int high = m_rareData->m_functionRegisterInfos.size();
1577 while (low < high) {
1578 int mid = low + (high - low) / 2;
1579 if (m_rareData->m_functionRegisterInfos[mid].bytecodeOffset <= bytecodeOffset)
1585 if (!low || m_rareData->m_functionRegisterInfos[low - 1].bytecodeOffset != bytecodeOffset)
1588 functionRegisterIndex = m_rareData->m_functionRegisterInfos[low - 1].functionRegisterIndex;
1594 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1596 if (m_globalResolveInstructions.isEmpty())
1600 int high = m_globalResolveInstructions.size();
1601 while (low < high) {
1602 int mid = low + (high - low) / 2;
1603 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1609 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1614 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1616 if (m_globalResolveInfos.isEmpty())
1620 int high = m_globalResolveInfos.size();
1621 while (low < high) {
1622 int mid = low + (high - low) / 2;
1623 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1629 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1636 void CodeBlock::setJITCode(JITCodeRef& jitCode)
1638 m_jitCode = jitCode;
1639 #if !ENABLE(OPCODE_SAMPLING)
1640 if (!BytecodeGenerator::dumpsGeneratedCode())
1641 m_instructions.clear();
1646 void CodeBlock::shrinkToFit()
1648 m_instructions.shrinkToFit();
1651 m_propertyAccessInstructions.shrinkToFit();
1652 m_globalResolveInstructions.shrinkToFit();
1654 m_structureStubInfos.shrinkToFit();
1655 m_globalResolveInfos.shrinkToFit();
1656 m_callLinkInfos.shrinkToFit();
1657 m_linkedCallerList.shrinkToFit();
1660 m_identifiers.shrinkToFit();
1661 m_functionExpressions.shrinkToFit();
1662 m_constantRegisters.shrinkToFit();
1664 if (m_exceptionInfo) {
1665 m_exceptionInfo->m_expressionInfo.shrinkToFit();
1666 m_exceptionInfo->m_lineInfo.shrinkToFit();
1667 m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit();
1671 m_rareData->m_exceptionHandlers.shrinkToFit();
1672 m_rareData->m_functions.shrinkToFit();
1673 m_rareData->m_unexpectedConstants.shrinkToFit();
1674 m_rareData->m_regexps.shrinkToFit();
1675 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1676 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1677 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1679 m_rareData->m_functionRegisterInfos.shrinkToFit();