257130d614cbecb19675da65631379870f5ecabb
[WebKit-https.git] / JavaScriptCore / bytecode / CodeBlock.cpp
1 /*
2  * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "CodeBlock.h"
32
33 #include "JIT.h"
34 #include "JSValue.h"
35 #include "Interpreter.h"
36 #include "Debugger.h"
37 #include "BytecodeGenerator.h"
38 #include <stdio.h>
39 #include <wtf/StringExtras.h>
40
41 #define DUMP_CODE_BLOCK_STATISTICS 0
42
43 namespace JSC {
44
45 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
46
47 static UString escapeQuotes(const UString& str)
48 {
49     UString result = str;
50     int pos = 0;
51     while ((pos = result.find('\"', pos)) >= 0) {
52         result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
53         pos += 4;
54     }
55     return result;
56 }
57
58 static UString valueToSourceString(ExecState* exec, JSValuePtr val)
59 {
60     if (val->isString()) {
61         UString result("\"");
62         result += escapeQuotes(val->toString(exec)) + "\"";
63         return result;
64     } 
65
66     return val->toString(exec);
67 }
68
69 static CString registerName(int r)
70 {
71     if (r == missingThisObjectMarker())
72         return "<null>";
73
74     return (UString("r") + UString::from(r)).UTF8String();
75 }
76
77 static CString constantName(ExecState* exec, int k, JSValuePtr value)
78 {
79     return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
80 }
81
82 static CString idName(int id0, const Identifier& ident)
83 {
84     return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
85 }
86
87 static UString regexpToSourceString(RegExp* regExp)
88 {
89     UString pattern = UString("/") + regExp->pattern() + "/";
90     if (regExp->global())
91         pattern += "g";
92     if (regExp->ignoreCase())
93         pattern += "i";
94     if (regExp->multiline())
95         pattern += "m";
96
97     return pattern;
98 }
99
100 static CString regexpName(int re, RegExp* regexp)
101 {
102     return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
103 }
104
105 static UString pointerToSourceString(void* p)
106 {
107     char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
108     snprintf(buffer, sizeof(buffer), "%p", p);
109     return buffer;
110 }
111
112 NEVER_INLINE static const char* debugHookName(int debugHookID)
113 {
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";
127     }
128
129     ASSERT_NOT_REACHED();
130     return "";
131 }
132
133 static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
134 {
135     return it - begin + offset;
136 }
137
138 static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
139 {
140     int r0 = (++it)->u.operand;
141     int r1 = (++it)->u.operand;
142
143     printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str());
144 }
145
146 static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
147 {
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());
152 }
153
154 static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
155 {
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));
159 }
160
161 static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
162 {
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());
167     it += 4;
168 }
169
170 static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
171 {
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());
176     it += 4;
177 }
178
179 #if ENABLE(JIT)
180 static bool isGlobalResolve(OpcodeID opcodeID)
181 {
182     return opcodeID == op_resolve_global;
183 }
184
185 static bool isPropertyAccess(OpcodeID opcodeID)
186 {
187     switch (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:
195         case op_get_by_id:
196         case op_put_by_id:
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:
201             return true;
202         default:
203             return false;
204     }
205 }
206
207 static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
208 {
209     size_t i = 0;
210     while (i < instructions.size()) {
211         OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode);
212         if (predicate(currentOpcode)) {
213             if (!--nth)
214                 return i;
215         }
216         i += opcodeLengths[currentOpcode];
217     }
218
219     ASSERT_NOT_REACHED();
220     return 0;
221 }
222
223 static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
224 {
225     printf("  [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).UTF8String().c_str());
226 }
227
228 static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset)
229 {
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());
233         return;
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());
236         return;
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());
239         return;
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);
242         return;
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);
245         return;
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());
248         return;
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());
251         return;
252     case op_get_by_id:
253         printf("  [%4d] %s\n", instructionOffset, "get_by_id");
254         return;
255     case op_put_by_id:
256         printf("  [%4d] %s\n", instructionOffset, "put_by_id");
257         return;
258     case op_get_by_id_generic:
259         printf("  [%4d] %s\n", instructionOffset, "op_get_by_id_generic");
260         return;
261     case op_put_by_id_generic:
262         printf("  [%4d] %s\n", instructionOffset, "op_put_by_id_generic");
263         return;
264     case op_get_array_length:
265         printf("  [%4d] %s\n", instructionOffset, "op_get_array_length");
266         return;
267     case op_get_string_length:
268         printf("  [%4d] %s\n", instructionOffset, "op_get_string_length");
269         return;
270     default:
271         ASSERT_NOT_REACHED();
272     }
273 }
274 #endif
275
276 void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
277 {
278     unsigned instructionOffset = vPC - m_instructions.begin();
279     printf("  [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).UTF8String().c_str());
280 }
281
282 void CodeBlock::printStructures(const Instruction* vPC) const
283 {
284     Interpreter* interpreter = m_globalData->interpreter;
285     unsigned instructionOffset = vPC - m_instructions.begin();
286
287     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
288         printStructure("get_by_id", vPC, 4);
289         return;
290     }
291     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
292         printStructure("get_by_id_self", vPC, 4);
293         return;
294     }
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());
297         return;
298     }
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());
301         return;
302     }
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());
305         return;
306     }
307     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
308         printStructure("put_by_id", vPC, 4);
309         return;
310     }
311     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
312         printStructure("put_by_id_replace", vPC, 4);
313         return;
314     }
315     if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
316         printStructure("resolve_global", vPC, 4);
317         return;
318     }
319
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));
322 }
323
324 void CodeBlock::dump(ExecState* exec) const
325 {
326     if (m_instructions.isEmpty()) {
327         printf("No instructions available.\n");
328         return;
329     }
330
331     size_t instructionCount = 0;
332
333     for (size_t i = 0; i < m_instructions.size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(m_instructions[i].u.opcode)])
334         ++instructionCount;
335
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);
340
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);
345
346     if (!m_identifiers.isEmpty()) {
347         printf("\nIdentifiers:\n");
348         size_t i = 0;
349         do {
350             printf("  id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ascii());
351             ++i;
352         } while (i != m_identifiers.size());
353     }
354
355     if (!m_constantRegisters.isEmpty()) {
356         printf("\nConstants:\n");
357         unsigned registerIndex = m_numVars;
358         size_t i = 0;
359         do {
360             printf("   r%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue(exec)).ascii());
361             ++i;
362             ++registerIndex;
363         } while (i < m_constantRegisters.size());
364     }
365
366     if (m_rareData && !m_rareData->m_unexpectedConstants.isEmpty()) {
367         printf("\nUnexpected Constants:\n");
368         size_t i = 0;
369         do {
370             printf("  k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_rareData->m_unexpectedConstants[i]).ascii());
371             ++i;
372         } while (i < m_rareData->m_unexpectedConstants.size());
373     }
374     
375     if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
376         printf("\nm_regexps:\n");
377         size_t i = 0;
378         do {
379             printf("  re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).ascii());
380             ++i;
381         } while (i < m_rareData->m_regexps.size());
382     }
383
384 #if ENABLE(JIT)
385     if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
386         printf("\nStructures:\n");
387
388     if (!m_globalResolveInfos.isEmpty()) {
389         size_t i = 0;
390         do {
391              printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isGlobalResolve));
392              ++i;
393         } while (i < m_globalResolveInfos.size());
394     }
395     if (!m_structureStubInfos.isEmpty()) {
396         size_t i = 0;
397         do {
398             printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isPropertyAccess));
399              ++i;
400         } while (i < m_structureStubInfos.size());
401     }
402 #else
403     if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
404         printf("\nStructures:\n");
405
406     if (!m_globalResolveInstructions.isEmpty()) {
407         size_t i = 0;
408         do {
409              printStructures(&m_instructions[m_globalResolveInstructions[i]]);
410              ++i;
411         } while (i < m_globalResolveInstructions.size());
412     }
413     if (!m_propertyAccessInstructions.isEmpty()) {
414         size_t i = 0;
415         do {
416             printStructures(&m_instructions[m_propertyAccessInstructions[i]]);
417              ++i;
418         } while (i < m_propertyAccessInstructions.size());
419     }
420 #endif
421
422     if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
423         printf("\nException Handlers:\n");
424         unsigned i = 0;
425         do {
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);
427             ++i;
428         } while (i < m_rareData->m_exceptionHandlers.size());
429     }
430     
431     if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
432         printf("Immediate Switch Jump Tables:\n");
433         unsigned i = 0;
434         do {
435             printf("  %1d = {\n", i);
436             int entry = 0;
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) {
439                 if (!*iter)
440                     continue;
441                 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
442             }
443             printf("      }\n");
444             ++i;
445         } while (i < m_rareData->m_immediateSwitchJumpTables.size());
446     }
447     
448     if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
449         printf("\nCharacter Switch Jump Tables:\n");
450         unsigned i = 0;
451         do {
452             printf("  %1d = {\n", i);
453             int entry = 0;
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) {
456                 if (!*iter)
457                     continue;
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);
461         }
462             printf("      }\n");
463             ++i;
464         } while (i < m_rareData->m_characterSwitchJumpTables.size());
465     }
466     
467     if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
468         printf("\nString Switch Jump Tables:\n");
469         unsigned i = 0;
470         do {
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);
475             printf("      }\n");
476             ++i;
477         } while (i < m_rareData->m_stringSwitchJumpTables.size());
478     }
479
480     printf("\n");
481 }
482
483 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
484 {
485     int location = it - begin;
486     switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
487         case op_enter: {
488             printf("[%4d] enter\n", location);
489             break;
490         }
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());
494             break;
495         }
496         case op_create_arguments: {
497             printf("[%4d] create_arguments\n", location);
498             break;
499         }
500         case op_convert_this: {
501             int r0 = (++it)->u.operand;
502             printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
503             break;
504         }
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());
509             break;
510         }
511         case op_new_object: {
512             int r0 = (++it)->u.operand;
513             printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
514             break;
515         }
516         case op_new_array: {
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);
521             break;
522         }
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());
527             break;
528         }
529         case op_mov: {
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());
533             break;
534         }
535         case op_not: {
536             printUnaryOp(location, it, "not");
537             break;
538         }
539         case op_eq: {
540             printBinaryOp(location, it, "eq");
541             break;
542         }
543         case op_eq_null: {
544             printUnaryOp(location, it, "eq_null");
545             break;
546         }
547         case op_neq: {
548             printBinaryOp(location, it, "neq");
549             break;
550         }
551         case op_neq_null: {
552             printUnaryOp(location, it, "neq_null");
553             break;
554         }
555         case op_stricteq: {
556             printBinaryOp(location, it, "stricteq");
557             break;
558         }
559         case op_nstricteq: {
560             printBinaryOp(location, it, "nstricteq");
561             break;
562         }
563         case op_less: {
564             printBinaryOp(location, it, "less");
565             break;
566         }
567         case op_lesseq: {
568             printBinaryOp(location, it, "lesseq");
569             break;
570         }
571         case op_pre_inc: {
572             int r0 = (++it)->u.operand;
573             printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
574             break;
575         }
576         case op_pre_dec: {
577             int r0 = (++it)->u.operand;
578             printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
579             break;
580         }
581         case op_post_inc: {
582             printUnaryOp(location, it, "post_inc");
583             break;
584         }
585         case op_post_dec: {
586             printUnaryOp(location, it, "post_dec");
587             break;
588         }
589         case op_to_jsnumber: {
590             printUnaryOp(location, it, "to_jsnumber");
591             break;
592         }
593         case op_negate: {
594             printUnaryOp(location, it, "negate");
595             break;
596         }
597         case op_add: {
598             printBinaryOp(location, it, "add");
599             ++it;
600             break;
601         }
602         case op_mul: {
603             printBinaryOp(location, it, "mul");
604             ++it;
605             break;
606         }
607         case op_div: {
608             printBinaryOp(location, it, "div");
609             break;
610         }
611         case op_mod: {
612             printBinaryOp(location, it, "mod");
613             break;
614         }
615         case op_sub: {
616             printBinaryOp(location, it, "sub");
617             ++it;
618             break;
619         }
620         case op_lshift: {
621             printBinaryOp(location, it, "lshift");
622             break;            
623         }
624         case op_rshift: {
625             printBinaryOp(location, it, "rshift");
626             break;
627         }
628         case op_urshift: {
629             printBinaryOp(location, it, "urshift");
630             break;
631         }
632         case op_bitand: {
633             printBinaryOp(location, it, "bitand");
634             ++it;
635             break;
636         }
637         case op_bitxor: {
638             printBinaryOp(location, it, "bitxor");
639             ++it;
640             break;
641         }
642         case op_bitor: {
643             printBinaryOp(location, it, "bitor");
644             ++it;
645             break;
646         }
647         case op_bitnot: {
648             printUnaryOp(location, it, "bitnot");
649             break;
650         }
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());
657             break;
658         }
659         case op_typeof: {
660             printUnaryOp(location, it, "typeof");
661             break;
662         }
663         case op_is_undefined: {
664             printUnaryOp(location, it, "is_undefined");
665             break;
666         }
667         case op_is_boolean: {
668             printUnaryOp(location, it, "is_boolean");
669             break;
670         }
671         case op_is_number: {
672             printUnaryOp(location, it, "is_number");
673             break;
674         }
675         case op_is_string: {
676             printUnaryOp(location, it, "is_string");
677             break;
678         }
679         case op_is_object: {
680             printUnaryOp(location, it, "is_object");
681             break;
682         }
683         case op_is_function: {
684             printUnaryOp(location, it, "is_function");
685             break;
686         }
687         case op_in: {
688             printBinaryOp(location, it, "in");
689             break;
690         }
691         case op_resolve: {
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());
695             break;
696         }
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);
702             break;
703         }
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());
709             it += 2;
710             break;
711         }
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);
717             break;
718         }
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());
724             break;
725         }
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);
731             break;
732         }
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());
738             break;
739         }
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());
744             break;
745         }
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());
751             break;
752         }
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());
758             break;
759         }
760         case op_get_by_id: {
761             printGetByIdOp(location, it, m_identifiers, "get_by_id");
762             break;
763         }
764         case op_get_by_id_self: {
765             printGetByIdOp(location, it, m_identifiers, "get_by_id_self");
766             break;
767         }
768         case op_get_by_id_self_list: {
769             printGetByIdOp(location, it, m_identifiers, "get_by_id_self_list");
770             break;
771         }
772         case op_get_by_id_proto: {
773             printGetByIdOp(location, it, m_identifiers, "get_by_id_proto");
774             break;
775         }
776         case op_get_by_id_proto_list: {
777             printGetByIdOp(location, it, m_identifiers, "op_get_by_id_proto_list");
778             break;
779         }
780         case op_get_by_id_chain: {
781             printGetByIdOp(location, it, m_identifiers, "get_by_id_chain");
782             break;
783         }
784         case op_get_by_id_generic: {
785             printGetByIdOp(location, it, m_identifiers, "get_by_id_generic");
786             break;
787         }
788         case op_get_array_length: {
789             printGetByIdOp(location, it, m_identifiers, "get_array_length");
790             break;
791         }
792         case op_get_string_length: {
793             printGetByIdOp(location, it, m_identifiers, "get_string_length");
794             break;
795         }
796         case op_put_by_id: {
797             printPutByIdOp(location, it, m_identifiers, "put_by_id");
798             break;
799         }
800         case op_put_by_id_replace: {
801             printPutByIdOp(location, it, m_identifiers, "put_by_id_replace");
802             break;
803         }
804         case op_put_by_id_transition: {
805             printPutByIdOp(location, it, m_identifiers, "put_by_id_transition");
806             break;
807         }
808         case op_put_by_id_generic: {
809             printPutByIdOp(location, it, m_identifiers, "put_by_id_generic");
810             break;
811         }
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());
817             break;
818         }
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());
824             break;
825         }
826         case op_del_by_id: {
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());
831             break;
832         }
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());
838             break;
839         }
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());
845             break;
846         }
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());
852             break;
853         }
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());
859             break;
860         }
861         case op_jmp: {
862             int offset = (++it)->u.operand;
863             printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
864             break;
865         }
866         case op_loop: {
867             int offset = (++it)->u.operand;
868             printf("[%4d] loop\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
869             break;
870         }
871         case op_jtrue: {
872             printConditionalJump(begin, it, location, "jtrue");
873             break;
874         }
875         case op_loop_if_true: {
876             printConditionalJump(begin, it, location, "loop_if_true");
877             break;
878         }
879         case op_jfalse: {
880             printConditionalJump(begin, it, location, "jfalse");
881             break;
882         }
883         case op_jeq_null: {
884             printConditionalJump(begin, it, location, "jeq_null");
885             break;
886         }
887         case op_jneq_null: {
888             printConditionalJump(begin, it, location, "jneq_null");
889             break;
890         }
891         case op_jnless: {
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));
896             break;
897         }
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));
903             break;
904         }
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));
910             break;
911         }
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());
917             break;
918         }
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());
924             break;
925         }
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());
931             break;
932         }
933         case op_new_func: {
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);
937             break;
938         }
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);
943             break;
944         }
945         case op_call: {
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);
951             break;
952         }
953         case op_call_eval: {
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);
959             break;
960         }
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());
964             break;
965         }
966         case op_tear_off_arguments: {
967             printf("[%4d] tear_off_arguments\n", location);
968             break;
969         }
970         case op_ret: {
971             int r0 = (++it)->u.operand;
972             printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
973             break;
974         }
975         case op_construct: {
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());
983             break;
984         }
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());
989             break;
990         }
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());
995             break;
996         }
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));
1002             break;
1003         }
1004         case op_push_scope: {
1005             int r0 = (++it)->u.operand;
1006             printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
1007             break;
1008         }
1009         case op_pop_scope: {
1010             printf("[%4d] pop_scope\n", location);
1011             break;
1012         }
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());
1018             break;
1019         }
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));
1024             break;
1025         }
1026         case op_catch: {
1027             int r0 = (++it)->u.operand;
1028             printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
1029             break;
1030         }
1031         case op_throw: {
1032             int r0 = (++it)->u.operand;
1033             printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
1034             break;
1035         }
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());
1041             break;
1042         }
1043         case op_jsr: {
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));
1047             break;
1048         }
1049         case op_sret: {
1050             int retAddrSrc = (++it)->u.operand;
1051             printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
1052             break;
1053         }
1054         case op_debug: {
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);
1059             break;
1060         }
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());
1064             break;
1065         }
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());
1069             break;
1070         }
1071         case op_end: {
1072             int r0 = (++it)->u.operand;
1073             printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
1074             break;
1075         }
1076     }
1077 }
1078
1079 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1080
1081 #if DUMP_CODE_BLOCK_STATISTICS
1082 static HashSet<CodeBlock*> liveCodeBlockSet;
1083 #endif
1084
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)
1094
1095 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1096     macro(regexps) \
1097     macro(functions) \
1098     macro(unexpectedConstants) \
1099     macro(exceptionHandlers) \
1100     macro(immediateSwitchJumpTables) \
1101     macro(characterSwitchJumpTables) \
1102     macro(stringSwitchJumpTables) \
1103     macro(functionRegisterInfos)
1104
1105 #define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1106     macro(expressionInfo) \
1107     macro(lineInfo) \
1108     macro(getByIdExceptionInfo) \
1109     macro(pcVector)
1110
1111 template<typename T>
1112 static size_t sizeInBytes(const Vector<T>& vector)
1113 {
1114     return vector.capacity() * sizeof(T);
1115 }
1116
1117 void CodeBlock::dumpStatistics()
1118 {
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)
1124     #undef DEFINE_VARS
1125
1126     // Non-vector data members
1127     size_t evalCodeCacheIsNotEmpty = 0;
1128
1129     size_t symbolTableIsNotEmpty = 0;
1130     size_t symbolTableTotalSize = 0;
1131
1132     size_t hasExceptionInfo = 0;
1133     size_t hasRareData = 0;
1134
1135     size_t isFunctionCode = 0;
1136     size_t isGlobalCode = 0;
1137     size_t isEvalCode = 0;
1138
1139     HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1140     for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1141         CodeBlock* codeBlock = *it;
1142
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)
1145         #undef GET_STATS
1146
1147         if (!codeBlock->m_symbolTable.isEmpty()) {
1148             symbolTableIsNotEmpty++;
1149             symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1150         }
1151
1152         if (codeBlock->m_exceptionInfo) {
1153             hasExceptionInfo++;
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)
1156             #undef GET_STATS
1157         }
1158
1159         if (codeBlock->m_rareData) {
1160             hasRareData++;
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)
1163             #undef GET_STATS
1164
1165             if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1166                 evalCodeCacheIsNotEmpty++;
1167         }
1168
1169         switch (codeBlock->codeType()) {
1170             case FunctionCode:
1171                 ++isFunctionCode;
1172                 break;
1173             case GlobalCode:
1174                 ++isGlobalCode;
1175                 break;
1176             case EvalCode:
1177                 ++isEvalCode;
1178                 break;
1179         }
1180     }
1181
1182     size_t totalSize = 0;
1183
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
1189
1190     totalSize += symbolTableTotalSize;
1191     totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1192
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());
1197
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());
1201
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());
1204
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)
1209     #undef PRINT_STATS
1210
1211     printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1212     printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1213
1214     printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1215
1216 #else
1217     printf("Dumping CodeBlock statistics is not enabled.\n");
1218 #endif
1219 }
1220
1221
1222 CodeBlock::CodeBlock(ScopeNode* ownerNode, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
1223     : m_numCalleeRegisters(0)
1224     , m_numConstants(0)
1225     , m_numVars(0)
1226     , m_numParameters(0)
1227     , m_ownerNode(ownerNode)
1228     , m_globalData(0)
1229 #ifndef NDEBUG
1230     , m_instructionCount(0)
1231 #endif
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)
1238 {
1239     ASSERT(m_source);
1240
1241 #if DUMP_CODE_BLOCK_STATISTICS
1242     liveCodeBlockSet.add(this);
1243 #endif
1244 }
1245
1246 CodeBlock::~CodeBlock()
1247 {
1248 #if !ENABLE(JIT)
1249     for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
1250         derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
1251
1252     for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1253         derefStructures(&m_instructions[m_propertyAccessInstructions[i]]);
1254 #else
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();
1258     }
1259
1260     for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1261         m_structureStubInfos[i].deref();
1262
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);
1267     }
1268
1269     unlinkCallers();
1270 #endif
1271
1272 #if DUMP_CODE_BLOCK_STATISTICS
1273     liveCodeBlockSet.remove(this);
1274 #endif
1275 }
1276
1277 #if ENABLE(JIT) 
1278 void CodeBlock::unlinkCallers()
1279 {
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();
1285     }
1286     m_linkedCallerList.clear();
1287 }
1288 #endif
1289
1290 void CodeBlock::derefStructures(Instruction* vPC) const
1291 {
1292     Interpreter* interpreter = m_globalData->interpreter;
1293
1294     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1295         vPC[4].u.structure->deref();
1296         return;
1297     }
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();
1301         return;
1302     }
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();
1306         return;
1307     }
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();
1312         return;
1313     }
1314     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1315         vPC[4].u.structure->deref();
1316         return;
1317     }
1318     if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
1319         if(vPC[4].u.structure)
1320             vPC[4].u.structure->deref();
1321         return;
1322     }
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;
1328         return;
1329     }
1330
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));
1333 }
1334
1335 void CodeBlock::refStructures(Instruction* vPC) const
1336 {
1337     Interpreter* interpreter = m_globalData->interpreter;
1338
1339     if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1340         vPC[4].u.structure->ref();
1341         return;
1342     }
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();
1346         return;
1347     }
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();
1351         return;
1352     }
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();
1357         return;
1358     }
1359     if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1360         vPC[4].u.structure->ref();
1361         return;
1362     }
1363     
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));
1366 }
1367
1368 void CodeBlock::mark()
1369 {
1370     for (size_t i = 0; i < m_constantRegisters.size(); ++i)
1371         if (!m_constantRegisters[i].marked())
1372             m_constantRegisters[i].mark();
1373
1374     for (size_t i = 0; i < m_functionExpressions.size(); ++i)
1375         m_functionExpressions[i]->body()->mark();
1376
1377     if (m_rareData) {
1378         for (size_t i = 0; i < m_rareData->m_functions.size(); ++i)
1379             m_rareData->m_functions[i]->body()->mark();
1380
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();
1384         }
1385         m_rareData->m_evalCodeCache.mark();
1386     }
1387 }
1388
1389 void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
1390 {
1391     if (m_exceptionInfo)
1392         return;
1393
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;
1405     }
1406
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());
1412             CodeBlock& newCodeBlock = newFunctionBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1413             ASSERT(newCodeBlock.m_exceptionInfo);
1414             ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1415
1416 #if ENABLE(JIT)
1417             JIT::compile(m_globalData, &newCodeBlock);
1418             ASSERT(newCodeBlock.m_jitCode.codeSize == m_jitCode.codeSize);
1419 #endif
1420
1421             m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1422             break;
1423         }
1424         case EvalCode: {
1425             EvalNode* ownerEvalNode = static_cast<EvalNode*>(m_ownerNode);
1426             RefPtr<EvalNode> newEvalBody = m_globalData->parser->reparse<EvalNode>(m_globalData, ownerEvalNode);
1427             EvalCodeBlock& newCodeBlock = newEvalBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1428             ASSERT(newCodeBlock.m_exceptionInfo);
1429             ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1430
1431 #if ENABLE(JIT)
1432             JIT::compile(m_globalData, &newCodeBlock);
1433             ASSERT(newCodeBlock.m_jitCode.codeSize == m_jitCode.codeSize);
1434 #endif
1435
1436             m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1437             break;
1438         }
1439         default:
1440             // CodeBlocks for Global code blocks are transient and therefore to not gain from 
1441             // from throwing out there exception information.
1442             ASSERT_NOT_REACHED();
1443     }
1444 }
1445
1446 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1447 {
1448     ASSERT(bytecodeOffset < m_instructionCount);
1449
1450     if (!m_rareData)
1451         return 0;
1452     
1453     Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1454     for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1455         // Handlers are ordered innermost first, so the first handler we encounter
1456         // that contains the source address is the correct handler to use.
1457         if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1458             return &exceptionHandlers[i];
1459     }
1460
1461     return 0;
1462 }
1463
1464 int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset)
1465 {
1466     ASSERT(bytecodeOffset < m_instructionCount);
1467
1468     reparseForExceptionInfoIfNecessary(callFrame);
1469     ASSERT(m_exceptionInfo);
1470
1471     if (!m_exceptionInfo->m_lineInfo.size())
1472         return m_ownerNode->source().firstLine(); // Empty function
1473
1474     int low = 0;
1475     int high = m_exceptionInfo->m_lineInfo.size();
1476     while (low < high) {
1477         int mid = low + (high - low) / 2;
1478         if (m_exceptionInfo->m_lineInfo[mid].instructionOffset <= bytecodeOffset)
1479             low = mid + 1;
1480         else
1481             high = mid;
1482     }
1483     
1484     if (!low)
1485         return m_ownerNode->source().firstLine();
1486     return m_exceptionInfo->m_lineInfo[low - 1].lineNumber;
1487 }
1488
1489 int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1490 {
1491     ASSERT(bytecodeOffset < m_instructionCount);
1492
1493     reparseForExceptionInfoIfNecessary(callFrame);
1494     ASSERT(m_exceptionInfo);
1495
1496     if (!m_exceptionInfo->m_expressionInfo.size()) {
1497         // We didn't think anything could throw.  Apparently we were wrong.
1498         startOffset = 0;
1499         endOffset = 0;
1500         divot = 0;
1501         return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1502     }
1503
1504     int low = 0;
1505     int high = m_exceptionInfo->m_expressionInfo.size();
1506     while (low < high) {
1507         int mid = low + (high - low) / 2;
1508         if (m_exceptionInfo->m_expressionInfo[mid].instructionOffset <= bytecodeOffset)
1509             low = mid + 1;
1510         else
1511             high = mid;
1512     }
1513     
1514     ASSERT(low);
1515     if (!low) {
1516         startOffset = 0;
1517         endOffset = 0;
1518         divot = 0;
1519         return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1520     }
1521
1522     startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset;
1523     endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset;
1524     divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
1525     return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1526 }
1527
1528 bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID)
1529 {
1530     ASSERT(bytecodeOffset < m_instructionCount);
1531
1532     reparseForExceptionInfoIfNecessary(callFrame);
1533     ASSERT(m_exceptionInfo);        
1534
1535     if (!m_exceptionInfo->m_getByIdExceptionInfo.size())
1536         return false;
1537
1538     int low = 0;
1539     int high = m_exceptionInfo->m_getByIdExceptionInfo.size();
1540     while (low < high) {
1541         int mid = low + (high - low) / 2;
1542         if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset)
1543             low = mid + 1;
1544         else
1545             high = mid;
1546     }
1547
1548     if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset)
1549         return false;
1550
1551     opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpConstruct ? op_construct : op_instanceof;
1552     return true;
1553 }
1554
1555 #if ENABLE(JIT)
1556 bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex)
1557 {
1558     ASSERT(bytecodeOffset < m_instructionCount);
1559
1560     if (!m_rareData || !m_rareData->m_functionRegisterInfos.size())
1561         return false;
1562
1563     int low = 0;
1564     int high = m_rareData->m_functionRegisterInfos.size();
1565     while (low < high) {
1566         int mid = low + (high - low) / 2;
1567         if (m_rareData->m_functionRegisterInfos[mid].bytecodeOffset <= bytecodeOffset)
1568             low = mid + 1;
1569         else
1570             high = mid;
1571     }
1572
1573     if (!low || m_rareData->m_functionRegisterInfos[low - 1].bytecodeOffset != bytecodeOffset)
1574         return false;
1575
1576     functionRegisterIndex = m_rareData->m_functionRegisterInfos[low - 1].functionRegisterIndex;
1577     return true;
1578 }
1579 #endif
1580
1581 #if !ENABLE(JIT)
1582 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1583 {
1584     if (m_globalResolveInstructions.isEmpty())
1585         return false;
1586
1587     int low = 0;
1588     int high = m_globalResolveInstructions.size();
1589     while (low < high) {
1590         int mid = low + (high - low) / 2;
1591         if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1592             low = mid + 1;
1593         else
1594             high = mid;
1595     }
1596
1597     if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1598         return false;
1599     return true;
1600 }
1601 #else
1602 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1603 {
1604     if (m_globalResolveInfos.isEmpty())
1605         return false;
1606
1607     int low = 0;
1608     int high = m_globalResolveInfos.size();
1609     while (low < high) {
1610         int mid = low + (high - low) / 2;
1611         if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1612             low = mid + 1;
1613         else
1614             high = mid;
1615     }
1616
1617     if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1618         return false;
1619     return true;
1620 }
1621 #endif
1622
1623 #if ENABLE(JIT)
1624 void CodeBlock::setJITCode(JITCodeRef& jitCode)
1625 {
1626     m_jitCode = jitCode;
1627 #if !ENABLE(OPCODE_SAMPLING)
1628     if (!BytecodeGenerator::dumpsGeneratedCode())
1629         m_instructions.clear();
1630 #endif
1631 }
1632 #endif
1633
1634 void CodeBlock::shrinkToFit()
1635 {
1636     m_instructions.shrinkToFit();
1637
1638 #if !ENABLE(JIT)
1639     m_propertyAccessInstructions.shrinkToFit();
1640     m_globalResolveInstructions.shrinkToFit();
1641 #else
1642     m_structureStubInfos.shrinkToFit();
1643     m_globalResolveInfos.shrinkToFit();
1644     m_callLinkInfos.shrinkToFit();
1645     m_linkedCallerList.shrinkToFit();
1646 #endif
1647
1648     m_identifiers.shrinkToFit();
1649     m_functionExpressions.shrinkToFit();
1650     m_constantRegisters.shrinkToFit();
1651
1652     if (m_exceptionInfo) {
1653         m_exceptionInfo->m_expressionInfo.shrinkToFit();
1654         m_exceptionInfo->m_lineInfo.shrinkToFit();
1655         m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit();
1656     }
1657
1658     if (m_rareData) {
1659         m_rareData->m_exceptionHandlers.shrinkToFit();
1660         m_rareData->m_functions.shrinkToFit();
1661         m_rareData->m_unexpectedConstants.shrinkToFit();
1662         m_rareData->m_regexps.shrinkToFit();
1663         m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1664         m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1665         m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1666 #if ENABLE(JIT)
1667         m_rareData->m_functionRegisterInfos.shrinkToFit();
1668 #endif
1669     }
1670 }
1671
1672 } // namespace JSC