2 * Copyright (C) 2008, 2009, 2010 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"
33 #include "BytecodeGenerator.h"
35 #include "Interpreter.h"
37 #include "JSActivation.h"
38 #include "JSFunction.h"
39 #include "JSStaticScopeObject.h"
41 #include "RepatchBuffer.h"
42 #include "UStringConcatenate.h"
44 #include <wtf/StringExtras.h>
46 #define DUMP_CODE_BLOCK_STATISTICS 0
50 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
52 static UString
escapeQuotes(const UString
& str
)
56 while ((pos
= result
.find('\"', pos
)) != notFound
) {
57 result
= makeUString(result
.substringSharingImpl(0, pos
), "\"\\\"\"", result
.substringSharingImpl(pos
+ 1));
63 static UString
valueToSourceString(ExecState
* exec
, JSValue val
)
69 return makeUString("\"", escapeQuotes(val
.toString(exec
)), "\"");
71 return val
.toString(exec
);
74 static CString
constantName(ExecState
* exec
, int k
, JSValue value
)
76 return makeUString(valueToSourceString(exec
, value
), "(@k", UString::number(k
- FirstConstantRegisterIndex
), ")").utf8();
79 static CString
idName(int id0
, const Identifier
& ident
)
81 return makeUString(ident
.ustring(), "(@id", UString::number(id0
), ")").utf8();
84 CString
CodeBlock::registerName(ExecState
* exec
, int r
) const
86 if (r
== missingThisObjectMarker())
89 if (isConstantRegisterIndex(r
))
90 return constantName(exec
, r
, getConstant(r
));
92 return makeUString("r", UString::number(r
)).utf8();
95 static UString
regexpToSourceString(RegExp
* regExp
)
97 char postfix
[5] = { '/', 0, 0, 0, 0 };
100 postfix
[index
++] = 'g';
101 if (regExp
->ignoreCase())
102 postfix
[index
++] = 'i';
103 if (regExp
->multiline())
104 postfix
[index
] = 'm';
106 return makeUString("/", regExp
->pattern(), postfix
);
109 static CString
regexpName(int re
, RegExp
* regexp
)
111 return makeUString(regexpToSourceString(regexp
), "(@re", UString::number(re
), ")").utf8();
114 static UString
pointerToSourceString(void* p
)
116 char buffer
[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
117 snprintf(buffer
, sizeof(buffer
), "%p", p
);
121 NEVER_INLINE
static const char* debugHookName(int debugHookID
)
123 switch (static_cast<DebugHookID
>(debugHookID
)) {
124 case DidEnterCallFrame
:
125 return "didEnterCallFrame";
126 case WillLeaveCallFrame
:
127 return "willLeaveCallFrame";
128 case WillExecuteStatement
:
129 return "willExecuteStatement";
130 case WillExecuteProgram
:
131 return "willExecuteProgram";
132 case DidExecuteProgram
:
133 return "didExecuteProgram";
134 case DidReachBreakpoint
:
135 return "didReachBreakpoint";
138 ASSERT_NOT_REACHED();
142 void CodeBlock::printUnaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
144 int r0
= (++it
)->u
.operand
;
145 int r1
= (++it
)->u
.operand
;
147 printf("[%4d] %s\t\t %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
150 void CodeBlock::printBinaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
152 int r0
= (++it
)->u
.operand
;
153 int r1
= (++it
)->u
.operand
;
154 int r2
= (++it
)->u
.operand
;
155 printf("[%4d] %s\t\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
158 void CodeBlock::printConditionalJump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
&, Vector
<Instruction
>::const_iterator
& it
, int location
, const char* op
) const
160 int r0
= (++it
)->u
.operand
;
161 int offset
= (++it
)->u
.operand
;
162 printf("[%4d] %s\t\t %s, %d(->%d)\n", location
, op
, registerName(exec
, r0
).data(), offset
, location
+ offset
);
165 void CodeBlock::printGetByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
167 int r0
= (++it
)->u
.operand
;
168 int r1
= (++it
)->u
.operand
;
169 int id0
= (++it
)->u
.operand
;
170 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
174 void CodeBlock::printPutByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
176 int r0
= (++it
)->u
.operand
;
177 int id0
= (++it
)->u
.operand
;
178 int r1
= (++it
)->u
.operand
;
179 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
184 static bool isGlobalResolve(OpcodeID opcodeID
)
186 return opcodeID
== op_resolve_global
|| opcodeID
== op_resolve_global_dynamic
;
189 static bool isPropertyAccess(OpcodeID opcodeID
)
192 case op_get_by_id_self
:
193 case op_get_by_id_proto
:
194 case op_get_by_id_chain
:
195 case op_get_by_id_self_list
:
196 case op_get_by_id_proto_list
:
197 case op_put_by_id_transition
:
198 case op_put_by_id_replace
:
201 case op_get_by_id_generic
:
202 case op_put_by_id_generic
:
203 case op_get_array_length
:
204 case op_get_string_length
:
211 static unsigned instructionOffsetForNth(ExecState
* exec
, const Vector
<Instruction
>& instructions
, int nth
, bool (*predicate
)(OpcodeID
))
214 while (i
< instructions
.size()) {
215 OpcodeID currentOpcode
= exec
->interpreter()->getOpcodeID(instructions
[i
].u
.opcode
);
216 if (predicate(currentOpcode
)) {
220 i
+= opcodeLengths
[currentOpcode
];
223 ASSERT_NOT_REACHED();
227 static void printGlobalResolveInfo(const GlobalResolveInfo
& resolveInfo
, unsigned instructionOffset
)
229 printf(" [%4d] %s: %s\n", instructionOffset
, "resolve_global", pointerToSourceString(resolveInfo
.structure
).utf8().data());
232 static void printStructureStubInfo(const StructureStubInfo
& stubInfo
, unsigned instructionOffset
)
234 switch (stubInfo
.accessType
) {
235 case access_get_by_id_self
:
236 printf(" [%4d] %s: %s\n", instructionOffset
, "get_by_id_self", pointerToSourceString(stubInfo
.u
.getByIdSelf
.baseObjectStructure
).utf8().data());
238 case access_get_by_id_proto
:
239 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(stubInfo
.u
.getByIdProto
.baseObjectStructure
).utf8().data(), pointerToSourceString(stubInfo
.u
.getByIdProto
.prototypeStructure
).utf8().data());
241 case access_get_by_id_chain
:
242 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(stubInfo
.u
.getByIdChain
.baseObjectStructure
).utf8().data(), pointerToSourceString(stubInfo
.u
.getByIdChain
.chain
).utf8().data());
244 case access_get_by_id_self_list
:
245 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_self_list", pointerToSourceString(stubInfo
.u
.getByIdSelfList
.structureList
).utf8().data(), stubInfo
.u
.getByIdSelfList
.listSize
);
247 case access_get_by_id_proto_list
:
248 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_proto_list", pointerToSourceString(stubInfo
.u
.getByIdProtoList
.structureList
).utf8().data(), stubInfo
.u
.getByIdProtoList
.listSize
);
250 case access_put_by_id_transition
:
251 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(stubInfo
.u
.putByIdTransition
.previousStructure
).utf8().data(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.structure
).utf8().data(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.chain
).utf8().data());
253 case access_put_by_id_replace
:
254 printf(" [%4d] %s: %s\n", instructionOffset
, "put_by_id_replace", pointerToSourceString(stubInfo
.u
.putByIdReplace
.baseObjectStructure
).utf8().data());
256 case access_get_by_id
:
257 printf(" [%4d] %s\n", instructionOffset
, "get_by_id");
259 case access_put_by_id
:
260 printf(" [%4d] %s\n", instructionOffset
, "put_by_id");
262 case access_get_by_id_generic
:
263 printf(" [%4d] %s\n", instructionOffset
, "op_get_by_id_generic");
265 case access_put_by_id_generic
:
266 printf(" [%4d] %s\n", instructionOffset
, "op_put_by_id_generic");
268 case access_get_array_length
:
269 printf(" [%4d] %s\n", instructionOffset
, "op_get_array_length");
271 case access_get_string_length
:
272 printf(" [%4d] %s\n", instructionOffset
, "op_get_string_length");
275 ASSERT_NOT_REACHED();
280 void CodeBlock::printStructure(const char* name
, const Instruction
* vPC
, int operand
) const
282 unsigned instructionOffset
= vPC
- m_instructions
.begin();
283 printf(" [%4d] %s: %s\n", instructionOffset
, name
, pointerToSourceString(vPC
[operand
].u
.structure
).utf8().data());
286 void CodeBlock::printStructures(const Instruction
* vPC
) const
288 Interpreter
* interpreter
= m_globalData
->interpreter
;
289 unsigned instructionOffset
= vPC
- m_instructions
.begin();
291 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
)) {
292 printStructure("get_by_id", vPC
, 4);
295 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
296 printStructure("get_by_id_self", vPC
, 4);
299 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
300 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structure
).utf8().data());
303 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
304 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structure
).utf8().data(), pointerToSourceString(vPC
[6].u
.structureChain
).utf8().data());
307 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
308 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structureChain
).utf8().data());
311 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
)) {
312 printStructure("put_by_id", vPC
, 4);
315 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
316 printStructure("put_by_id_replace", vPC
, 4);
319 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
)) {
320 printStructure("resolve_global", vPC
, 4);
323 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
324 printStructure("resolve_global_dynamic", vPC
, 4);
328 // These m_instructions doesn't ref Structures.
329 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
));
332 void CodeBlock::dump(ExecState
* exec
) const
334 if (m_instructions
.isEmpty()) {
335 printf("No instructions available.\n");
339 size_t instructionCount
= 0;
341 for (size_t i
= 0; i
< m_instructions
.size(); i
+= opcodeLengths
[exec
->interpreter()->getOpcodeID(m_instructions
[i
].u
.opcode
)])
344 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
345 static_cast<unsigned long>(instructionCount
),
346 static_cast<unsigned long>(m_instructions
.size() * sizeof(Instruction
)),
347 this, m_numParameters
, m_numCalleeRegisters
);
349 Vector
<Instruction
>::const_iterator begin
= m_instructions
.begin();
350 Vector
<Instruction
>::const_iterator end
= m_instructions
.end();
351 for (Vector
<Instruction
>::const_iterator it
= begin
; it
!= end
; ++it
)
352 dump(exec
, begin
, it
);
354 if (!m_identifiers
.isEmpty()) {
355 printf("\nIdentifiers:\n");
358 printf(" id%u = %s\n", static_cast<unsigned>(i
), m_identifiers
[i
].ustring().utf8().data());
360 } while (i
!= m_identifiers
.size());
363 if (!m_constantRegisters
.isEmpty()) {
364 printf("\nConstants:\n");
365 unsigned registerIndex
= m_numVars
;
368 printf(" k%u = %s\n", registerIndex
, valueToSourceString(exec
, m_constantRegisters
[i
].get()).utf8().data());
371 } while (i
< m_constantRegisters
.size());
374 if (m_rareData
&& !m_rareData
->m_regexps
.isEmpty()) {
375 printf("\nm_regexps:\n");
378 printf(" re%u = %s\n", static_cast<unsigned>(i
), regexpToSourceString(m_rareData
->m_regexps
[i
].get()).utf8().data());
380 } while (i
< m_rareData
->m_regexps
.size());
384 if (!m_globalResolveInfos
.isEmpty() || !m_structureStubInfos
.isEmpty())
385 printf("\nStructures:\n");
387 if (!m_globalResolveInfos
.isEmpty()) {
390 printGlobalResolveInfo(m_globalResolveInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isGlobalResolve
));
392 } while (i
< m_globalResolveInfos
.size());
394 if (!m_structureStubInfos
.isEmpty()) {
397 printStructureStubInfo(m_structureStubInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isPropertyAccess
));
399 } while (i
< m_structureStubInfos
.size());
402 #if ENABLE(INTERPRETER)
403 if (!m_globalResolveInstructions
.isEmpty() || !m_propertyAccessInstructions
.isEmpty())
404 printf("\nStructures:\n");
406 if (!m_globalResolveInstructions
.isEmpty()) {
409 printStructures(&m_instructions
[m_globalResolveInstructions
[i
]]);
411 } while (i
< m_globalResolveInstructions
.size());
413 if (!m_propertyAccessInstructions
.isEmpty()) {
416 printStructures(&m_instructions
[m_propertyAccessInstructions
[i
]]);
418 } while (i
< m_propertyAccessInstructions
.size());
422 if (m_rareData
&& !m_rareData
->m_exceptionHandlers
.isEmpty()) {
423 printf("\nException Handlers:\n");
426 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i
+ 1, m_rareData
->m_exceptionHandlers
[i
].start
, m_rareData
->m_exceptionHandlers
[i
].end
, m_rareData
->m_exceptionHandlers
[i
].target
);
428 } while (i
< m_rareData
->m_exceptionHandlers
.size());
431 if (m_rareData
&& !m_rareData
->m_immediateSwitchJumpTables
.isEmpty()) {
432 printf("Immediate Switch Jump Tables:\n");
435 printf(" %1d = {\n", i
);
437 Vector
<int32_t>::const_iterator end
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.end();
438 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
441 printf("\t\t%4d => %04d\n", entry
+ m_rareData
->m_immediateSwitchJumpTables
[i
].min
, *iter
);
445 } while (i
< m_rareData
->m_immediateSwitchJumpTables
.size());
448 if (m_rareData
&& !m_rareData
->m_characterSwitchJumpTables
.isEmpty()) {
449 printf("\nCharacter Switch Jump Tables:\n");
452 printf(" %1d = {\n", i
);
454 Vector
<int32_t>::const_iterator end
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.end();
455 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
458 ASSERT(!((i
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
) & ~0xFFFF));
459 UChar ch
= static_cast<UChar
>(entry
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
);
460 printf("\t\t\"%s\" => %04d\n", UString(&ch
, 1).utf8().data(), *iter
);
464 } while (i
< m_rareData
->m_characterSwitchJumpTables
.size());
467 if (m_rareData
&& !m_rareData
->m_stringSwitchJumpTables
.isEmpty()) {
468 printf("\nString Switch Jump Tables:\n");
471 printf(" %1d = {\n", i
);
472 StringJumpTable::StringOffsetTable::const_iterator end
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.end();
473 for (StringJumpTable::StringOffsetTable::const_iterator iter
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.begin(); iter
!= end
; ++iter
)
474 printf("\t\t\"%s\" => %04d\n", UString(iter
->first
).utf8().data(), iter
->second
.branchOffset
);
477 } while (i
< m_rareData
->m_stringSwitchJumpTables
.size());
483 void CodeBlock::dump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
) const
485 int location
= it
- begin
;
486 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
488 printf("[%4d] enter\n", location
);
491 case op_create_activation
: {
492 int r0
= (++it
)->u
.operand
;
493 printf("[%4d] create_activation %s\n", location
, registerName(exec
, r0
).data());
496 case op_create_arguments
: {
497 int r0
= (++it
)->u
.operand
;
498 printf("[%4d] create_arguments\t %s\n", location
, registerName(exec
, r0
).data());
501 case op_init_lazy_reg
: {
502 int r0
= (++it
)->u
.operand
;
503 printf("[%4d] init_lazy_reg\t %s\n", location
, registerName(exec
, r0
).data());
506 case op_get_callee
: {
507 int r0
= (++it
)->u
.operand
;
508 printf("[%4d] op_get_callee %s\n", location
, registerName(exec
, r0
).data());
511 case op_create_this
: {
512 int r0
= (++it
)->u
.operand
;
513 int r1
= (++it
)->u
.operand
;
514 printf("[%4d] create_this %s %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
517 case op_convert_this
: {
518 int r0
= (++it
)->u
.operand
;
519 printf("[%4d] convert_this %s\n", location
, registerName(exec
, r0
).data());
522 case op_convert_this_strict
: {
523 int r0
= (++it
)->u
.operand
;
524 printf("[%4d] convert_this_strict %s\n", location
, registerName(exec
, r0
).data());
527 case op_new_object
: {
528 int r0
= (++it
)->u
.operand
;
529 printf("[%4d] new_object\t %s\n", location
, registerName(exec
, r0
).data());
533 int dst
= (++it
)->u
.operand
;
534 int argv
= (++it
)->u
.operand
;
535 int argc
= (++it
)->u
.operand
;
536 printf("[%4d] new_array\t %s, %s, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, argv
).data(), argc
);
539 case op_new_array_buffer
: {
540 int dst
= (++it
)->u
.operand
;
541 int argv
= (++it
)->u
.operand
;
542 int argc
= (++it
)->u
.operand
;
543 printf("[%4d] new_array_buffer %s, %d, %d\n", location
, registerName(exec
, dst
).data(), argv
, argc
);
546 case op_new_regexp
: {
547 int r0
= (++it
)->u
.operand
;
548 int re0
= (++it
)->u
.operand
;
549 printf("[%4d] new_regexp\t %s, %s\n", location
, registerName(exec
, r0
).data(), regexpName(re0
, regexp(re0
)).data());
553 int r0
= (++it
)->u
.operand
;
554 int r1
= (++it
)->u
.operand
;
555 printf("[%4d] mov\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
559 printUnaryOp(exec
, location
, it
, "not");
563 printBinaryOp(exec
, location
, it
, "eq");
567 printUnaryOp(exec
, location
, it
, "eq_null");
571 printBinaryOp(exec
, location
, it
, "neq");
575 printUnaryOp(exec
, location
, it
, "neq_null");
579 printBinaryOp(exec
, location
, it
, "stricteq");
583 printBinaryOp(exec
, location
, it
, "nstricteq");
587 printBinaryOp(exec
, location
, it
, "less");
591 printBinaryOp(exec
, location
, it
, "lesseq");
595 int r0
= (++it
)->u
.operand
;
596 printf("[%4d] pre_inc\t\t %s\n", location
, registerName(exec
, r0
).data());
600 int r0
= (++it
)->u
.operand
;
601 printf("[%4d] pre_dec\t\t %s\n", location
, registerName(exec
, r0
).data());
605 printUnaryOp(exec
, location
, it
, "post_inc");
609 printUnaryOp(exec
, location
, it
, "post_dec");
612 case op_to_jsnumber
: {
613 printUnaryOp(exec
, location
, it
, "to_jsnumber");
617 printUnaryOp(exec
, location
, it
, "negate");
621 printBinaryOp(exec
, location
, it
, "add");
626 printBinaryOp(exec
, location
, it
, "mul");
631 printBinaryOp(exec
, location
, it
, "div");
636 printBinaryOp(exec
, location
, it
, "mod");
640 printBinaryOp(exec
, location
, it
, "sub");
645 printBinaryOp(exec
, location
, it
, "lshift");
649 printBinaryOp(exec
, location
, it
, "rshift");
653 printBinaryOp(exec
, location
, it
, "urshift");
657 printBinaryOp(exec
, location
, it
, "bitand");
662 printBinaryOp(exec
, location
, it
, "bitxor");
667 printBinaryOp(exec
, location
, it
, "bitor");
672 printUnaryOp(exec
, location
, it
, "bitnot");
675 case op_check_has_instance
: {
676 int base
= (++it
)->u
.operand
;
677 printf("[%4d] check_has_instance\t\t %s\n", location
, registerName(exec
, base
).data());
680 case op_instanceof
: {
681 int r0
= (++it
)->u
.operand
;
682 int r1
= (++it
)->u
.operand
;
683 int r2
= (++it
)->u
.operand
;
684 int r3
= (++it
)->u
.operand
;
685 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());
689 printUnaryOp(exec
, location
, it
, "typeof");
692 case op_is_undefined
: {
693 printUnaryOp(exec
, location
, it
, "is_undefined");
696 case op_is_boolean
: {
697 printUnaryOp(exec
, location
, it
, "is_boolean");
701 printUnaryOp(exec
, location
, it
, "is_number");
705 printUnaryOp(exec
, location
, it
, "is_string");
709 printUnaryOp(exec
, location
, it
, "is_object");
712 case op_is_function
: {
713 printUnaryOp(exec
, location
, it
, "is_function");
717 printBinaryOp(exec
, location
, it
, "in");
721 int r0
= (++it
)->u
.operand
;
722 int id0
= (++it
)->u
.operand
;
723 printf("[%4d] resolve\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
726 case op_resolve_skip
: {
727 int r0
= (++it
)->u
.operand
;
728 int id0
= (++it
)->u
.operand
;
729 int skipLevels
= (++it
)->u
.operand
;
730 printf("[%4d] resolve_skip\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), skipLevels
);
733 case op_resolve_global
: {
734 int r0
= (++it
)->u
.operand
;
735 int id0
= (++it
)->u
.operand
;
736 printf("[%4d] resolve_global\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
740 case op_resolve_global_dynamic
: {
741 int r0
= (++it
)->u
.operand
;
742 int id0
= (++it
)->u
.operand
;
743 JSValue scope
= JSValue((++it
)->u
.jsCell
.get());
745 int depth
= (++it
)->u
.operand
;
746 printf("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location
, registerName(exec
, r0
).data(), valueToSourceString(exec
, scope
).utf8().data(), idName(id0
, m_identifiers
[id0
]).data(), depth
);
749 case op_get_scoped_var
: {
750 int r0
= (++it
)->u
.operand
;
751 int index
= (++it
)->u
.operand
;
752 int skipLevels
= (++it
)->u
.operand
;
753 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location
, registerName(exec
, r0
).data(), index
, skipLevels
);
756 case op_put_scoped_var
: {
757 int index
= (++it
)->u
.operand
;
758 int skipLevels
= (++it
)->u
.operand
;
759 int r0
= (++it
)->u
.operand
;
760 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location
, index
, skipLevels
, registerName(exec
, r0
).data());
763 case op_get_global_var
: {
764 int r0
= (++it
)->u
.operand
;
765 int index
= (++it
)->u
.operand
;
766 printf("[%4d] get_global_var\t %s, %d\n", location
, registerName(exec
, r0
).data(), index
);
769 case op_put_global_var
: {
770 int index
= (++it
)->u
.operand
;
771 int r0
= (++it
)->u
.operand
;
772 printf("[%4d] put_global_var\t %d, %s\n", location
, index
, registerName(exec
, r0
).data());
775 case op_resolve_base
: {
776 int r0
= (++it
)->u
.operand
;
777 int id0
= (++it
)->u
.operand
;
778 int isStrict
= (++it
)->u
.operand
;
779 printf("[%4d] resolve_base%s\t %s, %s\n", location
, isStrict
? "_strict" : "", registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
782 case op_ensure_property_exists
: {
783 int r0
= (++it
)->u
.operand
;
784 int id0
= (++it
)->u
.operand
;
785 printf("[%4d] ensure_property_exists\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
788 case op_resolve_with_base
: {
789 int r0
= (++it
)->u
.operand
;
790 int r1
= (++it
)->u
.operand
;
791 int id0
= (++it
)->u
.operand
;
792 printf("[%4d] resolve_with_base %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
796 printGetByIdOp(exec
, location
, it
, "get_by_id");
799 case op_get_by_id_self
: {
800 printGetByIdOp(exec
, location
, it
, "get_by_id_self");
803 case op_get_by_id_self_list
: {
804 printGetByIdOp(exec
, location
, it
, "get_by_id_self_list");
807 case op_get_by_id_proto
: {
808 printGetByIdOp(exec
, location
, it
, "get_by_id_proto");
811 case op_get_by_id_proto_list
: {
812 printGetByIdOp(exec
, location
, it
, "op_get_by_id_proto_list");
815 case op_get_by_id_chain
: {
816 printGetByIdOp(exec
, location
, it
, "get_by_id_chain");
819 case op_get_by_id_getter_self
: {
820 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_self");
823 case op_get_by_id_getter_self_list
: {
824 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_self_list");
827 case op_get_by_id_getter_proto
: {
828 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_proto");
831 case op_get_by_id_getter_proto_list
: {
832 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_proto_list");
835 case op_get_by_id_getter_chain
: {
836 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_chain");
839 case op_get_by_id_custom_self
: {
840 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_self");
843 case op_get_by_id_custom_self_list
: {
844 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_self_list");
847 case op_get_by_id_custom_proto
: {
848 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_proto");
851 case op_get_by_id_custom_proto_list
: {
852 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_proto_list");
855 case op_get_by_id_custom_chain
: {
856 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_chain");
859 case op_get_by_id_generic
: {
860 printGetByIdOp(exec
, location
, it
, "get_by_id_generic");
863 case op_get_array_length
: {
864 printGetByIdOp(exec
, location
, it
, "get_array_length");
867 case op_get_string_length
: {
868 printGetByIdOp(exec
, location
, it
, "get_string_length");
871 case op_get_arguments_length
: {
872 printUnaryOp(exec
, location
, it
, "get_arguments_length");
877 printPutByIdOp(exec
, location
, it
, "put_by_id");
880 case op_put_by_id_replace
: {
881 printPutByIdOp(exec
, location
, it
, "put_by_id_replace");
884 case op_put_by_id_transition
: {
885 printPutByIdOp(exec
, location
, it
, "put_by_id_transition");
888 case op_put_by_id_generic
: {
889 printPutByIdOp(exec
, location
, it
, "put_by_id_generic");
892 case op_put_getter
: {
893 int r0
= (++it
)->u
.operand
;
894 int id0
= (++it
)->u
.operand
;
895 int r1
= (++it
)->u
.operand
;
896 printf("[%4d] put_getter\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
899 case op_put_setter
: {
900 int r0
= (++it
)->u
.operand
;
901 int id0
= (++it
)->u
.operand
;
902 int r1
= (++it
)->u
.operand
;
903 printf("[%4d] put_setter\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
906 case op_method_check
: {
907 printf("[%4d] method_check\n", location
);
911 int r0
= (++it
)->u
.operand
;
912 int r1
= (++it
)->u
.operand
;
913 int id0
= (++it
)->u
.operand
;
914 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());
917 case op_get_by_val
: {
918 int r0
= (++it
)->u
.operand
;
919 int r1
= (++it
)->u
.operand
;
920 int r2
= (++it
)->u
.operand
;
921 printf("[%4d] get_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
924 case op_get_argument_by_val
: {
925 int r0
= (++it
)->u
.operand
;
926 int r1
= (++it
)->u
.operand
;
927 int r2
= (++it
)->u
.operand
;
928 printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
931 case op_get_by_pname
: {
932 int r0
= (++it
)->u
.operand
;
933 int r1
= (++it
)->u
.operand
;
934 int r2
= (++it
)->u
.operand
;
935 int r3
= (++it
)->u
.operand
;
936 int r4
= (++it
)->u
.operand
;
937 int r5
= (++it
)->u
.operand
;
938 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());
941 case op_put_by_val
: {
942 int r0
= (++it
)->u
.operand
;
943 int r1
= (++it
)->u
.operand
;
944 int r2
= (++it
)->u
.operand
;
945 printf("[%4d] put_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
948 case op_del_by_val
: {
949 int r0
= (++it
)->u
.operand
;
950 int r1
= (++it
)->u
.operand
;
951 int r2
= (++it
)->u
.operand
;
952 printf("[%4d] del_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
955 case op_put_by_index
: {
956 int r0
= (++it
)->u
.operand
;
957 unsigned n0
= (++it
)->u
.operand
;
958 int r1
= (++it
)->u
.operand
;
959 printf("[%4d] put_by_index\t %s, %u, %s\n", location
, registerName(exec
, r0
).data(), n0
, registerName(exec
, r1
).data());
963 int offset
= (++it
)->u
.operand
;
964 printf("[%4d] jmp\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
968 int offset
= (++it
)->u
.operand
;
969 printf("[%4d] loop\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
973 printConditionalJump(exec
, begin
, it
, location
, "jtrue");
976 case op_loop_if_true
: {
977 printConditionalJump(exec
, begin
, it
, location
, "loop_if_true");
980 case op_loop_if_false
: {
981 printConditionalJump(exec
, begin
, it
, location
, "loop_if_false");
985 printConditionalJump(exec
, begin
, it
, location
, "jfalse");
989 printConditionalJump(exec
, begin
, it
, location
, "jeq_null");
993 printConditionalJump(exec
, begin
, it
, location
, "jneq_null");
997 int r0
= (++it
)->u
.operand
;
998 int r1
= (++it
)->u
.operand
;
999 int offset
= (++it
)->u
.operand
;
1000 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1004 int r0
= (++it
)->u
.operand
;
1005 int r1
= (++it
)->u
.operand
;
1006 int offset
= (++it
)->u
.operand
;
1007 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1011 int r0
= (++it
)->u
.operand
;
1012 int r1
= (++it
)->u
.operand
;
1013 int offset
= (++it
)->u
.operand
;
1014 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1017 case op_loop_if_less
: {
1018 int r0
= (++it
)->u
.operand
;
1019 int r1
= (++it
)->u
.operand
;
1020 int offset
= (++it
)->u
.operand
;
1021 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1025 int r0
= (++it
)->u
.operand
;
1026 int r1
= (++it
)->u
.operand
;
1027 int offset
= (++it
)->u
.operand
;
1028 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1032 int r0
= (++it
)->u
.operand
;
1033 int r1
= (++it
)->u
.operand
;
1034 int offset
= (++it
)->u
.operand
;
1035 printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1038 case op_loop_if_lesseq
: {
1039 int r0
= (++it
)->u
.operand
;
1040 int r1
= (++it
)->u
.operand
;
1041 int offset
= (++it
)->u
.operand
;
1042 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1045 case op_switch_imm
: {
1046 int tableIndex
= (++it
)->u
.operand
;
1047 int defaultTarget
= (++it
)->u
.operand
;
1048 int scrutineeRegister
= (++it
)->u
.operand
;
1049 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1052 case op_switch_char
: {
1053 int tableIndex
= (++it
)->u
.operand
;
1054 int defaultTarget
= (++it
)->u
.operand
;
1055 int scrutineeRegister
= (++it
)->u
.operand
;
1056 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1059 case op_switch_string
: {
1060 int tableIndex
= (++it
)->u
.operand
;
1061 int defaultTarget
= (++it
)->u
.operand
;
1062 int scrutineeRegister
= (++it
)->u
.operand
;
1063 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1067 int r0
= (++it
)->u
.operand
;
1068 int f0
= (++it
)->u
.operand
;
1069 int shouldCheck
= (++it
)->u
.operand
;
1070 printf("[%4d] new_func\t\t %s, f%d, %s\n", location
, registerName(exec
, r0
).data(), f0
, shouldCheck
? "<Checked>" : "<Unchecked>");
1073 case op_new_func_exp
: {
1074 int r0
= (++it
)->u
.operand
;
1075 int f0
= (++it
)->u
.operand
;
1076 printf("[%4d] new_func_exp\t %s, f%d\n", location
, registerName(exec
, r0
).data(), f0
);
1080 int func
= (++it
)->u
.operand
;
1081 int argCount
= (++it
)->u
.operand
;
1082 int registerOffset
= (++it
)->u
.operand
;
1083 printf("[%4d] call\t\t %s, %d, %d\n", location
, registerName(exec
, func
).data(), argCount
, registerOffset
);
1086 case op_call_eval
: {
1087 int func
= (++it
)->u
.operand
;
1088 int argCount
= (++it
)->u
.operand
;
1089 int registerOffset
= (++it
)->u
.operand
;
1090 printf("[%4d] call_eval\t %s, %d, %d\n", location
, registerName(exec
, func
).data(), argCount
, registerOffset
);
1093 case op_call_varargs
: {
1094 int func
= (++it
)->u
.operand
;
1095 int argCount
= (++it
)->u
.operand
;
1096 int registerOffset
= (++it
)->u
.operand
;
1097 printf("[%4d] call_varargs\t %s, %s, %d\n", location
, registerName(exec
, func
).data(), registerName(exec
, argCount
).data(), registerOffset
);
1100 case op_load_varargs
: {
1101 printUnaryOp(exec
, location
, it
, "load_varargs");
1104 case op_tear_off_activation
: {
1105 int r0
= (++it
)->u
.operand
;
1106 int r1
= (++it
)->u
.operand
;
1107 printf("[%4d] tear_off_activation\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1110 case op_tear_off_arguments
: {
1111 int r0
= (++it
)->u
.operand
;
1112 printf("[%4d] tear_off_arguments\t %s\n", location
, registerName(exec
, r0
).data());
1116 int r0
= (++it
)->u
.operand
;
1117 printf("[%4d] ret\t\t %s\n", location
, registerName(exec
, r0
).data());
1120 case op_call_put_result
: {
1121 int r0
= (++it
)->u
.operand
;
1122 printf("[%4d] op_call_put_result\t\t %s\n", location
, registerName(exec
, r0
).data());
1125 case op_ret_object_or_this
: {
1126 int r0
= (++it
)->u
.operand
;
1127 int r1
= (++it
)->u
.operand
;
1128 printf("[%4d] constructor_ret\t\t %s %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1131 case op_construct
: {
1132 int func
= (++it
)->u
.operand
;
1133 int argCount
= (++it
)->u
.operand
;
1134 int registerOffset
= (++it
)->u
.operand
;
1135 printf("[%4d] construct\t %s, %d, %d\n", location
, registerName(exec
, func
).data(), argCount
, registerOffset
);
1139 int r0
= (++it
)->u
.operand
;
1140 int r1
= (++it
)->u
.operand
;
1141 int count
= (++it
)->u
.operand
;
1142 printf("[%4d] strcat\t\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), count
);
1145 case op_to_primitive
: {
1146 int r0
= (++it
)->u
.operand
;
1147 int r1
= (++it
)->u
.operand
;
1148 printf("[%4d] to_primitive\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1151 case op_get_pnames
: {
1152 int r0
= it
[1].u
.operand
;
1153 int r1
= it
[2].u
.operand
;
1154 int r2
= it
[3].u
.operand
;
1155 int r3
= it
[4].u
.operand
;
1156 int offset
= it
[5].u
.operand
;
1157 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
);
1158 it
+= OPCODE_LENGTH(op_get_pnames
) - 1;
1161 case op_next_pname
: {
1162 int dest
= it
[1].u
.operand
;
1163 int base
= it
[2].u
.operand
;
1164 int i
= it
[3].u
.operand
;
1165 int size
= it
[4].u
.operand
;
1166 int iter
= it
[5].u
.operand
;
1167 int offset
= it
[6].u
.operand
;
1168 printf("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)\n", location
, registerName(exec
, dest
).data(), registerName(exec
, base
).data(), registerName(exec
, i
).data(), registerName(exec
, size
).data(), registerName(exec
, iter
).data(), offset
, location
+ offset
);
1169 it
+= OPCODE_LENGTH(op_next_pname
) - 1;
1172 case op_push_scope
: {
1173 int r0
= (++it
)->u
.operand
;
1174 printf("[%4d] push_scope\t %s\n", location
, registerName(exec
, r0
).data());
1177 case op_pop_scope
: {
1178 printf("[%4d] pop_scope\n", location
);
1181 case op_push_new_scope
: {
1182 int r0
= (++it
)->u
.operand
;
1183 int id0
= (++it
)->u
.operand
;
1184 int r1
= (++it
)->u
.operand
;
1185 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());
1188 case op_jmp_scopes
: {
1189 int scopeDelta
= (++it
)->u
.operand
;
1190 int offset
= (++it
)->u
.operand
;
1191 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location
, scopeDelta
, offset
, location
+ offset
);
1195 int r0
= (++it
)->u
.operand
;
1196 printf("[%4d] catch\t\t %s\n", location
, registerName(exec
, r0
).data());
1200 int r0
= (++it
)->u
.operand
;
1201 printf("[%4d] throw\t\t %s\n", location
, registerName(exec
, r0
).data());
1204 case op_throw_reference_error
: {
1205 int k0
= (++it
)->u
.operand
;
1206 printf("[%4d] throw_reference_error\t %s\n", location
, constantName(exec
, k0
, getConstant(k0
)).data());
1210 int retAddrDst
= (++it
)->u
.operand
;
1211 int offset
= (++it
)->u
.operand
;
1212 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location
, registerName(exec
, retAddrDst
).data(), offset
, location
+ offset
);
1216 int retAddrSrc
= (++it
)->u
.operand
;
1217 printf("[%4d] sret\t\t %s\n", location
, registerName(exec
, retAddrSrc
).data());
1221 int debugHookID
= (++it
)->u
.operand
;
1222 int firstLine
= (++it
)->u
.operand
;
1223 int lastLine
= (++it
)->u
.operand
;
1224 printf("[%4d] debug\t\t %s, %d, %d\n", location
, debugHookName(debugHookID
), firstLine
, lastLine
);
1227 case op_profile_will_call
: {
1228 int function
= (++it
)->u
.operand
;
1229 printf("[%4d] profile_will_call %s\n", location
, registerName(exec
, function
).data());
1232 case op_profile_did_call
: {
1233 int function
= (++it
)->u
.operand
;
1234 printf("[%4d] profile_did_call\t %s\n", location
, registerName(exec
, function
).data());
1238 int r0
= (++it
)->u
.operand
;
1239 printf("[%4d] end\t\t %s\n", location
, registerName(exec
, r0
).data());
1245 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1247 #if DUMP_CODE_BLOCK_STATISTICS
1248 static HashSet
<CodeBlock
*> liveCodeBlockSet
;
1251 #define FOR_EACH_MEMBER_VECTOR(macro) \
1252 macro(instructions) \
1253 macro(globalResolveInfos) \
1254 macro(structureStubInfos) \
1255 macro(callLinkInfos) \
1256 macro(linkedCallerList) \
1257 macro(identifiers) \
1258 macro(functionExpressions) \
1259 macro(constantRegisters)
1261 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1264 macro(exceptionHandlers) \
1265 macro(immediateSwitchJumpTables) \
1266 macro(characterSwitchJumpTables) \
1267 macro(stringSwitchJumpTables) \
1268 macro(evalCodeCache) \
1269 macro(expressionInfo) \
1271 macro(callReturnIndexVector)
1273 template<typename T
>
1274 static size_t sizeInBytes(const Vector
<T
>& vector
)
1276 return vector
.capacity() * sizeof(T
);
1279 void CodeBlock::dumpStatistics()
1281 #if DUMP_CODE_BLOCK_STATISTICS
1282 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1283 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS
)
1284 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS
)
1287 // Non-vector data members
1288 size_t evalCodeCacheIsNotEmpty
= 0;
1290 size_t symbolTableIsNotEmpty
= 0;
1291 size_t symbolTableTotalSize
= 0;
1293 size_t hasRareData
= 0;
1295 size_t isFunctionCode
= 0;
1296 size_t isGlobalCode
= 0;
1297 size_t isEvalCode
= 0;
1299 HashSet
<CodeBlock
*>::const_iterator end
= liveCodeBlockSet
.end();
1300 for (HashSet
<CodeBlock
*>::const_iterator it
= liveCodeBlockSet
.begin(); it
!= end
; ++it
) {
1301 CodeBlock
* codeBlock
= *it
;
1303 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1304 FOR_EACH_MEMBER_VECTOR(GET_STATS
)
1307 if (!codeBlock
->m_symbolTable
.isEmpty()) {
1308 symbolTableIsNotEmpty
++;
1309 symbolTableTotalSize
+= (codeBlock
->m_symbolTable
.capacity() * (sizeof(SymbolTable::KeyType
) + sizeof(SymbolTable::MappedType
)));
1312 if (codeBlock
->m_rareData
) {
1314 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1315 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS
)
1318 if (!codeBlock
->m_rareData
->m_evalCodeCache
.isEmpty())
1319 evalCodeCacheIsNotEmpty
++;
1322 switch (codeBlock
->codeType()) {
1335 size_t totalSize
= 0;
1337 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1338 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE
)
1339 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE
)
1340 #undef GET_TOTAL_SIZE
1342 totalSize
+= symbolTableTotalSize
;
1343 totalSize
+= (liveCodeBlockSet
.size() * sizeof(CodeBlock
));
1345 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet
.size());
1346 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock
));
1347 printf("Size of all CodeBlocks: %zu\n", totalSize
);
1348 printf("Average size of a CodeBlock: %zu\n", totalSize
/ liveCodeBlockSet
.size());
1350 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode
, static_cast<double>(isFunctionCode
) * 100.0 / liveCodeBlockSet
.size());
1351 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode
, static_cast<double>(isGlobalCode
) * 100.0 / liveCodeBlockSet
.size());
1352 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode
, static_cast<double>(isEvalCode
) * 100.0 / liveCodeBlockSet
.size());
1354 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData
, static_cast<double>(hasRareData
) * 100.0 / liveCodeBlockSet
.size());
1356 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1357 FOR_EACH_MEMBER_VECTOR(PRINT_STATS
)
1358 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS
)
1361 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty
);
1362 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty
);
1364 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize
);
1367 printf("Dumping CodeBlock statistics is not enabled.\n");
1371 CodeBlock::CodeBlock(ScriptExecutable
* ownerExecutable
, CodeType codeType
, JSGlobalObject
*globalObject
, PassRefPtr
<SourceProvider
> sourceProvider
, unsigned sourceOffset
, SymbolTable
* symTab
, bool isConstructor
)
1372 : m_globalObject(globalObject
->globalData(), ownerExecutable
, globalObject
)
1373 , m_heap(&m_globalObject
->globalData().heap
)
1374 , m_numCalleeRegisters(0)
1376 , m_numParameters(0)
1377 , m_isConstructor(isConstructor
)
1378 , m_ownerExecutable(globalObject
->globalData(), ownerExecutable
, ownerExecutable
)
1381 , m_instructionCount(0)
1383 , m_argumentsRegister(-1)
1384 , m_needsFullScopeChain(ownerExecutable
->needsActivation())
1385 , m_usesEval(ownerExecutable
->usesEval())
1386 , m_isNumericCompareFunction(false)
1387 , m_isStrictMode(ownerExecutable
->isStrictMode())
1388 , m_codeType(codeType
)
1389 , m_source(sourceProvider
)
1390 , m_sourceOffset(sourceOffset
)
1391 , m_symbolTable(symTab
)
1395 #if DUMP_CODE_BLOCK_STATISTICS
1396 liveCodeBlockSet
.add(this);
1400 CodeBlock::~CodeBlock()
1403 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
1404 m_structureStubInfos
[i
].deref();
1405 #endif // ENABLE(JIT)
1407 #if DUMP_CODE_BLOCK_STATISTICS
1408 liveCodeBlockSet
.remove(this);
1412 void CodeBlock::visitStructures(SlotVisitor
& visitor
, Instruction
* vPC
) const
1414 Interpreter
* interpreter
= m_globalData
->interpreter
;
1416 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
) && vPC
[4].u
.structure
) {
1417 visitor
.append(&vPC
[4].u
.structure
);
1421 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
)) {
1422 visitor
.append(&vPC
[4].u
.structure
);
1425 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
)) {
1426 visitor
.append(&vPC
[4].u
.structure
);
1427 visitor
.append(&vPC
[5].u
.structure
);
1430 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
)) {
1431 visitor
.append(&vPC
[4].u
.structure
);
1432 visitor
.append(&vPC
[5].u
.structureChain
);
1435 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1436 visitor
.append(&vPC
[4].u
.structure
);
1437 visitor
.append(&vPC
[5].u
.structure
);
1438 visitor
.append(&vPC
[6].u
.structureChain
);
1441 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
) && vPC
[4].u
.structure
) {
1442 visitor
.append(&vPC
[4].u
.structure
);
1445 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1446 visitor
.append(&vPC
[4].u
.structure
);
1449 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
1450 if (vPC
[3].u
.structure
)
1451 visitor
.append(&vPC
[3].u
.structure
);
1454 if ((vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto_list
))
1455 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self_list
))
1456 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_proto_list
))
1457 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_getter_self_list
))
1458 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_proto_list
))
1459 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_custom_self_list
))) {
1460 PolymorphicAccessStructureList
* polymorphicStructures
= vPC
[4].u
.polymorphicStructures
;
1461 polymorphicStructures
->visitAggregate(visitor
, vPC
[5].u
.operand
);
1462 delete polymorphicStructures
;
1466 // These instructions don't ref their Structures.
1467 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
));
1470 void EvalCodeCache::visitAggregate(SlotVisitor
& visitor
)
1472 EvalCacheMap::iterator end
= m_cacheMap
.end();
1473 for (EvalCacheMap::iterator ptr
= m_cacheMap
.begin(); ptr
!= end
; ++ptr
)
1474 visitor
.append(&ptr
->second
);
1477 void CodeBlock::visitAggregate(SlotVisitor
& visitor
)
1479 visitor
.append(&m_globalObject
);
1480 visitor
.append(&m_ownerExecutable
);
1482 m_rareData
->m_evalCodeCache
.visitAggregate(visitor
);
1483 size_t regExpCount
= m_rareData
->m_regexps
.size();
1484 WriteBarrier
<RegExp
>* regexps
= m_rareData
->m_regexps
.data();
1485 for (size_t i
= 0; i
< regExpCount
; i
++)
1486 visitor
.append(regexps
+ i
);
1488 visitor
.appendValues(m_constantRegisters
.data(), m_constantRegisters
.size());
1489 for (size_t i
= 0; i
< m_functionExprs
.size(); ++i
)
1490 visitor
.append(&m_functionExprs
[i
]);
1491 for (size_t i
= 0; i
< m_functionDecls
.size(); ++i
)
1492 visitor
.append(&m_functionDecls
[i
]);
1493 #if ENABLE(JIT_OPTIMIZE_CALL)
1494 if (visitor
.shouldUnlinkCalls())
1496 for (unsigned i
= 0; i
< numberOfCallLinkInfos(); ++i
)
1497 if (callLinkInfo(i
).isLinked())
1498 visitor
.append(&callLinkInfo(i
).callee
);
1500 #if ENABLE(INTERPRETER)
1501 for (size_t size
= m_propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
)
1502 visitStructures(visitor
, &m_instructions
[m_propertyAccessInstructions
[i
]]);
1503 for (size_t size
= m_globalResolveInstructions
.size(), i
= 0; i
< size
; ++i
)
1504 visitStructures(visitor
, &m_instructions
[m_globalResolveInstructions
[i
]]);
1507 for (size_t size
= m_globalResolveInfos
.size(), i
= 0; i
< size
; ++i
) {
1508 if (m_globalResolveInfos
[i
].structure
)
1509 visitor
.append(&m_globalResolveInfos
[i
].structure
);
1512 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
1513 m_structureStubInfos
[i
].visitAggregate(visitor
);
1515 for (size_t size
= m_methodCallLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1516 if (m_methodCallLinkInfos
[i
].cachedStructure
) {
1517 // Both members must be filled at the same time
1518 visitor
.append(&m_methodCallLinkInfos
[i
].cachedStructure
);
1519 ASSERT(!!m_methodCallLinkInfos
[i
].cachedPrototypeStructure
);
1520 visitor
.append(&m_methodCallLinkInfos
[i
].cachedPrototypeStructure
);
1521 visitor
.append(&m_methodCallLinkInfos
[i
].cachedFunction
);
1522 visitor
.append(&m_methodCallLinkInfos
[i
].cachedPrototype
);
1528 HandlerInfo
* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset
)
1530 ASSERT(bytecodeOffset
< m_instructionCount
);
1535 Vector
<HandlerInfo
>& exceptionHandlers
= m_rareData
->m_exceptionHandlers
;
1536 for (size_t i
= 0; i
< exceptionHandlers
.size(); ++i
) {
1537 // Handlers are ordered innermost first, so the first handler we encounter
1538 // that contains the source address is the correct handler to use.
1539 if (exceptionHandlers
[i
].start
<= bytecodeOffset
&& exceptionHandlers
[i
].end
>= bytecodeOffset
)
1540 return &exceptionHandlers
[i
];
1546 int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
1548 ASSERT(bytecodeOffset
< m_instructionCount
);
1551 return m_ownerExecutable
->source().firstLine();
1553 Vector
<LineInfo
>& lineInfo
= m_rareData
->m_lineInfo
;
1556 int high
= lineInfo
.size();
1557 while (low
< high
) {
1558 int mid
= low
+ (high
- low
) / 2;
1559 if (lineInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1566 return m_ownerExecutable
->source().firstLine();
1567 return lineInfo
[low
- 1].lineNumber
;
1570 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
, int& divot
, int& startOffset
, int& endOffset
)
1572 ASSERT(bytecodeOffset
< m_instructionCount
);
1581 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_rareData
->m_expressionInfo
;
1584 int high
= expressionInfo
.size();
1585 while (low
< high
) {
1586 int mid
= low
+ (high
- low
) / 2;
1587 if (expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1601 startOffset
= expressionInfo
[low
- 1].startOffset
;
1602 endOffset
= expressionInfo
[low
- 1].endOffset
;
1603 divot
= expressionInfo
[low
- 1].divotPoint
+ m_sourceOffset
;
1607 #if ENABLE(INTERPRETER)
1608 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset
)
1610 if (m_globalResolveInstructions
.isEmpty())
1614 int high
= m_globalResolveInstructions
.size();
1615 while (low
< high
) {
1616 int mid
= low
+ (high
- low
) / 2;
1617 if (m_globalResolveInstructions
[mid
] <= bytecodeOffset
)
1623 if (!low
|| m_globalResolveInstructions
[low
- 1] != bytecodeOffset
)
1629 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset
)
1631 if (m_globalResolveInfos
.isEmpty())
1635 int high
= m_globalResolveInfos
.size();
1636 while (low
< high
) {
1637 int mid
= low
+ (high
- low
) / 2;
1638 if (m_globalResolveInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
1644 if (!low
|| m_globalResolveInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1650 void CodeBlock::shrinkToFit()
1652 m_instructions
.shrinkToFit();
1654 #if ENABLE(INTERPRETER)
1655 m_propertyAccessInstructions
.shrinkToFit();
1656 m_globalResolveInstructions
.shrinkToFit();
1659 m_structureStubInfos
.shrinkToFit();
1660 m_globalResolveInfos
.shrinkToFit();
1661 m_callLinkInfos
.shrinkToFit();
1664 m_identifiers
.shrinkToFit();
1665 m_functionDecls
.shrinkToFit();
1666 m_functionExprs
.shrinkToFit();
1667 m_constantRegisters
.shrinkToFit();
1670 m_rareData
->m_exceptionHandlers
.shrinkToFit();
1671 m_rareData
->m_regexps
.shrinkToFit();
1672 m_rareData
->m_immediateSwitchJumpTables
.shrinkToFit();
1673 m_rareData
->m_characterSwitchJumpTables
.shrinkToFit();
1674 m_rareData
->m_stringSwitchJumpTables
.shrinkToFit();
1675 m_rareData
->m_expressionInfo
.shrinkToFit();
1676 m_rareData
->m_lineInfo
.shrinkToFit();
1680 void CodeBlock::createActivation(CallFrame
* callFrame
)
1682 ASSERT(codeType() == FunctionCode
);
1683 ASSERT(needsFullScopeChain());
1684 ASSERT(!callFrame
->uncheckedR(activationRegister()).jsValue());
1685 JSActivation
* activation
= new (callFrame
) JSActivation(callFrame
, static_cast<FunctionExecutable
*>(ownerExecutable()));
1686 callFrame
->uncheckedR(activationRegister()) = JSValue(activation
);
1687 callFrame
->setScopeChain(callFrame
->scopeChain()->push(activation
));
1691 void CodeBlock::unlinkCalls()
1693 if (!(m_callLinkInfos
.size() || m_methodCallLinkInfos
.size()))
1695 if (!m_globalData
->canUseJIT())
1697 RepatchBuffer
repatchBuffer(this);
1698 for (size_t i
= 0; i
< m_callLinkInfos
.size(); i
++) {
1699 if (!m_callLinkInfos
[i
].isLinked())
1701 repatchBuffer
.relink(m_callLinkInfos
[i
].callReturnLocation
, m_callLinkInfos
[i
].isCall
? m_globalData
->jitStubs
->ctiVirtualCallLink() : m_globalData
->jitStubs
->ctiVirtualConstructLink());
1702 m_callLinkInfos
[i
].unlink();
1707 void CodeBlock::clearEvalCache()
1711 m_rareData
->m_evalCodeCache
.clear();