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"
36 #include "JSFunction.h"
37 #include "JSStaticScopeObject.h"
39 #include "BytecodeGenerator.h"
41 #include <wtf/StringExtras.h>
43 #define DUMP_CODE_BLOCK_STATISTICS 0
47 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
49 static UString
escapeQuotes(const UString
& str
)
53 while ((pos
= result
.find('\"', pos
)) != UString::NotFound
) {
54 result
= makeString(result
.substr(0, pos
), "\"\\\"\"", result
.substr(pos
+ 1));
60 static UString
valueToSourceString(ExecState
* exec
, JSValue val
)
66 return makeString("\"", escapeQuotes(val
.toString(exec
)), "\"");
68 return val
.toString(exec
);
71 static CString
constantName(ExecState
* exec
, int k
, JSValue value
)
73 return makeString(valueToSourceString(exec
, value
), "(@k", UString::from(k
- FirstConstantRegisterIndex
), ")").UTF8String();
76 static CString
idName(int id0
, const Identifier
& ident
)
78 return makeString(ident
.ustring(), "(@id", UString::from(id0
), ")").UTF8String();
81 CString
CodeBlock::registerName(ExecState
* exec
, int r
) const
83 if (r
== missingThisObjectMarker())
86 if (isConstantRegisterIndex(r
))
87 return constantName(exec
, r
, getConstant(r
));
89 return makeString("r", UString::from(r
)).UTF8String();
92 static UString
regexpToSourceString(RegExp
* regExp
)
94 char postfix
[5] = { '/', 0, 0, 0, 0 };
97 postfix
[index
++] = 'g';
98 if (regExp
->ignoreCase())
99 postfix
[index
++] = 'i';
100 if (regExp
->multiline())
101 postfix
[index
] = 'm';
103 return makeString("/", regExp
->pattern(), postfix
);
106 static CString
regexpName(int re
, RegExp
* regexp
)
108 return makeString(regexpToSourceString(regexp
), "(@re", UString::from(re
), ")").UTF8String();
111 static UString
pointerToSourceString(void* p
)
113 char buffer
[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
114 snprintf(buffer
, sizeof(buffer
), "%p", p
);
118 NEVER_INLINE
static const char* debugHookName(int debugHookID
)
120 switch (static_cast<DebugHookID
>(debugHookID
)) {
121 case DidEnterCallFrame
:
122 return "didEnterCallFrame";
123 case WillLeaveCallFrame
:
124 return "willLeaveCallFrame";
125 case WillExecuteStatement
:
126 return "willExecuteStatement";
127 case WillExecuteProgram
:
128 return "willExecuteProgram";
129 case DidExecuteProgram
:
130 return "didExecuteProgram";
131 case DidReachBreakpoint
:
132 return "didReachBreakpoint";
135 ASSERT_NOT_REACHED();
139 void CodeBlock::printUnaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
141 int r0
= (++it
)->u
.operand
;
142 int r1
= (++it
)->u
.operand
;
144 printf("[%4d] %s\t\t %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
147 void CodeBlock::printBinaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
149 int r0
= (++it
)->u
.operand
;
150 int r1
= (++it
)->u
.operand
;
151 int r2
= (++it
)->u
.operand
;
152 printf("[%4d] %s\t\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
155 void CodeBlock::printConditionalJump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
&, Vector
<Instruction
>::const_iterator
& it
, int location
, const char* op
) const
157 int r0
= (++it
)->u
.operand
;
158 int offset
= (++it
)->u
.operand
;
159 printf("[%4d] %s\t\t %s, %d(->%d)\n", location
, op
, registerName(exec
, r0
).data(), offset
, location
+ offset
);
162 void CodeBlock::printGetByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
164 int r0
= (++it
)->u
.operand
;
165 int r1
= (++it
)->u
.operand
;
166 int id0
= (++it
)->u
.operand
;
167 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
171 void CodeBlock::printPutByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
173 int r0
= (++it
)->u
.operand
;
174 int id0
= (++it
)->u
.operand
;
175 int r1
= (++it
)->u
.operand
;
176 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
181 static bool isGlobalResolve(OpcodeID opcodeID
)
183 return opcodeID
== op_resolve_global
|| opcodeID
== op_resolve_global_dynamic
;
186 static bool isPropertyAccess(OpcodeID opcodeID
)
189 case op_get_by_id_self
:
190 case op_get_by_id_proto
:
191 case op_get_by_id_chain
:
192 case op_get_by_id_self_list
:
193 case op_get_by_id_proto_list
:
194 case op_put_by_id_transition
:
195 case op_put_by_id_replace
:
198 case op_get_by_id_generic
:
199 case op_put_by_id_generic
:
200 case op_get_array_length
:
201 case op_get_string_length
:
208 static unsigned instructionOffsetForNth(ExecState
* exec
, const Vector
<Instruction
>& instructions
, int nth
, bool (*predicate
)(OpcodeID
))
211 while (i
< instructions
.size()) {
212 OpcodeID currentOpcode
= exec
->interpreter()->getOpcodeID(instructions
[i
].u
.opcode
);
213 if (predicate(currentOpcode
)) {
217 i
+= opcodeLengths
[currentOpcode
];
220 ASSERT_NOT_REACHED();
224 static void printGlobalResolveInfo(const GlobalResolveInfo
& resolveInfo
, unsigned instructionOffset
)
226 printf(" [%4d] %s: %s\n", instructionOffset
, "resolve_global", pointerToSourceString(resolveInfo
.structure
).UTF8String().data());
229 static void printStructureStubInfo(const StructureStubInfo
& stubInfo
, unsigned instructionOffset
)
231 switch (stubInfo
.accessType
) {
232 case access_get_by_id_self
:
233 printf(" [%4d] %s: %s\n", instructionOffset
, "get_by_id_self", pointerToSourceString(stubInfo
.u
.getByIdSelf
.baseObjectStructure
).UTF8String().data());
235 case access_get_by_id_proto
:
236 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(stubInfo
.u
.getByIdProto
.baseObjectStructure
).UTF8String().data(), pointerToSourceString(stubInfo
.u
.getByIdProto
.prototypeStructure
).UTF8String().data());
238 case access_get_by_id_chain
:
239 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(stubInfo
.u
.getByIdChain
.baseObjectStructure
).UTF8String().data(), pointerToSourceString(stubInfo
.u
.getByIdChain
.chain
).UTF8String().data());
241 case access_get_by_id_self_list
:
242 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_self_list", pointerToSourceString(stubInfo
.u
.getByIdSelfList
.structureList
).UTF8String().data(), stubInfo
.u
.getByIdSelfList
.listSize
);
244 case access_get_by_id_proto_list
:
245 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_proto_list", pointerToSourceString(stubInfo
.u
.getByIdProtoList
.structureList
).UTF8String().data(), stubInfo
.u
.getByIdProtoList
.listSize
);
247 case access_put_by_id_transition
:
248 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(stubInfo
.u
.putByIdTransition
.previousStructure
).UTF8String().data(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.structure
).UTF8String().data(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.chain
).UTF8String().data());
250 case access_put_by_id_replace
:
251 printf(" [%4d] %s: %s\n", instructionOffset
, "put_by_id_replace", pointerToSourceString(stubInfo
.u
.putByIdReplace
.baseObjectStructure
).UTF8String().data());
253 case access_get_by_id
:
254 printf(" [%4d] %s\n", instructionOffset
, "get_by_id");
256 case access_put_by_id
:
257 printf(" [%4d] %s\n", instructionOffset
, "put_by_id");
259 case access_get_by_id_generic
:
260 printf(" [%4d] %s\n", instructionOffset
, "op_get_by_id_generic");
262 case access_put_by_id_generic
:
263 printf(" [%4d] %s\n", instructionOffset
, "op_put_by_id_generic");
265 case access_get_array_length
:
266 printf(" [%4d] %s\n", instructionOffset
, "op_get_array_length");
268 case access_get_string_length
:
269 printf(" [%4d] %s\n", instructionOffset
, "op_get_string_length");
272 ASSERT_NOT_REACHED();
277 void CodeBlock::printStructure(const char* name
, const Instruction
* vPC
, int operand
) const
279 unsigned instructionOffset
= vPC
- m_instructions
.begin();
280 printf(" [%4d] %s: %s\n", instructionOffset
, name
, pointerToSourceString(vPC
[operand
].u
.structure
).UTF8String().data());
283 void CodeBlock::printStructures(const Instruction
* vPC
) const
285 Interpreter
* interpreter
= m_globalData
->interpreter
;
286 unsigned instructionOffset
= vPC
- m_instructions
.begin();
288 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
)) {
289 printStructure("get_by_id", vPC
, 4);
292 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
293 printStructure("get_by_id_self", vPC
, 4);
296 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
297 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().data(), pointerToSourceString(vPC
[5].u
.structure
).UTF8String().data());
300 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
301 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().data(), pointerToSourceString(vPC
[5].u
.structure
).UTF8String().data(), pointerToSourceString(vPC
[6].u
.structureChain
).UTF8String().data());
304 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
305 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().data(), pointerToSourceString(vPC
[5].u
.structureChain
).UTF8String().data());
308 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
)) {
309 printStructure("put_by_id", vPC
, 4);
312 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
313 printStructure("put_by_id_replace", vPC
, 4);
316 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
)) {
317 printStructure("resolve_global", vPC
, 4);
320 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
321 printStructure("resolve_global_dynamic", vPC
, 4);
325 // These m_instructions doesn't ref Structures.
326 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
));
329 void CodeBlock::dump(ExecState
* exec
) const
331 if (m_instructions
.isEmpty()) {
332 printf("No instructions available.\n");
336 size_t instructionCount
= 0;
338 for (size_t i
= 0; i
< m_instructions
.size(); i
+= opcodeLengths
[exec
->interpreter()->getOpcodeID(m_instructions
[i
].u
.opcode
)])
341 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
342 static_cast<unsigned long>(instructionCount
),
343 static_cast<unsigned long>(m_instructions
.size() * sizeof(Instruction
)),
344 this, m_numParameters
, m_numCalleeRegisters
);
346 Vector
<Instruction
>::const_iterator begin
= m_instructions
.begin();
347 Vector
<Instruction
>::const_iterator end
= m_instructions
.end();
348 for (Vector
<Instruction
>::const_iterator it
= begin
; it
!= end
; ++it
)
349 dump(exec
, begin
, it
);
351 if (!m_identifiers
.isEmpty()) {
352 printf("\nIdentifiers:\n");
355 printf(" id%u = %s\n", static_cast<unsigned>(i
), m_identifiers
[i
].ascii());
357 } while (i
!= m_identifiers
.size());
360 if (!m_constantRegisters
.isEmpty()) {
361 printf("\nConstants:\n");
362 unsigned registerIndex
= m_numVars
;
365 printf(" k%u = %s\n", registerIndex
, valueToSourceString(exec
, m_constantRegisters
[i
].jsValue()).ascii());
368 } while (i
< m_constantRegisters
.size());
371 if (m_rareData
&& !m_rareData
->m_regexps
.isEmpty()) {
372 printf("\nm_regexps:\n");
375 printf(" re%u = %s\n", static_cast<unsigned>(i
), regexpToSourceString(m_rareData
->m_regexps
[i
].get()).ascii());
377 } while (i
< m_rareData
->m_regexps
.size());
381 if (!m_globalResolveInfos
.isEmpty() || !m_structureStubInfos
.isEmpty())
382 printf("\nStructures:\n");
384 if (!m_globalResolveInfos
.isEmpty()) {
387 printGlobalResolveInfo(m_globalResolveInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isGlobalResolve
));
389 } while (i
< m_globalResolveInfos
.size());
391 if (!m_structureStubInfos
.isEmpty()) {
394 printStructureStubInfo(m_structureStubInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isPropertyAccess
));
396 } while (i
< m_structureStubInfos
.size());
399 if (!m_globalResolveInstructions
.isEmpty() || !m_propertyAccessInstructions
.isEmpty())
400 printf("\nStructures:\n");
402 if (!m_globalResolveInstructions
.isEmpty()) {
405 printStructures(&m_instructions
[m_globalResolveInstructions
[i
]]);
407 } while (i
< m_globalResolveInstructions
.size());
409 if (!m_propertyAccessInstructions
.isEmpty()) {
412 printStructures(&m_instructions
[m_propertyAccessInstructions
[i
]]);
414 } while (i
< m_propertyAccessInstructions
.size());
418 if (m_rareData
&& !m_rareData
->m_exceptionHandlers
.isEmpty()) {
419 printf("\nException Handlers:\n");
422 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
);
424 } while (i
< m_rareData
->m_exceptionHandlers
.size());
427 if (m_rareData
&& !m_rareData
->m_immediateSwitchJumpTables
.isEmpty()) {
428 printf("Immediate Switch Jump Tables:\n");
431 printf(" %1d = {\n", i
);
433 Vector
<int32_t>::const_iterator end
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.end();
434 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
437 printf("\t\t%4d => %04d\n", entry
+ m_rareData
->m_immediateSwitchJumpTables
[i
].min
, *iter
);
441 } while (i
< m_rareData
->m_immediateSwitchJumpTables
.size());
444 if (m_rareData
&& !m_rareData
->m_characterSwitchJumpTables
.isEmpty()) {
445 printf("\nCharacter Switch Jump Tables:\n");
448 printf(" %1d = {\n", i
);
450 Vector
<int32_t>::const_iterator end
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.end();
451 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
454 ASSERT(!((i
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
) & ~0xFFFF));
455 UChar ch
= static_cast<UChar
>(entry
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
);
456 printf("\t\t\"%s\" => %04d\n", UString(&ch
, 1).ascii(), *iter
);
460 } while (i
< m_rareData
->m_characterSwitchJumpTables
.size());
463 if (m_rareData
&& !m_rareData
->m_stringSwitchJumpTables
.isEmpty()) {
464 printf("\nString Switch Jump Tables:\n");
467 printf(" %1d = {\n", i
);
468 StringJumpTable::StringOffsetTable::const_iterator end
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.end();
469 for (StringJumpTable::StringOffsetTable::const_iterator iter
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.begin(); iter
!= end
; ++iter
)
470 printf("\t\t\"%s\" => %04d\n", UString(iter
->first
).ascii(), iter
->second
.branchOffset
);
473 } while (i
< m_rareData
->m_stringSwitchJumpTables
.size());
479 void CodeBlock::dump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
) const
481 int location
= it
- begin
;
482 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
484 printf("[%4d] enter\n", location
);
487 case op_enter_with_activation
: {
488 int r0
= (++it
)->u
.operand
;
489 printf("[%4d] enter_with_activation %s\n", location
, registerName(exec
, r0
).data());
492 case op_create_arguments
: {
493 printf("[%4d] create_arguments\n", location
);
496 case op_init_arguments
: {
497 printf("[%4d] init_arguments\n", location
);
500 case op_convert_this
: {
501 int r0
= (++it
)->u
.operand
;
502 printf("[%4d] convert_this %s\n", location
, registerName(exec
, r0
).data());
505 case op_new_object
: {
506 int r0
= (++it
)->u
.operand
;
507 printf("[%4d] new_object\t %s\n", location
, registerName(exec
, r0
).data());
511 int dst
= (++it
)->u
.operand
;
512 int argv
= (++it
)->u
.operand
;
513 int argc
= (++it
)->u
.operand
;
514 printf("[%4d] new_array\t %s, %s, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, argv
).data(), argc
);
517 case op_new_regexp
: {
518 int r0
= (++it
)->u
.operand
;
519 int re0
= (++it
)->u
.operand
;
520 printf("[%4d] new_regexp\t %s, %s\n", location
, registerName(exec
, r0
).data(), regexpName(re0
, regexp(re0
)).data());
524 int r0
= (++it
)->u
.operand
;
525 int r1
= (++it
)->u
.operand
;
526 printf("[%4d] mov\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
530 printUnaryOp(exec
, location
, it
, "not");
534 printBinaryOp(exec
, location
, it
, "eq");
538 printUnaryOp(exec
, location
, it
, "eq_null");
542 printBinaryOp(exec
, location
, it
, "neq");
546 printUnaryOp(exec
, location
, it
, "neq_null");
550 printBinaryOp(exec
, location
, it
, "stricteq");
554 printBinaryOp(exec
, location
, it
, "nstricteq");
558 printBinaryOp(exec
, location
, it
, "less");
562 printBinaryOp(exec
, location
, it
, "lesseq");
566 int r0
= (++it
)->u
.operand
;
567 printf("[%4d] pre_inc\t\t %s\n", location
, registerName(exec
, r0
).data());
571 int r0
= (++it
)->u
.operand
;
572 printf("[%4d] pre_dec\t\t %s\n", location
, registerName(exec
, r0
).data());
576 printUnaryOp(exec
, location
, it
, "post_inc");
580 printUnaryOp(exec
, location
, it
, "post_dec");
583 case op_to_jsnumber
: {
584 printUnaryOp(exec
, location
, it
, "to_jsnumber");
588 printUnaryOp(exec
, location
, it
, "negate");
592 printBinaryOp(exec
, location
, it
, "add");
597 printBinaryOp(exec
, location
, it
, "mul");
602 printBinaryOp(exec
, location
, it
, "div");
607 printBinaryOp(exec
, location
, it
, "mod");
611 printBinaryOp(exec
, location
, it
, "sub");
616 printBinaryOp(exec
, location
, it
, "lshift");
620 printBinaryOp(exec
, location
, it
, "rshift");
624 printBinaryOp(exec
, location
, it
, "urshift");
628 printBinaryOp(exec
, location
, it
, "bitand");
633 printBinaryOp(exec
, location
, it
, "bitxor");
638 printBinaryOp(exec
, location
, it
, "bitor");
643 printUnaryOp(exec
, location
, it
, "bitnot");
646 case op_instanceof
: {
647 int r0
= (++it
)->u
.operand
;
648 int r1
= (++it
)->u
.operand
;
649 int r2
= (++it
)->u
.operand
;
650 int r3
= (++it
)->u
.operand
;
651 printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data(), registerName(exec
, r3
).data());
655 printUnaryOp(exec
, location
, it
, "typeof");
658 case op_is_undefined
: {
659 printUnaryOp(exec
, location
, it
, "is_undefined");
662 case op_is_boolean
: {
663 printUnaryOp(exec
, location
, it
, "is_boolean");
667 printUnaryOp(exec
, location
, it
, "is_number");
671 printUnaryOp(exec
, location
, it
, "is_string");
675 printUnaryOp(exec
, location
, it
, "is_object");
678 case op_is_function
: {
679 printUnaryOp(exec
, location
, it
, "is_function");
683 printBinaryOp(exec
, location
, it
, "in");
687 int r0
= (++it
)->u
.operand
;
688 int id0
= (++it
)->u
.operand
;
689 printf("[%4d] resolve\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
692 case op_resolve_skip
: {
693 int r0
= (++it
)->u
.operand
;
694 int id0
= (++it
)->u
.operand
;
695 int skipLevels
= (++it
)->u
.operand
;
696 printf("[%4d] resolve_skip\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), skipLevels
);
699 case op_resolve_global
: {
700 int r0
= (++it
)->u
.operand
;
701 JSValue scope
= JSValue((++it
)->u
.jsCell
);
702 int id0
= (++it
)->u
.operand
;
703 printf("[%4d] resolve_global\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), valueToSourceString(exec
, scope
).ascii(), idName(id0
, m_identifiers
[id0
]).data());
707 case op_resolve_global_dynamic
: {
708 int r0
= (++it
)->u
.operand
;
709 JSValue scope
= JSValue((++it
)->u
.jsCell
);
710 int id0
= (++it
)->u
.operand
;
711 int depth
= it
[2].u
.operand
;
712 printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location
, registerName(exec
, r0
).data(), valueToSourceString(exec
, scope
).ascii(), idName(id0
, m_identifiers
[id0
]).data(), depth
);
716 case op_get_scoped_var
: {
717 int r0
= (++it
)->u
.operand
;
718 int index
= (++it
)->u
.operand
;
719 int skipLevels
= (++it
)->u
.operand
;
720 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location
, registerName(exec
, r0
).data(), index
, skipLevels
);
723 case op_put_scoped_var
: {
724 int index
= (++it
)->u
.operand
;
725 int skipLevels
= (++it
)->u
.operand
;
726 int r0
= (++it
)->u
.operand
;
727 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location
, index
, skipLevels
, registerName(exec
, r0
).data());
730 case op_get_global_var
: {
731 int r0
= (++it
)->u
.operand
;
732 JSValue scope
= JSValue((++it
)->u
.jsCell
);
733 int index
= (++it
)->u
.operand
;
734 printf("[%4d] get_global_var\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), valueToSourceString(exec
, scope
).ascii(), index
);
737 case op_put_global_var
: {
738 JSValue scope
= JSValue((++it
)->u
.jsCell
);
739 int index
= (++it
)->u
.operand
;
740 int r0
= (++it
)->u
.operand
;
741 printf("[%4d] put_global_var\t %s, %d, %s\n", location
, valueToSourceString(exec
, scope
).ascii(), index
, registerName(exec
, r0
).data());
744 case op_resolve_base
: {
745 int r0
= (++it
)->u
.operand
;
746 int id0
= (++it
)->u
.operand
;
747 printf("[%4d] resolve_base\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
750 case op_resolve_with_base
: {
751 int r0
= (++it
)->u
.operand
;
752 int r1
= (++it
)->u
.operand
;
753 int id0
= (++it
)->u
.operand
;
754 printf("[%4d] resolve_with_base %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
758 printGetByIdOp(exec
, location
, it
, "get_by_id");
761 case op_get_by_id_self
: {
762 printGetByIdOp(exec
, location
, it
, "get_by_id_self");
765 case op_get_by_id_self_list
: {
766 printGetByIdOp(exec
, location
, it
, "get_by_id_self_list");
769 case op_get_by_id_proto
: {
770 printGetByIdOp(exec
, location
, it
, "get_by_id_proto");
773 case op_get_by_id_proto_list
: {
774 printGetByIdOp(exec
, location
, it
, "op_get_by_id_proto_list");
777 case op_get_by_id_chain
: {
778 printGetByIdOp(exec
, location
, it
, "get_by_id_chain");
781 case op_get_by_id_getter_self
: {
782 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_self");
785 case op_get_by_id_getter_self_list
: {
786 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_self_list");
789 case op_get_by_id_getter_proto
: {
790 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_proto");
793 case op_get_by_id_getter_proto_list
: {
794 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_proto_list");
797 case op_get_by_id_getter_chain
: {
798 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_chain");
801 case op_get_by_id_custom_self
: {
802 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_self");
805 case op_get_by_id_custom_self_list
: {
806 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_self_list");
809 case op_get_by_id_custom_proto
: {
810 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_proto");
813 case op_get_by_id_custom_proto_list
: {
814 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_proto_list");
817 case op_get_by_id_custom_chain
: {
818 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_chain");
821 case op_get_by_id_generic
: {
822 printGetByIdOp(exec
, location
, it
, "get_by_id_generic");
825 case op_get_array_length
: {
826 printGetByIdOp(exec
, location
, it
, "get_array_length");
829 case op_get_string_length
: {
830 printGetByIdOp(exec
, location
, it
, "get_string_length");
834 printPutByIdOp(exec
, location
, it
, "put_by_id");
837 case op_put_by_id_replace
: {
838 printPutByIdOp(exec
, location
, it
, "put_by_id_replace");
841 case op_put_by_id_transition
: {
842 printPutByIdOp(exec
, location
, it
, "put_by_id_transition");
845 case op_put_by_id_generic
: {
846 printPutByIdOp(exec
, location
, it
, "put_by_id_generic");
849 case op_put_getter
: {
850 int r0
= (++it
)->u
.operand
;
851 int id0
= (++it
)->u
.operand
;
852 int r1
= (++it
)->u
.operand
;
853 printf("[%4d] put_getter\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
856 case op_put_setter
: {
857 int r0
= (++it
)->u
.operand
;
858 int id0
= (++it
)->u
.operand
;
859 int r1
= (++it
)->u
.operand
;
860 printf("[%4d] put_setter\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
863 case op_method_check
: {
864 printf("[%4d] method_check\n", location
);
868 int r0
= (++it
)->u
.operand
;
869 int r1
= (++it
)->u
.operand
;
870 int id0
= (++it
)->u
.operand
;
871 printf("[%4d] del_by_id\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
874 case op_get_by_val
: {
875 int r0
= (++it
)->u
.operand
;
876 int r1
= (++it
)->u
.operand
;
877 int r2
= (++it
)->u
.operand
;
878 printf("[%4d] get_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
881 case op_get_by_pname
: {
882 int r0
= (++it
)->u
.operand
;
883 int r1
= (++it
)->u
.operand
;
884 int r2
= (++it
)->u
.operand
;
885 int r3
= (++it
)->u
.operand
;
886 int r4
= (++it
)->u
.operand
;
887 int r5
= (++it
)->u
.operand
;
888 printf("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data(), registerName(exec
, r3
).data(), registerName(exec
, r4
).data(), registerName(exec
, r5
).data());
891 case op_put_by_val
: {
892 int r0
= (++it
)->u
.operand
;
893 int r1
= (++it
)->u
.operand
;
894 int r2
= (++it
)->u
.operand
;
895 printf("[%4d] put_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
898 case op_del_by_val
: {
899 int r0
= (++it
)->u
.operand
;
900 int r1
= (++it
)->u
.operand
;
901 int r2
= (++it
)->u
.operand
;
902 printf("[%4d] del_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
905 case op_put_by_index
: {
906 int r0
= (++it
)->u
.operand
;
907 unsigned n0
= (++it
)->u
.operand
;
908 int r1
= (++it
)->u
.operand
;
909 printf("[%4d] put_by_index\t %s, %u, %s\n", location
, registerName(exec
, r0
).data(), n0
, registerName(exec
, r1
).data());
913 int offset
= (++it
)->u
.operand
;
914 printf("[%4d] jmp\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
918 int offset
= (++it
)->u
.operand
;
919 printf("[%4d] loop\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
923 printConditionalJump(exec
, begin
, it
, location
, "jtrue");
926 case op_loop_if_true
: {
927 printConditionalJump(exec
, begin
, it
, location
, "loop_if_true");
930 case op_loop_if_false
: {
931 printConditionalJump(exec
, begin
, it
, location
, "loop_if_false");
935 printConditionalJump(exec
, begin
, it
, location
, "jfalse");
939 printConditionalJump(exec
, begin
, it
, location
, "jeq_null");
943 printConditionalJump(exec
, begin
, it
, location
, "jneq_null");
947 int r0
= (++it
)->u
.operand
;
948 int r1
= (++it
)->u
.operand
;
949 int offset
= (++it
)->u
.operand
;
950 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
954 int r0
= (++it
)->u
.operand
;
955 int r1
= (++it
)->u
.operand
;
956 int offset
= (++it
)->u
.operand
;
957 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
961 int r0
= (++it
)->u
.operand
;
962 int r1
= (++it
)->u
.operand
;
963 int offset
= (++it
)->u
.operand
;
964 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
967 case op_loop_if_less
: {
968 int r0
= (++it
)->u
.operand
;
969 int r1
= (++it
)->u
.operand
;
970 int offset
= (++it
)->u
.operand
;
971 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
975 int r0
= (++it
)->u
.operand
;
976 int r1
= (++it
)->u
.operand
;
977 int offset
= (++it
)->u
.operand
;
978 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
982 int r0
= (++it
)->u
.operand
;
983 int r1
= (++it
)->u
.operand
;
984 int offset
= (++it
)->u
.operand
;
985 printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
988 case op_loop_if_lesseq
: {
989 int r0
= (++it
)->u
.operand
;
990 int r1
= (++it
)->u
.operand
;
991 int offset
= (++it
)->u
.operand
;
992 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
995 case op_switch_imm
: {
996 int tableIndex
= (++it
)->u
.operand
;
997 int defaultTarget
= (++it
)->u
.operand
;
998 int scrutineeRegister
= (++it
)->u
.operand
;
999 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1002 case op_switch_char
: {
1003 int tableIndex
= (++it
)->u
.operand
;
1004 int defaultTarget
= (++it
)->u
.operand
;
1005 int scrutineeRegister
= (++it
)->u
.operand
;
1006 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1009 case op_switch_string
: {
1010 int tableIndex
= (++it
)->u
.operand
;
1011 int defaultTarget
= (++it
)->u
.operand
;
1012 int scrutineeRegister
= (++it
)->u
.operand
;
1013 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1017 int r0
= (++it
)->u
.operand
;
1018 int f0
= (++it
)->u
.operand
;
1019 printf("[%4d] new_func\t\t %s, f%d\n", location
, registerName(exec
, r0
).data(), f0
);
1022 case op_new_func_exp
: {
1023 int r0
= (++it
)->u
.operand
;
1024 int f0
= (++it
)->u
.operand
;
1025 printf("[%4d] new_func_exp\t %s, f%d\n", location
, registerName(exec
, r0
).data(), f0
);
1029 int dst
= (++it
)->u
.operand
;
1030 int func
= (++it
)->u
.operand
;
1031 int argCount
= (++it
)->u
.operand
;
1032 int registerOffset
= (++it
)->u
.operand
;
1033 printf("[%4d] call\t\t %s, %s, %d, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, func
).data(), argCount
, registerOffset
);
1036 case op_call_eval
: {
1037 int dst
= (++it
)->u
.operand
;
1038 int func
= (++it
)->u
.operand
;
1039 int argCount
= (++it
)->u
.operand
;
1040 int registerOffset
= (++it
)->u
.operand
;
1041 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, func
).data(), argCount
, registerOffset
);
1044 case op_call_varargs
: {
1045 int dst
= (++it
)->u
.operand
;
1046 int func
= (++it
)->u
.operand
;
1047 int argCount
= (++it
)->u
.operand
;
1048 int registerOffset
= (++it
)->u
.operand
;
1049 printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, func
).data(), registerName(exec
, argCount
).data(), registerOffset
);
1052 case op_load_varargs
: {
1053 printUnaryOp(exec
, location
, it
, "load_varargs");
1056 case op_tear_off_activation
: {
1057 int r0
= (++it
)->u
.operand
;
1058 printf("[%4d] tear_off_activation\t %s\n", location
, registerName(exec
, r0
).data());
1061 case op_tear_off_arguments
: {
1062 printf("[%4d] tear_off_arguments\n", location
);
1066 int r0
= (++it
)->u
.operand
;
1067 printf("[%4d] ret\t\t %s\n", location
, registerName(exec
, r0
).data());
1070 case op_construct
: {
1071 int dst
= (++it
)->u
.operand
;
1072 int func
= (++it
)->u
.operand
;
1073 int argCount
= (++it
)->u
.operand
;
1074 int registerOffset
= (++it
)->u
.operand
;
1075 int proto
= (++it
)->u
.operand
;
1076 int thisRegister
= (++it
)->u
.operand
;
1077 printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location
, registerName(exec
, dst
).data(), registerName(exec
, func
).data(), argCount
, registerOffset
, registerName(exec
, proto
).data(), registerName(exec
, thisRegister
).data());
1080 case op_construct_verify
: {
1081 int r0
= (++it
)->u
.operand
;
1082 int r1
= (++it
)->u
.operand
;
1083 printf("[%4d] construct_verify\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1087 int r0
= (++it
)->u
.operand
;
1088 int r1
= (++it
)->u
.operand
;
1089 int count
= (++it
)->u
.operand
;
1090 printf("[%4d] strcat\t\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), count
);
1093 case op_to_primitive
: {
1094 int r0
= (++it
)->u
.operand
;
1095 int r1
= (++it
)->u
.operand
;
1096 printf("[%4d] to_primitive\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1099 case op_get_pnames
: {
1100 int r0
= it
[1].u
.operand
;
1101 int r1
= it
[2].u
.operand
;
1102 int r2
= it
[3].u
.operand
;
1103 int r3
= it
[4].u
.operand
;
1104 int offset
= it
[5].u
.operand
;
1105 printf("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data(), registerName(exec
, r3
).data(), offset
, location
+ offset
);
1106 it
+= OPCODE_LENGTH(op_get_pnames
) - 1;
1109 case op_next_pname
: {
1110 int dest
= it
[1].u
.operand
;
1111 int iter
= it
[4].u
.operand
;
1112 int offset
= it
[5].u
.operand
;
1113 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location
, registerName(exec
, dest
).data(), registerName(exec
, iter
).data(), offset
, location
+ offset
);
1114 it
+= OPCODE_LENGTH(op_next_pname
) - 1;
1117 case op_push_scope
: {
1118 int r0
= (++it
)->u
.operand
;
1119 printf("[%4d] push_scope\t %s\n", location
, registerName(exec
, r0
).data());
1122 case op_pop_scope
: {
1123 printf("[%4d] pop_scope\n", location
);
1126 case op_push_new_scope
: {
1127 int r0
= (++it
)->u
.operand
;
1128 int id0
= (++it
)->u
.operand
;
1129 int r1
= (++it
)->u
.operand
;
1130 printf("[%4d] push_new_scope \t%s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
1133 case op_jmp_scopes
: {
1134 int scopeDelta
= (++it
)->u
.operand
;
1135 int offset
= (++it
)->u
.operand
;
1136 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location
, scopeDelta
, offset
, location
+ offset
);
1140 int r0
= (++it
)->u
.operand
;
1141 printf("[%4d] catch\t\t %s\n", location
, registerName(exec
, r0
).data());
1145 int r0
= (++it
)->u
.operand
;
1146 printf("[%4d] throw\t\t %s\n", location
, registerName(exec
, r0
).data());
1149 case op_new_error
: {
1150 int r0
= (++it
)->u
.operand
;
1151 int errorType
= (++it
)->u
.operand
;
1152 int k0
= (++it
)->u
.operand
;
1153 printf("[%4d] new_error\t %s, %d, %s\n", location
, registerName(exec
, r0
).data(), errorType
, constantName(exec
, k0
, getConstant(k0
)).data());
1157 int retAddrDst
= (++it
)->u
.operand
;
1158 int offset
= (++it
)->u
.operand
;
1159 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location
, registerName(exec
, retAddrDst
).data(), offset
, location
+ offset
);
1163 int retAddrSrc
= (++it
)->u
.operand
;
1164 printf("[%4d] sret\t\t %s\n", location
, registerName(exec
, retAddrSrc
).data());
1168 int debugHookID
= (++it
)->u
.operand
;
1169 int firstLine
= (++it
)->u
.operand
;
1170 int lastLine
= (++it
)->u
.operand
;
1171 printf("[%4d] debug\t\t %s, %d, %d\n", location
, debugHookName(debugHookID
), firstLine
, lastLine
);
1174 case op_profile_will_call
: {
1175 int function
= (++it
)->u
.operand
;
1176 printf("[%4d] profile_will_call %s\n", location
, registerName(exec
, function
).data());
1179 case op_profile_did_call
: {
1180 int function
= (++it
)->u
.operand
;
1181 printf("[%4d] profile_did_call\t %s\n", location
, registerName(exec
, function
).data());
1185 int r0
= (++it
)->u
.operand
;
1186 printf("[%4d] end\t\t %s\n", location
, registerName(exec
, r0
).data());
1192 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1194 #if DUMP_CODE_BLOCK_STATISTICS
1195 static HashSet
<CodeBlock
*> liveCodeBlockSet
;
1198 #define FOR_EACH_MEMBER_VECTOR(macro) \
1199 macro(instructions) \
1200 macro(globalResolveInfos) \
1201 macro(structureStubInfos) \
1202 macro(callLinkInfos) \
1203 macro(linkedCallerList) \
1204 macro(identifiers) \
1205 macro(functionExpressions) \
1206 macro(constantRegisters)
1208 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1211 macro(exceptionHandlers) \
1212 macro(immediateSwitchJumpTables) \
1213 macro(characterSwitchJumpTables) \
1214 macro(stringSwitchJumpTables) \
1215 macro(functionRegisterInfos)
1217 #define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1218 macro(expressionInfo) \
1220 macro(getByIdExceptionInfo) \
1223 template<typename T
>
1224 static size_t sizeInBytes(const Vector
<T
>& vector
)
1226 return vector
.capacity() * sizeof(T
);
1229 void CodeBlock::dumpStatistics()
1231 #if DUMP_CODE_BLOCK_STATISTICS
1232 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1233 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS
)
1234 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS
)
1235 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS
)
1238 // Non-vector data members
1239 size_t evalCodeCacheIsNotEmpty
= 0;
1241 size_t symbolTableIsNotEmpty
= 0;
1242 size_t symbolTableTotalSize
= 0;
1244 size_t hasExceptionInfo
= 0;
1245 size_t hasRareData
= 0;
1247 size_t isFunctionCode
= 0;
1248 size_t isGlobalCode
= 0;
1249 size_t isEvalCode
= 0;
1251 HashSet
<CodeBlock
*>::const_iterator end
= liveCodeBlockSet
.end();
1252 for (HashSet
<CodeBlock
*>::const_iterator it
= liveCodeBlockSet
.begin(); it
!= end
; ++it
) {
1253 CodeBlock
* codeBlock
= *it
;
1255 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1256 FOR_EACH_MEMBER_VECTOR(GET_STATS
)
1259 if (!codeBlock
->m_symbolTable
.isEmpty()) {
1260 symbolTableIsNotEmpty
++;
1261 symbolTableTotalSize
+= (codeBlock
->m_symbolTable
.capacity() * (sizeof(SymbolTable::KeyType
) + sizeof(SymbolTable::MappedType
)));
1264 if (codeBlock
->m_exceptionInfo
) {
1266 #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
1267 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS
)
1271 if (codeBlock
->m_rareData
) {
1273 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1274 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS
)
1277 if (!codeBlock
->m_rareData
->m_evalCodeCache
.isEmpty())
1278 evalCodeCacheIsNotEmpty
++;
1281 switch (codeBlock
->codeType()) {
1294 size_t totalSize
= 0;
1296 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1297 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE
)
1298 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE
)
1299 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE
)
1300 #undef GET_TOTAL_SIZE
1302 totalSize
+= symbolTableTotalSize
;
1303 totalSize
+= (liveCodeBlockSet
.size() * sizeof(CodeBlock
));
1305 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet
.size());
1306 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock
));
1307 printf("Size of all CodeBlocks: %zu\n", totalSize
);
1308 printf("Average size of a CodeBlock: %zu\n", totalSize
/ liveCodeBlockSet
.size());
1310 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode
, static_cast<double>(isFunctionCode
) * 100.0 / liveCodeBlockSet
.size());
1311 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode
, static_cast<double>(isGlobalCode
) * 100.0 / liveCodeBlockSet
.size());
1312 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode
, static_cast<double>(isEvalCode
) * 100.0 / liveCodeBlockSet
.size());
1314 printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo
, static_cast<double>(hasExceptionInfo
) * 100.0 / liveCodeBlockSet
.size());
1315 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData
, static_cast<double>(hasRareData
) * 100.0 / liveCodeBlockSet
.size());
1317 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1318 FOR_EACH_MEMBER_VECTOR(PRINT_STATS
)
1319 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS
)
1320 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS
)
1323 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty
);
1324 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty
);
1326 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize
);
1329 printf("Dumping CodeBlock statistics is not enabled.\n");
1333 CodeBlock::CodeBlock(ScriptExecutable
* ownerExecutable
, CodeType codeType
, PassRefPtr
<SourceProvider
> sourceProvider
, unsigned sourceOffset
, SymbolTable
* symTab
)
1334 : m_numCalleeRegisters(0)
1336 , m_numParameters(0)
1337 , m_ownerExecutable(ownerExecutable
)
1340 , m_instructionCount(0)
1342 , m_needsFullScopeChain(ownerExecutable
->needsActivation())
1343 , m_usesEval(ownerExecutable
->usesEval())
1344 , m_usesArguments(false)
1345 , m_isNumericCompareFunction(false)
1346 , m_codeType(codeType
)
1347 , m_source(sourceProvider
)
1348 , m_sourceOffset(sourceOffset
)
1349 , m_symbolTable(symTab
)
1350 , m_exceptionInfo(new ExceptionInfo
)
1354 #if DUMP_CODE_BLOCK_STATISTICS
1355 liveCodeBlockSet
.add(this);
1359 CodeBlock::~CodeBlock()
1361 #if ENABLE(INTERPRETER)
1362 for (size_t size
= m_globalResolveInstructions
.size(), i
= 0; i
< size
; ++i
)
1363 derefStructures(&m_instructions
[m_globalResolveInstructions
[i
]]);
1365 for (size_t size
= m_propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
)
1366 derefStructures(&m_instructions
[m_propertyAccessInstructions
[i
]]);
1369 for (size_t size
= m_globalResolveInfos
.size(), i
= 0; i
< size
; ++i
) {
1370 if (m_globalResolveInfos
[i
].structure
)
1371 m_globalResolveInfos
[i
].structure
->deref();
1374 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
1375 m_structureStubInfos
[i
].deref();
1377 for (size_t size
= m_callLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1378 CallLinkInfo
* callLinkInfo
= &m_callLinkInfos
[i
];
1379 if (callLinkInfo
->isLinked())
1380 callLinkInfo
->callee
->removeCaller(callLinkInfo
);
1383 for (size_t size
= m_methodCallLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1384 if (Structure
* structure
= m_methodCallLinkInfos
[i
].cachedStructure
) {
1386 // Both members must be filled at the same time
1387 ASSERT(!!m_methodCallLinkInfos
[i
].cachedPrototypeStructure
);
1388 m_methodCallLinkInfos
[i
].cachedPrototypeStructure
->deref();
1392 #if ENABLE(JIT_OPTIMIZE_CALL)
1396 #endif // ENABLE(JIT)
1398 #if DUMP_CODE_BLOCK_STATISTICS
1399 liveCodeBlockSet
.remove(this);
1403 #if ENABLE(JIT_OPTIMIZE_CALL)
1404 void CodeBlock::unlinkCallers()
1406 size_t size
= m_linkedCallerList
.size();
1407 for (size_t i
= 0; i
< size
; ++i
) {
1408 CallLinkInfo
* currentCaller
= m_linkedCallerList
[i
];
1409 JIT::unlinkCall(currentCaller
);
1410 currentCaller
->setUnlinked();
1412 m_linkedCallerList
.clear();
1416 void CodeBlock::derefStructures(Instruction
* vPC
) const
1418 Interpreter
* interpreter
= m_globalData
->interpreter
;
1420 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_self
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_self
)) {
1421 vPC
[4].u
.structure
->deref();
1424 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_proto
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_proto
)) {
1425 vPC
[4].u
.structure
->deref();
1426 vPC
[5].u
.structure
->deref();
1429 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_chain
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_chain
)) {
1430 vPC
[4].u
.structure
->deref();
1431 vPC
[5].u
.structureChain
->deref();
1434 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1435 vPC
[4].u
.structure
->deref();
1436 vPC
[5].u
.structure
->deref();
1437 vPC
[6].u
.structureChain
->deref();
1440 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1441 vPC
[4].u
.structure
->deref();
1444 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
1445 if(vPC
[4].u
.structure
)
1446 vPC
[4].u
.structure
->deref();
1449 if ((vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto_list
))
1450 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self_list
))
1451 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_proto_list
))
1452 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_self_list
))
1453 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_proto_list
))
1454 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_self_list
))) {
1455 PolymorphicAccessStructureList
* polymorphicStructures
= vPC
[4].u
.polymorphicStructures
;
1456 polymorphicStructures
->derefStructures(vPC
[5].u
.operand
);
1457 delete polymorphicStructures
;
1461 // These instructions don't ref their Structures.
1462 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
));
1465 void CodeBlock::refStructures(Instruction
* vPC
) const
1467 Interpreter
* interpreter
= m_globalData
->interpreter
;
1469 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_self
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_self
)) {
1470 vPC
[4].u
.structure
->ref();
1473 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_proto
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_proto
)) {
1474 vPC
[4].u
.structure
->ref();
1475 vPC
[5].u
.structure
->ref();
1478 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_chain
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_chain
)) {
1479 vPC
[4].u
.structure
->ref();
1480 vPC
[5].u
.structureChain
->ref();
1483 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1484 vPC
[4].u
.structure
->ref();
1485 vPC
[5].u
.structure
->ref();
1486 vPC
[6].u
.structureChain
->ref();
1489 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1490 vPC
[4].u
.structure
->ref();
1494 // These instructions don't ref their Structures.
1495 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
));
1498 void CodeBlock::markAggregate(MarkStack
& markStack
)
1500 for (size_t i
= 0; i
< m_constantRegisters
.size(); ++i
)
1501 markStack
.append(m_constantRegisters
[i
].jsValue());
1502 for (size_t i
= 0; i
< m_functionExprs
.size(); ++i
)
1503 m_functionExprs
[i
]->markAggregate(markStack
);
1504 for (size_t i
= 0; i
< m_functionDecls
.size(); ++i
)
1505 m_functionDecls
[i
]->markAggregate(markStack
);
1508 void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame
* callFrame
)
1510 if (m_exceptionInfo
)
1513 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1514 if (m_needsFullScopeChain
) {
1515 ScopeChain
sc(scopeChain
);
1516 int scopeDelta
= sc
.localDepth();
1517 if (m_codeType
== EvalCode
)
1518 scopeDelta
-= static_cast<EvalCodeBlock
*>(this)->baseScopeDepth();
1519 else if (m_codeType
== FunctionCode
)
1520 scopeDelta
++; // Compilation of function code assumes activation is not on the scope chain yet.
1521 ASSERT(scopeDelta
>= 0);
1522 while (scopeDelta
--)
1523 scopeChain
= scopeChain
->next
;
1526 m_exceptionInfo
.set(m_ownerExecutable
->reparseExceptionInfo(m_globalData
, scopeChain
, this));
1529 HandlerInfo
* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset
)
1531 ASSERT(bytecodeOffset
< m_instructionCount
);
1536 Vector
<HandlerInfo
>& exceptionHandlers
= m_rareData
->m_exceptionHandlers
;
1537 for (size_t i
= 0; i
< exceptionHandlers
.size(); ++i
) {
1538 // Handlers are ordered innermost first, so the first handler we encounter
1539 // that contains the source address is the correct handler to use.
1540 if (exceptionHandlers
[i
].start
<= bytecodeOffset
&& exceptionHandlers
[i
].end
>= bytecodeOffset
)
1541 return &exceptionHandlers
[i
];
1547 int CodeBlock::lineNumberForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
)
1549 ASSERT(bytecodeOffset
< m_instructionCount
);
1551 reparseForExceptionInfoIfNecessary(callFrame
);
1552 ASSERT(m_exceptionInfo
);
1554 if (!m_exceptionInfo
->m_lineInfo
.size())
1555 return m_ownerExecutable
->source().firstLine(); // Empty function
1558 int high
= m_exceptionInfo
->m_lineInfo
.size();
1559 while (low
< high
) {
1560 int mid
= low
+ (high
- low
) / 2;
1561 if (m_exceptionInfo
->m_lineInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1568 return m_ownerExecutable
->source().firstLine();
1569 return m_exceptionInfo
->m_lineInfo
[low
- 1].lineNumber
;
1572 int CodeBlock::expressionRangeForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
, int& divot
, int& startOffset
, int& endOffset
)
1574 ASSERT(bytecodeOffset
< m_instructionCount
);
1576 reparseForExceptionInfoIfNecessary(callFrame
);
1577 ASSERT(m_exceptionInfo
);
1579 if (!m_exceptionInfo
->m_expressionInfo
.size()) {
1580 // We didn't think anything could throw. Apparently we were wrong.
1584 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1588 int high
= m_exceptionInfo
->m_expressionInfo
.size();
1589 while (low
< high
) {
1590 int mid
= low
+ (high
- low
) / 2;
1591 if (m_exceptionInfo
->m_expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1602 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1605 startOffset
= m_exceptionInfo
->m_expressionInfo
[low
- 1].startOffset
;
1606 endOffset
= m_exceptionInfo
->m_expressionInfo
[low
- 1].endOffset
;
1607 divot
= m_exceptionInfo
->m_expressionInfo
[low
- 1].divotPoint
+ m_sourceOffset
;
1608 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1611 bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
, OpcodeID
& opcodeID
)
1613 ASSERT(bytecodeOffset
< m_instructionCount
);
1615 reparseForExceptionInfoIfNecessary(callFrame
);
1616 ASSERT(m_exceptionInfo
);
1618 if (!m_exceptionInfo
->m_getByIdExceptionInfo
.size())
1622 int high
= m_exceptionInfo
->m_getByIdExceptionInfo
.size();
1623 while (low
< high
) {
1624 int mid
= low
+ (high
- low
) / 2;
1625 if (m_exceptionInfo
->m_getByIdExceptionInfo
[mid
].bytecodeOffset
<= bytecodeOffset
)
1631 if (!low
|| m_exceptionInfo
->m_getByIdExceptionInfo
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1634 opcodeID
= m_exceptionInfo
->m_getByIdExceptionInfo
[low
- 1].isOpConstruct
? op_construct
: op_instanceof
;
1639 bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset
, int& functionRegisterIndex
)
1641 ASSERT(bytecodeOffset
< m_instructionCount
);
1643 if (!m_rareData
|| !m_rareData
->m_functionRegisterInfos
.size())
1647 int high
= m_rareData
->m_functionRegisterInfos
.size();
1648 while (low
< high
) {
1649 int mid
= low
+ (high
- low
) / 2;
1650 if (m_rareData
->m_functionRegisterInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
1656 if (!low
|| m_rareData
->m_functionRegisterInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1659 functionRegisterIndex
= m_rareData
->m_functionRegisterInfos
[low
- 1].functionRegisterIndex
;
1664 #if ENABLE(INTERPRETER)
1665 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset
)
1667 if (m_globalResolveInstructions
.isEmpty())
1671 int high
= m_globalResolveInstructions
.size();
1672 while (low
< high
) {
1673 int mid
= low
+ (high
- low
) / 2;
1674 if (m_globalResolveInstructions
[mid
] <= bytecodeOffset
)
1680 if (!low
|| m_globalResolveInstructions
[low
- 1] != bytecodeOffset
)
1686 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset
)
1688 if (m_globalResolveInfos
.isEmpty())
1692 int high
= m_globalResolveInfos
.size();
1693 while (low
< high
) {
1694 int mid
= low
+ (high
- low
) / 2;
1695 if (m_globalResolveInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
1701 if (!low
|| m_globalResolveInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1707 void CodeBlock::shrinkToFit()
1709 m_instructions
.shrinkToFit();
1711 #if ENABLE(INTERPRETER)
1712 m_propertyAccessInstructions
.shrinkToFit();
1713 m_globalResolveInstructions
.shrinkToFit();
1716 m_structureStubInfos
.shrinkToFit();
1717 m_globalResolveInfos
.shrinkToFit();
1718 m_callLinkInfos
.shrinkToFit();
1719 m_linkedCallerList
.shrinkToFit();
1722 m_identifiers
.shrinkToFit();
1723 m_functionDecls
.shrinkToFit();
1724 m_functionExprs
.shrinkToFit();
1725 m_constantRegisters
.shrinkToFit();
1727 if (m_exceptionInfo
) {
1728 m_exceptionInfo
->m_expressionInfo
.shrinkToFit();
1729 m_exceptionInfo
->m_lineInfo
.shrinkToFit();
1730 m_exceptionInfo
->m_getByIdExceptionInfo
.shrinkToFit();
1734 m_rareData
->m_exceptionHandlers
.shrinkToFit();
1735 m_rareData
->m_regexps
.shrinkToFit();
1736 m_rareData
->m_immediateSwitchJumpTables
.shrinkToFit();
1737 m_rareData
->m_characterSwitchJumpTables
.shrinkToFit();
1738 m_rareData
->m_stringSwitchJumpTables
.shrinkToFit();
1740 m_rareData
->m_functionRegisterInfos
.shrinkToFit();