2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "CodeBlock.h"
35 #include "Interpreter.h"
37 #include "BytecodeGenerator.h"
39 #include <wtf/StringExtras.h>
41 #define DUMP_CODE_BLOCK_STATISTICS 0
45 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
47 static UString
escapeQuotes(const UString
& str
)
51 while ((pos
= result
.find('\"', pos
)) >= 0) {
52 result
= result
.substr(0, pos
) + "\"\\\"\"" + result
.substr(pos
+ 1);
58 static UString
valueToSourceString(ExecState
* exec
, JSValue val
)
65 result
+= escapeQuotes(val
.toString(exec
)) + "\"";
69 return val
.toString(exec
);
72 static CString
registerName(int r
)
74 if (r
== missingThisObjectMarker())
77 return (UString("r") + UString::from(r
)).UTF8String();
80 static CString
constantName(ExecState
* exec
, int k
, JSValue value
)
82 return (valueToSourceString(exec
, value
) + "(@k" + UString::from(k
) + ")").UTF8String();
85 static CString
idName(int id0
, const Identifier
& ident
)
87 return (ident
.ustring() + "(@id" + UString::from(id0
) +")").UTF8String();
90 static UString
regexpToSourceString(RegExp
* regExp
)
92 UString pattern
= UString("/") + regExp
->pattern() + "/";
95 if (regExp
->ignoreCase())
97 if (regExp
->multiline())
103 static CString
regexpName(int re
, RegExp
* regexp
)
105 return (regexpToSourceString(regexp
) + "(@re" + UString::from(re
) + ")").UTF8String();
108 static UString
pointerToSourceString(void* p
)
110 char buffer
[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
111 snprintf(buffer
, sizeof(buffer
), "%p", p
);
115 NEVER_INLINE
static const char* debugHookName(int debugHookID
)
117 switch (static_cast<DebugHookID
>(debugHookID
)) {
118 case DidEnterCallFrame
:
119 return "didEnterCallFrame";
120 case WillLeaveCallFrame
:
121 return "willLeaveCallFrame";
122 case WillExecuteStatement
:
123 return "willExecuteStatement";
124 case WillExecuteProgram
:
125 return "willExecuteProgram";
126 case DidExecuteProgram
:
127 return "didExecuteProgram";
128 case DidReachBreakpoint
:
129 return "didReachBreakpoint";
132 ASSERT_NOT_REACHED();
136 static int locationForOffset(const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
, int offset
)
138 return it
- begin
+ offset
;
141 static void printUnaryOp(int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
)
143 int r0
= (++it
)->u
.operand
;
144 int r1
= (++it
)->u
.operand
;
146 printf("[%4d] %s\t\t %s, %s\n", location
, op
, registerName(r0
).c_str(), registerName(r1
).c_str());
149 static void printBinaryOp(int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
)
151 int r0
= (++it
)->u
.operand
;
152 int r1
= (++it
)->u
.operand
;
153 int r2
= (++it
)->u
.operand
;
154 printf("[%4d] %s\t\t %s, %s, %s\n", location
, op
, registerName(r0
).c_str(), registerName(r1
).c_str(), registerName(r2
).c_str());
157 static void printConditionalJump(const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
, int location
, const char* op
)
159 int r0
= (++it
)->u
.operand
;
160 int offset
= (++it
)->u
.operand
;
161 printf("[%4d] %s\t\t %s, %d(->%d)\n", location
, op
, registerName(r0
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
164 static void printGetByIdOp(int location
, Vector
<Instruction
>::const_iterator
& it
, const Vector
<Identifier
>& m_identifiers
, const char* op
)
166 int r0
= (++it
)->u
.operand
;
167 int r1
= (++it
)->u
.operand
;
168 int id0
= (++it
)->u
.operand
;
169 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(r0
).c_str(), registerName(r1
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str());
173 static void printPutByIdOp(int location
, Vector
<Instruction
>::const_iterator
& it
, const Vector
<Identifier
>& m_identifiers
, const char* op
)
175 int r0
= (++it
)->u
.operand
;
176 int id0
= (++it
)->u
.operand
;
177 int r1
= (++it
)->u
.operand
;
178 printf("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str(), registerName(r1
).c_str());
183 static bool isGlobalResolve(OpcodeID opcodeID
)
185 return opcodeID
== op_resolve_global
;
188 static bool isPropertyAccess(OpcodeID opcodeID
)
191 case op_get_by_id_self
:
192 case op_get_by_id_proto
:
193 case op_get_by_id_chain
:
194 case op_get_by_id_self_list
:
195 case op_get_by_id_proto_list
:
196 case op_put_by_id_transition
:
197 case op_put_by_id_replace
:
200 case op_get_by_id_generic
:
201 case op_put_by_id_generic
:
202 case op_get_array_length
:
203 case op_get_string_length
:
210 static unsigned instructionOffsetForNth(ExecState
* exec
, const Vector
<Instruction
>& instructions
, int nth
, bool (*predicate
)(OpcodeID
))
213 while (i
< instructions
.size()) {
214 OpcodeID currentOpcode
= exec
->interpreter()->getOpcodeID(instructions
[i
].u
.opcode
);
215 if (predicate(currentOpcode
)) {
219 i
+= opcodeLengths
[currentOpcode
];
222 ASSERT_NOT_REACHED();
226 static void printGlobalResolveInfo(const GlobalResolveInfo
& resolveInfo
, unsigned instructionOffset
)
228 printf(" [%4d] %s: %s\n", instructionOffset
, "resolve_global", pointerToSourceString(resolveInfo
.structure
).UTF8String().c_str());
231 static void printStructureStubInfo(const StructureStubInfo
& stubInfo
, unsigned instructionOffset
)
233 switch (stubInfo
.opcodeID
) {
234 case op_get_by_id_self
:
235 printf(" [%4d] %s: %s\n", instructionOffset
, "get_by_id_self", pointerToSourceString(stubInfo
.u
.getByIdSelf
.baseObjectStructure
).UTF8String().c_str());
237 case op_get_by_id_proto
:
238 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(stubInfo
.u
.getByIdProto
.baseObjectStructure
).UTF8String().c_str(), pointerToSourceString(stubInfo
.u
.getByIdProto
.prototypeStructure
).UTF8String().c_str());
240 case op_get_by_id_chain
:
241 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(stubInfo
.u
.getByIdChain
.baseObjectStructure
).UTF8String().c_str(), pointerToSourceString(stubInfo
.u
.getByIdChain
.chain
).UTF8String().c_str());
243 case op_get_by_id_self_list
:
244 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_self_list", pointerToSourceString(stubInfo
.u
.getByIdSelfList
.structureList
).UTF8String().c_str(), stubInfo
.u
.getByIdSelfList
.listSize
);
246 case op_get_by_id_proto_list
:
247 printf(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_proto_list", pointerToSourceString(stubInfo
.u
.getByIdProtoList
.structureList
).UTF8String().c_str(), stubInfo
.u
.getByIdProtoList
.listSize
);
249 case op_put_by_id_transition
:
250 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(stubInfo
.u
.putByIdTransition
.previousStructure
).UTF8String().c_str(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.structure
).UTF8String().c_str(), pointerToSourceString(stubInfo
.u
.putByIdTransition
.chain
).UTF8String().c_str());
252 case op_put_by_id_replace
:
253 printf(" [%4d] %s: %s\n", instructionOffset
, "put_by_id_replace", pointerToSourceString(stubInfo
.u
.putByIdReplace
.baseObjectStructure
).UTF8String().c_str());
256 printf(" [%4d] %s\n", instructionOffset
, "get_by_id");
259 printf(" [%4d] %s\n", instructionOffset
, "put_by_id");
261 case op_get_by_id_generic
:
262 printf(" [%4d] %s\n", instructionOffset
, "op_get_by_id_generic");
264 case op_put_by_id_generic
:
265 printf(" [%4d] %s\n", instructionOffset
, "op_put_by_id_generic");
267 case op_get_array_length
:
268 printf(" [%4d] %s\n", instructionOffset
, "op_get_array_length");
270 case op_get_string_length
:
271 printf(" [%4d] %s\n", instructionOffset
, "op_get_string_length");
274 ASSERT_NOT_REACHED();
279 void CodeBlock::printStructure(const char* name
, const Instruction
* vPC
, int operand
) const
281 unsigned instructionOffset
= vPC
- m_instructions
.begin();
282 printf(" [%4d] %s: %s\n", instructionOffset
, name
, pointerToSourceString(vPC
[operand
].u
.structure
).UTF8String().c_str());
285 void CodeBlock::printStructures(const Instruction
* vPC
) const
287 Interpreter
* interpreter
= m_globalData
->interpreter
;
288 unsigned instructionOffset
= vPC
- m_instructions
.begin();
290 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
)) {
291 printStructure("get_by_id", vPC
, 4);
294 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
295 printStructure("get_by_id_self", vPC
, 4);
298 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
299 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().c_str(), pointerToSourceString(vPC
[5].u
.structure
).UTF8String().c_str());
302 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
303 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().c_str(), pointerToSourceString(vPC
[5].u
.structure
).UTF8String().c_str(), pointerToSourceString(vPC
[6].u
.structureChain
).UTF8String().c_str());
306 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
307 printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(vPC
[4].u
.structure
).UTF8String().c_str(), pointerToSourceString(vPC
[5].u
.structureChain
).UTF8String().c_str());
310 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
)) {
311 printStructure("put_by_id", vPC
, 4);
314 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
315 printStructure("put_by_id_replace", vPC
, 4);
318 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
)) {
319 printStructure("resolve_global", vPC
, 4);
323 // These m_instructions doesn't ref Structures.
324 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
));
327 void CodeBlock::dump(ExecState
* exec
) const
329 if (m_instructions
.isEmpty()) {
330 printf("No instructions available.\n");
334 size_t instructionCount
= 0;
336 for (size_t i
= 0; i
< m_instructions
.size(); i
+= opcodeLengths
[exec
->interpreter()->getOpcodeID(m_instructions
[i
].u
.opcode
)])
339 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
340 static_cast<unsigned long>(instructionCount
),
341 static_cast<unsigned long>(m_instructions
.size() * sizeof(Instruction
)),
342 this, m_numParameters
, m_numCalleeRegisters
);
344 Vector
<Instruction
>::const_iterator begin
= m_instructions
.begin();
345 Vector
<Instruction
>::const_iterator end
= m_instructions
.end();
346 for (Vector
<Instruction
>::const_iterator it
= begin
; it
!= end
; ++it
)
347 dump(exec
, begin
, it
);
349 if (!m_identifiers
.isEmpty()) {
350 printf("\nIdentifiers:\n");
353 printf(" id%u = %s\n", static_cast<unsigned>(i
), m_identifiers
[i
].ascii());
355 } while (i
!= m_identifiers
.size());
358 if (!m_constantRegisters
.isEmpty()) {
359 printf("\nConstants:\n");
360 unsigned registerIndex
= m_numVars
;
363 printf(" r%u = %s\n", registerIndex
, valueToSourceString(exec
, m_constantRegisters
[i
].jsValue()).ascii());
366 } while (i
< m_constantRegisters
.size());
369 if (m_rareData
&& !m_rareData
->m_regexps
.isEmpty()) {
370 printf("\nm_regexps:\n");
373 printf(" re%u = %s\n", static_cast<unsigned>(i
), regexpToSourceString(m_rareData
->m_regexps
[i
].get()).ascii());
375 } while (i
< m_rareData
->m_regexps
.size());
379 if (!m_globalResolveInfos
.isEmpty() || !m_structureStubInfos
.isEmpty())
380 printf("\nStructures:\n");
382 if (!m_globalResolveInfos
.isEmpty()) {
385 printGlobalResolveInfo(m_globalResolveInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isGlobalResolve
));
387 } while (i
< m_globalResolveInfos
.size());
389 if (!m_structureStubInfos
.isEmpty()) {
392 printStructureStubInfo(m_structureStubInfos
[i
], instructionOffsetForNth(exec
, m_instructions
, i
+ 1, isPropertyAccess
));
394 } while (i
< m_structureStubInfos
.size());
397 if (!m_globalResolveInstructions
.isEmpty() || !m_propertyAccessInstructions
.isEmpty())
398 printf("\nStructures:\n");
400 if (!m_globalResolveInstructions
.isEmpty()) {
403 printStructures(&m_instructions
[m_globalResolveInstructions
[i
]]);
405 } while (i
< m_globalResolveInstructions
.size());
407 if (!m_propertyAccessInstructions
.isEmpty()) {
410 printStructures(&m_instructions
[m_propertyAccessInstructions
[i
]]);
412 } while (i
< m_propertyAccessInstructions
.size());
416 if (m_rareData
&& !m_rareData
->m_exceptionHandlers
.isEmpty()) {
417 printf("\nException Handlers:\n");
420 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
);
422 } while (i
< m_rareData
->m_exceptionHandlers
.size());
425 if (m_rareData
&& !m_rareData
->m_immediateSwitchJumpTables
.isEmpty()) {
426 printf("Immediate Switch Jump Tables:\n");
429 printf(" %1d = {\n", i
);
431 Vector
<int32_t>::const_iterator end
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.end();
432 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
435 printf("\t\t%4d => %04d\n", entry
+ m_rareData
->m_immediateSwitchJumpTables
[i
].min
, *iter
);
439 } while (i
< m_rareData
->m_immediateSwitchJumpTables
.size());
442 if (m_rareData
&& !m_rareData
->m_characterSwitchJumpTables
.isEmpty()) {
443 printf("\nCharacter Switch Jump Tables:\n");
446 printf(" %1d = {\n", i
);
448 Vector
<int32_t>::const_iterator end
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.end();
449 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
452 ASSERT(!((i
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
) & ~0xFFFF));
453 UChar ch
= static_cast<UChar
>(entry
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
);
454 printf("\t\t\"%s\" => %04d\n", UString(&ch
, 1).ascii(), *iter
);
458 } while (i
< m_rareData
->m_characterSwitchJumpTables
.size());
461 if (m_rareData
&& !m_rareData
->m_stringSwitchJumpTables
.isEmpty()) {
462 printf("\nString Switch Jump Tables:\n");
465 printf(" %1d = {\n", i
);
466 StringJumpTable::StringOffsetTable::const_iterator end
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.end();
467 for (StringJumpTable::StringOffsetTable::const_iterator iter
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.begin(); iter
!= end
; ++iter
)
468 printf("\t\t\"%s\" => %04d\n", UString(iter
->first
).ascii(), iter
->second
.branchOffset
);
471 } while (i
< m_rareData
->m_stringSwitchJumpTables
.size());
477 void CodeBlock::dump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
) const
479 int location
= it
- begin
;
480 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
482 printf("[%4d] enter\n", location
);
485 case op_enter_with_activation
: {
486 int r0
= (++it
)->u
.operand
;
487 printf("[%4d] enter_with_activation %s\n", location
, registerName(r0
).c_str());
490 case op_create_arguments
: {
491 printf("[%4d] create_arguments\n", location
);
494 case op_init_arguments
: {
495 printf("[%4d] init_arguments\n", location
);
498 case op_convert_this
: {
499 int r0
= (++it
)->u
.operand
;
500 printf("[%4d] convert_this %s\n", location
, registerName(r0
).c_str());
503 case op_new_object
: {
504 int r0
= (++it
)->u
.operand
;
505 printf("[%4d] new_object\t %s\n", location
, registerName(r0
).c_str());
509 int dst
= (++it
)->u
.operand
;
510 int argv
= (++it
)->u
.operand
;
511 int argc
= (++it
)->u
.operand
;
512 printf("[%4d] new_array\t %s, %s, %d\n", location
, registerName(dst
).c_str(), registerName(argv
).c_str(), argc
);
515 case op_new_regexp
: {
516 int r0
= (++it
)->u
.operand
;
517 int re0
= (++it
)->u
.operand
;
518 printf("[%4d] new_regexp\t %s, %s\n", location
, registerName(r0
).c_str(), regexpName(re0
, regexp(re0
)).c_str());
522 int r0
= (++it
)->u
.operand
;
523 int r1
= (++it
)->u
.operand
;
524 printf("[%4d] mov\t\t %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str());
528 printUnaryOp(location
, it
, "not");
532 printBinaryOp(location
, it
, "eq");
536 printUnaryOp(location
, it
, "eq_null");
540 printBinaryOp(location
, it
, "neq");
544 printUnaryOp(location
, it
, "neq_null");
548 printBinaryOp(location
, it
, "stricteq");
552 printBinaryOp(location
, it
, "nstricteq");
556 printBinaryOp(location
, it
, "less");
560 printBinaryOp(location
, it
, "lesseq");
564 int r0
= (++it
)->u
.operand
;
565 printf("[%4d] pre_inc\t\t %s\n", location
, registerName(r0
).c_str());
569 int r0
= (++it
)->u
.operand
;
570 printf("[%4d] pre_dec\t\t %s\n", location
, registerName(r0
).c_str());
574 printUnaryOp(location
, it
, "post_inc");
578 printUnaryOp(location
, it
, "post_dec");
581 case op_to_jsnumber
: {
582 printUnaryOp(location
, it
, "to_jsnumber");
586 printUnaryOp(location
, it
, "negate");
590 printBinaryOp(location
, it
, "add");
595 printBinaryOp(location
, it
, "mul");
600 printBinaryOp(location
, it
, "div");
605 printBinaryOp(location
, it
, "mod");
609 printBinaryOp(location
, it
, "sub");
614 printBinaryOp(location
, it
, "lshift");
618 printBinaryOp(location
, it
, "rshift");
622 printBinaryOp(location
, it
, "urshift");
626 printBinaryOp(location
, it
, "bitand");
631 printBinaryOp(location
, it
, "bitxor");
636 printBinaryOp(location
, it
, "bitor");
641 printUnaryOp(location
, it
, "bitnot");
644 case op_instanceof
: {
645 int r0
= (++it
)->u
.operand
;
646 int r1
= (++it
)->u
.operand
;
647 int r2
= (++it
)->u
.operand
;
648 int r3
= (++it
)->u
.operand
;
649 printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), registerName(r2
).c_str(), registerName(r3
).c_str());
653 printUnaryOp(location
, it
, "typeof");
656 case op_is_undefined
: {
657 printUnaryOp(location
, it
, "is_undefined");
660 case op_is_boolean
: {
661 printUnaryOp(location
, it
, "is_boolean");
665 printUnaryOp(location
, it
, "is_number");
669 printUnaryOp(location
, it
, "is_string");
673 printUnaryOp(location
, it
, "is_object");
676 case op_is_function
: {
677 printUnaryOp(location
, it
, "is_function");
681 printBinaryOp(location
, it
, "in");
685 int r0
= (++it
)->u
.operand
;
686 int id0
= (++it
)->u
.operand
;
687 printf("[%4d] resolve\t\t %s, %s\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str());
690 case op_resolve_skip
: {
691 int r0
= (++it
)->u
.operand
;
692 int id0
= (++it
)->u
.operand
;
693 int skipLevels
= (++it
)->u
.operand
;
694 printf("[%4d] resolve_skip\t %s, %s, %d\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str(), skipLevels
);
697 case op_resolve_global
: {
698 int r0
= (++it
)->u
.operand
;
699 JSValue scope
= JSValue((++it
)->u
.jsCell
);
700 int id0
= (++it
)->u
.operand
;
701 printf("[%4d] resolve_global\t %s, %s, %s\n", location
, registerName(r0
).c_str(), valueToSourceString(exec
, scope
).ascii(), idName(id0
, m_identifiers
[id0
]).c_str());
705 case op_get_scoped_var
: {
706 int r0
= (++it
)->u
.operand
;
707 int index
= (++it
)->u
.operand
;
708 int skipLevels
= (++it
)->u
.operand
;
709 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location
, registerName(r0
).c_str(), index
, skipLevels
);
712 case op_put_scoped_var
: {
713 int index
= (++it
)->u
.operand
;
714 int skipLevels
= (++it
)->u
.operand
;
715 int r0
= (++it
)->u
.operand
;
716 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location
, index
, skipLevels
, registerName(r0
).c_str());
719 case op_get_global_var
: {
720 int r0
= (++it
)->u
.operand
;
721 JSValue scope
= JSValue((++it
)->u
.jsCell
);
722 int index
= (++it
)->u
.operand
;
723 printf("[%4d] get_global_var\t %s, %s, %d\n", location
, registerName(r0
).c_str(), valueToSourceString(exec
, scope
).ascii(), index
);
726 case op_put_global_var
: {
727 JSValue scope
= JSValue((++it
)->u
.jsCell
);
728 int index
= (++it
)->u
.operand
;
729 int r0
= (++it
)->u
.operand
;
730 printf("[%4d] put_global_var\t %s, %d, %s\n", location
, valueToSourceString(exec
, scope
).ascii(), index
, registerName(r0
).c_str());
733 case op_resolve_base
: {
734 int r0
= (++it
)->u
.operand
;
735 int id0
= (++it
)->u
.operand
;
736 printf("[%4d] resolve_base\t %s, %s\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str());
739 case op_resolve_with_base
: {
740 int r0
= (++it
)->u
.operand
;
741 int r1
= (++it
)->u
.operand
;
742 int id0
= (++it
)->u
.operand
;
743 printf("[%4d] resolve_with_base %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str());
747 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id");
750 case op_get_by_id_self
: {
751 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id_self");
754 case op_get_by_id_self_list
: {
755 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id_self_list");
758 case op_get_by_id_proto
: {
759 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id_proto");
762 case op_get_by_id_proto_list
: {
763 printGetByIdOp(location
, it
, m_identifiers
, "op_get_by_id_proto_list");
766 case op_get_by_id_chain
: {
767 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id_chain");
770 case op_get_by_id_generic
: {
771 printGetByIdOp(location
, it
, m_identifiers
, "get_by_id_generic");
774 case op_get_array_length
: {
775 printGetByIdOp(location
, it
, m_identifiers
, "get_array_length");
778 case op_get_string_length
: {
779 printGetByIdOp(location
, it
, m_identifiers
, "get_string_length");
783 printPutByIdOp(location
, it
, m_identifiers
, "put_by_id");
786 case op_put_by_id_replace
: {
787 printPutByIdOp(location
, it
, m_identifiers
, "put_by_id_replace");
790 case op_put_by_id_transition
: {
791 printPutByIdOp(location
, it
, m_identifiers
, "put_by_id_transition");
794 case op_put_by_id_generic
: {
795 printPutByIdOp(location
, it
, m_identifiers
, "put_by_id_generic");
798 case op_put_getter
: {
799 int r0
= (++it
)->u
.operand
;
800 int id0
= (++it
)->u
.operand
;
801 int r1
= (++it
)->u
.operand
;
802 printf("[%4d] put_getter\t %s, %s, %s\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str(), registerName(r1
).c_str());
805 case op_put_setter
: {
806 int r0
= (++it
)->u
.operand
;
807 int id0
= (++it
)->u
.operand
;
808 int r1
= (++it
)->u
.operand
;
809 printf("[%4d] put_setter\t %s, %s, %s\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str(), registerName(r1
).c_str());
812 case op_method_check
: {
813 printf("[%4d] op_method_check\n", location
);
817 int r0
= (++it
)->u
.operand
;
818 int r1
= (++it
)->u
.operand
;
819 int id0
= (++it
)->u
.operand
;
820 printf("[%4d] del_by_id\t %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str());
823 case op_get_by_val
: {
824 int r0
= (++it
)->u
.operand
;
825 int r1
= (++it
)->u
.operand
;
826 int r2
= (++it
)->u
.operand
;
827 printf("[%4d] get_by_val\t %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), registerName(r2
).c_str());
830 case op_put_by_val
: {
831 int r0
= (++it
)->u
.operand
;
832 int r1
= (++it
)->u
.operand
;
833 int r2
= (++it
)->u
.operand
;
834 printf("[%4d] put_by_val\t %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), registerName(r2
).c_str());
837 case op_del_by_val
: {
838 int r0
= (++it
)->u
.operand
;
839 int r1
= (++it
)->u
.operand
;
840 int r2
= (++it
)->u
.operand
;
841 printf("[%4d] del_by_val\t %s, %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), registerName(r2
).c_str());
844 case op_put_by_index
: {
845 int r0
= (++it
)->u
.operand
;
846 unsigned n0
= (++it
)->u
.operand
;
847 int r1
= (++it
)->u
.operand
;
848 printf("[%4d] put_by_index\t %s, %u, %s\n", location
, registerName(r0
).c_str(), n0
, registerName(r1
).c_str());
852 int offset
= (++it
)->u
.operand
;
853 printf("[%4d] jmp\t\t %d(->%d)\n", location
, offset
, locationForOffset(begin
, it
, offset
));
857 int offset
= (++it
)->u
.operand
;
858 printf("[%4d] loop\t\t %d(->%d)\n", location
, offset
, locationForOffset(begin
, it
, offset
));
862 printConditionalJump(begin
, it
, location
, "jtrue");
865 case op_loop_if_true
: {
866 printConditionalJump(begin
, it
, location
, "loop_if_true");
870 printConditionalJump(begin
, it
, location
, "jfalse");
874 printConditionalJump(begin
, it
, location
, "jeq_null");
878 printConditionalJump(begin
, it
, location
, "jneq_null");
882 int r0
= (++it
)->u
.operand
;
883 int r1
= (++it
)->u
.operand
;
884 int offset
= (++it
)->u
.operand
;
885 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
889 int r0
= (++it
)->u
.operand
;
890 int r1
= (++it
)->u
.operand
;
891 int offset
= (++it
)->u
.operand
;
892 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
896 int r0
= (++it
)->u
.operand
;
897 int r1
= (++it
)->u
.operand
;
898 int offset
= (++it
)->u
.operand
;
899 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
902 case op_loop_if_less
: {
903 int r0
= (++it
)->u
.operand
;
904 int r1
= (++it
)->u
.operand
;
905 int offset
= (++it
)->u
.operand
;
906 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
909 case op_loop_if_lesseq
: {
910 int r0
= (++it
)->u
.operand
;
911 int r1
= (++it
)->u
.operand
;
912 int offset
= (++it
)->u
.operand
;
913 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
916 case op_switch_imm
: {
917 int tableIndex
= (++it
)->u
.operand
;
918 int defaultTarget
= (++it
)->u
.operand
;
919 int scrutineeRegister
= (++it
)->u
.operand
;
920 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, locationForOffset(begin
, it
, defaultTarget
), registerName(scrutineeRegister
).c_str());
923 case op_switch_char
: {
924 int tableIndex
= (++it
)->u
.operand
;
925 int defaultTarget
= (++it
)->u
.operand
;
926 int scrutineeRegister
= (++it
)->u
.operand
;
927 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, locationForOffset(begin
, it
, defaultTarget
), registerName(scrutineeRegister
).c_str());
930 case op_switch_string
: {
931 int tableIndex
= (++it
)->u
.operand
;
932 int defaultTarget
= (++it
)->u
.operand
;
933 int scrutineeRegister
= (++it
)->u
.operand
;
934 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, locationForOffset(begin
, it
, defaultTarget
), registerName(scrutineeRegister
).c_str());
938 int r0
= (++it
)->u
.operand
;
939 int f0
= (++it
)->u
.operand
;
940 printf("[%4d] new_func\t\t %s, f%d\n", location
, registerName(r0
).c_str(), f0
);
943 case op_new_func_exp
: {
944 int r0
= (++it
)->u
.operand
;
945 int f0
= (++it
)->u
.operand
;
946 printf("[%4d] new_func_exp\t %s, f%d\n", location
, registerName(r0
).c_str(), f0
);
950 int dst
= (++it
)->u
.operand
;
951 int func
= (++it
)->u
.operand
;
952 int argCount
= (++it
)->u
.operand
;
953 int registerOffset
= (++it
)->u
.operand
;
954 printf("[%4d] call\t\t %s, %s, %d, %d\n", location
, registerName(dst
).c_str(), registerName(func
).c_str(), argCount
, registerOffset
);
958 int dst
= (++it
)->u
.operand
;
959 int func
= (++it
)->u
.operand
;
960 int argCount
= (++it
)->u
.operand
;
961 int registerOffset
= (++it
)->u
.operand
;
962 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location
, registerName(dst
).c_str(), registerName(func
).c_str(), argCount
, registerOffset
);
965 case op_call_varargs
: {
966 int dst
= (++it
)->u
.operand
;
967 int func
= (++it
)->u
.operand
;
968 int argCount
= (++it
)->u
.operand
;
969 int registerOffset
= (++it
)->u
.operand
;
970 printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location
, registerName(dst
).c_str(), registerName(func
).c_str(), registerName(argCount
).c_str(), registerOffset
);
973 case op_load_varargs
: {
974 printUnaryOp(location
, it
, "load_varargs");
977 case op_tear_off_activation
: {
978 int r0
= (++it
)->u
.operand
;
979 printf("[%4d] tear_off_activation\t %s\n", location
, registerName(r0
).c_str());
982 case op_tear_off_arguments
: {
983 printf("[%4d] tear_off_arguments\n", location
);
987 int r0
= (++it
)->u
.operand
;
988 printf("[%4d] ret\t\t %s\n", location
, registerName(r0
).c_str());
992 int dst
= (++it
)->u
.operand
;
993 int func
= (++it
)->u
.operand
;
994 int argCount
= (++it
)->u
.operand
;
995 int registerOffset
= (++it
)->u
.operand
;
996 int proto
= (++it
)->u
.operand
;
997 int thisRegister
= (++it
)->u
.operand
;
998 printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location
, registerName(dst
).c_str(), registerName(func
).c_str(), argCount
, registerOffset
, registerName(proto
).c_str(), registerName(thisRegister
).c_str());
1001 case op_construct_verify
: {
1002 int r0
= (++it
)->u
.operand
;
1003 int r1
= (++it
)->u
.operand
;
1004 printf("[%4d] construct_verify\t %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str());
1008 int r0
= (++it
)->u
.operand
;
1009 int r1
= (++it
)->u
.operand
;
1010 int count
= (++it
)->u
.operand
;
1011 printf("[%4d] op_strcat\t %s, %s, %d\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str(), count
);
1014 case op_to_primitive
: {
1015 int r0
= (++it
)->u
.operand
;
1016 int r1
= (++it
)->u
.operand
;
1017 printf("[%4d] op_to_primitive\t %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str());
1020 case op_get_pnames
: {
1021 int r0
= (++it
)->u
.operand
;
1022 int r1
= (++it
)->u
.operand
;
1023 printf("[%4d] get_pnames\t %s, %s\n", location
, registerName(r0
).c_str(), registerName(r1
).c_str());
1026 case op_next_pname
: {
1027 int dest
= (++it
)->u
.operand
;
1028 int iter
= (++it
)->u
.operand
;
1029 int offset
= (++it
)->u
.operand
;
1030 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location
, registerName(dest
).c_str(), registerName(iter
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
1033 case op_push_scope
: {
1034 int r0
= (++it
)->u
.operand
;
1035 printf("[%4d] push_scope\t %s\n", location
, registerName(r0
).c_str());
1038 case op_pop_scope
: {
1039 printf("[%4d] pop_scope\n", location
);
1042 case op_push_new_scope
: {
1043 int r0
= (++it
)->u
.operand
;
1044 int id0
= (++it
)->u
.operand
;
1045 int r1
= (++it
)->u
.operand
;
1046 printf("[%4d] push_new_scope \t%s, %s, %s\n", location
, registerName(r0
).c_str(), idName(id0
, m_identifiers
[id0
]).c_str(), registerName(r1
).c_str());
1049 case op_jmp_scopes
: {
1050 int scopeDelta
= (++it
)->u
.operand
;
1051 int offset
= (++it
)->u
.operand
;
1052 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location
, scopeDelta
, offset
, locationForOffset(begin
, it
, offset
));
1056 int r0
= (++it
)->u
.operand
;
1057 printf("[%4d] catch\t\t %s\n", location
, registerName(r0
).c_str());
1061 int r0
= (++it
)->u
.operand
;
1062 printf("[%4d] throw\t\t %s\n", location
, registerName(r0
).c_str());
1065 case op_new_error
: {
1066 int r0
= (++it
)->u
.operand
;
1067 int errorType
= (++it
)->u
.operand
;
1068 int k0
= (++it
)->u
.operand
;
1069 printf("[%4d] new_error\t %s, %d, %s\n", location
, registerName(r0
).c_str(), errorType
, constantName(exec
, k0
, getConstant(k0
)).c_str());
1073 int retAddrDst
= (++it
)->u
.operand
;
1074 int offset
= (++it
)->u
.operand
;
1075 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location
, registerName(retAddrDst
).c_str(), offset
, locationForOffset(begin
, it
, offset
));
1079 int retAddrSrc
= (++it
)->u
.operand
;
1080 printf("[%4d] sret\t\t %s\n", location
, registerName(retAddrSrc
).c_str());
1084 int debugHookID
= (++it
)->u
.operand
;
1085 int firstLine
= (++it
)->u
.operand
;
1086 int lastLine
= (++it
)->u
.operand
;
1087 printf("[%4d] debug\t\t %s, %d, %d\n", location
, debugHookName(debugHookID
), firstLine
, lastLine
);
1090 case op_profile_will_call
: {
1091 int function
= (++it
)->u
.operand
;
1092 printf("[%4d] profile_will_call %s\n", location
, registerName(function
).c_str());
1095 case op_profile_did_call
: {
1096 int function
= (++it
)->u
.operand
;
1097 printf("[%4d] profile_did_call\t %s\n", location
, registerName(function
).c_str());
1101 int r0
= (++it
)->u
.operand
;
1102 printf("[%4d] end\t\t %s\n", location
, registerName(r0
).c_str());
1108 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1110 #if DUMP_CODE_BLOCK_STATISTICS
1111 static HashSet
<CodeBlock
*> liveCodeBlockSet
;
1114 #define FOR_EACH_MEMBER_VECTOR(macro) \
1115 macro(instructions) \
1116 macro(globalResolveInfos) \
1117 macro(structureStubInfos) \
1118 macro(callLinkInfos) \
1119 macro(linkedCallerList) \
1120 macro(identifiers) \
1121 macro(functionExpressions) \
1122 macro(constantRegisters)
1124 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1127 macro(exceptionHandlers) \
1128 macro(immediateSwitchJumpTables) \
1129 macro(characterSwitchJumpTables) \
1130 macro(stringSwitchJumpTables) \
1131 macro(functionRegisterInfos)
1133 #define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1134 macro(expressionInfo) \
1136 macro(getByIdExceptionInfo) \
1139 template<typename T
>
1140 static size_t sizeInBytes(const Vector
<T
>& vector
)
1142 return vector
.capacity() * sizeof(T
);
1145 void CodeBlock::dumpStatistics()
1147 #if DUMP_CODE_BLOCK_STATISTICS
1148 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1149 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS
)
1150 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS
)
1151 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS
)
1154 // Non-vector data members
1155 size_t evalCodeCacheIsNotEmpty
= 0;
1157 size_t symbolTableIsNotEmpty
= 0;
1158 size_t symbolTableTotalSize
= 0;
1160 size_t hasExceptionInfo
= 0;
1161 size_t hasRareData
= 0;
1163 size_t isFunctionCode
= 0;
1164 size_t isGlobalCode
= 0;
1165 size_t isEvalCode
= 0;
1167 HashSet
<CodeBlock
*>::const_iterator end
= liveCodeBlockSet
.end();
1168 for (HashSet
<CodeBlock
*>::const_iterator it
= liveCodeBlockSet
.begin(); it
!= end
; ++it
) {
1169 CodeBlock
* codeBlock
= *it
;
1171 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1172 FOR_EACH_MEMBER_VECTOR(GET_STATS
)
1175 if (!codeBlock
->m_symbolTable
.isEmpty()) {
1176 symbolTableIsNotEmpty
++;
1177 symbolTableTotalSize
+= (codeBlock
->m_symbolTable
.capacity() * (sizeof(SymbolTable::KeyType
) + sizeof(SymbolTable::MappedType
)));
1180 if (codeBlock
->m_exceptionInfo
) {
1182 #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
1183 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS
)
1187 if (codeBlock
->m_rareData
) {
1189 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1190 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS
)
1193 if (!codeBlock
->m_rareData
->m_evalCodeCache
.isEmpty())
1194 evalCodeCacheIsNotEmpty
++;
1197 switch (codeBlock
->codeType()) {
1210 size_t totalSize
= 0;
1212 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1213 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE
)
1214 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE
)
1215 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE
)
1216 #undef GET_TOTAL_SIZE
1218 totalSize
+= symbolTableTotalSize
;
1219 totalSize
+= (liveCodeBlockSet
.size() * sizeof(CodeBlock
));
1221 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet
.size());
1222 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock
));
1223 printf("Size of all CodeBlocks: %zu\n", totalSize
);
1224 printf("Average size of a CodeBlock: %zu\n", totalSize
/ liveCodeBlockSet
.size());
1226 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode
, static_cast<double>(isFunctionCode
) * 100.0 / liveCodeBlockSet
.size());
1227 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode
, static_cast<double>(isGlobalCode
) * 100.0 / liveCodeBlockSet
.size());
1228 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode
, static_cast<double>(isEvalCode
) * 100.0 / liveCodeBlockSet
.size());
1230 printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo
, static_cast<double>(hasExceptionInfo
) * 100.0 / liveCodeBlockSet
.size());
1231 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData
, static_cast<double>(hasRareData
) * 100.0 / liveCodeBlockSet
.size());
1233 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1234 FOR_EACH_MEMBER_VECTOR(PRINT_STATS
)
1235 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS
)
1236 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS
)
1239 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty
);
1240 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty
);
1242 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize
);
1245 printf("Dumping CodeBlock statistics is not enabled.\n");
1249 CodeBlock::CodeBlock(ScopeNode
* ownerNode
)
1250 : m_numCalleeRegisters(0)
1252 , m_numParameters(0)
1253 , m_ownerNode(ownerNode
)
1256 , m_instructionCount(0)
1258 , m_needsFullScopeChain(false)
1260 , m_isNumericCompareFunction(false)
1261 , m_codeType(NativeCode
)
1264 , m_exceptionInfo(0)
1266 #if DUMP_CODE_BLOCK_STATISTICS
1267 liveCodeBlockSet
.add(this);
1271 CodeBlock::CodeBlock(ScopeNode
* ownerNode
, CodeType codeType
, PassRefPtr
<SourceProvider
> sourceProvider
, unsigned sourceOffset
)
1272 : m_numCalleeRegisters(0)
1274 , m_numParameters(0)
1275 , m_ownerNode(ownerNode
)
1278 , m_instructionCount(0)
1280 , m_needsFullScopeChain(ownerNode
->needsActivation())
1281 , m_usesEval(ownerNode
->usesEval())
1282 , m_isNumericCompareFunction(false)
1283 , m_codeType(codeType
)
1284 , m_source(sourceProvider
)
1285 , m_sourceOffset(sourceOffset
)
1286 , m_exceptionInfo(new ExceptionInfo
)
1290 #if DUMP_CODE_BLOCK_STATISTICS
1291 liveCodeBlockSet
.add(this);
1295 CodeBlock::~CodeBlock()
1298 for (size_t size
= m_globalResolveInstructions
.size(), i
= 0; i
< size
; ++i
)
1299 derefStructures(&m_instructions
[m_globalResolveInstructions
[i
]]);
1301 for (size_t size
= m_propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
)
1302 derefStructures(&m_instructions
[m_propertyAccessInstructions
[i
]]);
1304 for (size_t size
= m_globalResolveInfos
.size(), i
= 0; i
< size
; ++i
) {
1305 if (m_globalResolveInfos
[i
].structure
)
1306 m_globalResolveInfos
[i
].structure
->deref();
1309 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
1310 m_structureStubInfos
[i
].deref();
1312 for (size_t size
= m_callLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1313 CallLinkInfo
* callLinkInfo
= &m_callLinkInfos
[i
];
1314 if (callLinkInfo
->isLinked())
1315 callLinkInfo
->callee
->removeCaller(callLinkInfo
);
1318 for (size_t size
= m_methodCallLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1319 if (Structure
* structure
= m_methodCallLinkInfos
[i
].cachedStructure
) {
1321 // Both members must be filled at the same time
1322 ASSERT(m_methodCallLinkInfos
[i
].cachedPrototypeStructure
);
1323 m_methodCallLinkInfos
[i
].cachedPrototypeStructure
->deref();
1327 #if ENABLE(JIT_OPTIMIZE_CALL)
1331 #endif // !ENABLE(JIT)
1333 #if DUMP_CODE_BLOCK_STATISTICS
1334 liveCodeBlockSet
.remove(this);
1338 #if ENABLE(JIT_OPTIMIZE_CALL)
1339 void CodeBlock::unlinkCallers()
1341 size_t size
= m_linkedCallerList
.size();
1342 for (size_t i
= 0; i
< size
; ++i
) {
1343 CallLinkInfo
* currentCaller
= m_linkedCallerList
[i
];
1344 JIT::unlinkCall(currentCaller
);
1345 currentCaller
->setUnlinked();
1347 m_linkedCallerList
.clear();
1351 void CodeBlock::derefStructures(Instruction
* vPC
) const
1353 ASSERT(m_codeType
!= NativeCode
);
1354 Interpreter
* interpreter
= m_globalData
->interpreter
;
1356 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
1357 vPC
[4].u
.structure
->deref();
1360 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
1361 vPC
[4].u
.structure
->deref();
1362 vPC
[5].u
.structure
->deref();
1365 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
1366 vPC
[4].u
.structure
->deref();
1367 vPC
[5].u
.structureChain
->deref();
1370 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1371 vPC
[4].u
.structure
->deref();
1372 vPC
[5].u
.structure
->deref();
1373 vPC
[6].u
.structureChain
->deref();
1376 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1377 vPC
[4].u
.structure
->deref();
1380 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
)) {
1381 if(vPC
[4].u
.structure
)
1382 vPC
[4].u
.structure
->deref();
1385 if ((vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto_list
))
1386 || (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self_list
))) {
1387 PolymorphicAccessStructureList
* polymorphicStructures
= vPC
[4].u
.polymorphicStructures
;
1388 polymorphicStructures
->derefStructures(vPC
[5].u
.operand
);
1389 delete polymorphicStructures
;
1393 // These instructions don't ref their Structures.
1394 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
));
1397 void CodeBlock::refStructures(Instruction
* vPC
) const
1399 ASSERT(m_codeType
!= NativeCode
);
1400 Interpreter
* interpreter
= m_globalData
->interpreter
;
1402 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
1403 vPC
[4].u
.structure
->ref();
1406 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
1407 vPC
[4].u
.structure
->ref();
1408 vPC
[5].u
.structure
->ref();
1411 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
1412 vPC
[4].u
.structure
->ref();
1413 vPC
[5].u
.structureChain
->ref();
1416 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1417 vPC
[4].u
.structure
->ref();
1418 vPC
[5].u
.structure
->ref();
1419 vPC
[6].u
.structureChain
->ref();
1422 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1423 vPC
[4].u
.structure
->ref();
1427 // These instructions don't ref their Structures.
1428 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
));
1431 void CodeBlock::mark()
1433 for (size_t i
= 0; i
< m_constantRegisters
.size(); ++i
)
1434 if (!m_constantRegisters
[i
].marked())
1435 m_constantRegisters
[i
].mark();
1437 for (size_t i
= 0; i
< m_functionExpressions
.size(); ++i
)
1438 m_functionExpressions
[i
]->body()->mark();
1441 for (size_t i
= 0; i
< m_rareData
->m_functions
.size(); ++i
)
1442 m_rareData
->m_functions
[i
]->body()->mark();
1444 m_rareData
->m_evalCodeCache
.mark();
1448 void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame
* callFrame
)
1450 ASSERT(m_codeType
!= NativeCode
);
1451 if (m_exceptionInfo
)
1454 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1455 if (m_needsFullScopeChain
) {
1456 ScopeChain
sc(scopeChain
);
1457 int scopeDelta
= sc
.localDepth();
1458 if (m_codeType
== EvalCode
)
1459 scopeDelta
-= static_cast<EvalCodeBlock
*>(this)->baseScopeDepth();
1460 else if (m_codeType
== FunctionCode
)
1461 scopeDelta
++; // Compilation of function code assumes activation is not on the scope chain yet.
1462 ASSERT(scopeDelta
>= 0);
1463 while (scopeDelta
--)
1464 scopeChain
= scopeChain
->next
;
1467 switch (m_codeType
) {
1468 case FunctionCode
: {
1469 FunctionBodyNode
* ownerFunctionBodyNode
= static_cast<FunctionBodyNode
*>(m_ownerNode
);
1470 RefPtr
<FunctionBodyNode
> newFunctionBody
= m_globalData
->parser
->reparse
<FunctionBodyNode
>(m_globalData
, ownerFunctionBodyNode
);
1471 ASSERT(newFunctionBody
);
1472 newFunctionBody
->finishParsing(ownerFunctionBodyNode
->copyParameters(), ownerFunctionBodyNode
->parameterCount());
1474 m_globalData
->scopeNodeBeingReparsed
= newFunctionBody
.get();
1476 CodeBlock
& newCodeBlock
= newFunctionBody
->bytecodeForExceptionInfoReparse(scopeChain
, this);
1477 ASSERT(newCodeBlock
.m_exceptionInfo
);
1478 ASSERT(newCodeBlock
.m_instructionCount
== m_instructionCount
);
1481 JIT::compile(m_globalData
, &newCodeBlock
);
1482 ASSERT(newFunctionBody
->generatedJITCode().size() == ownerNode()->generatedJITCode().size());
1485 m_exceptionInfo
.set(newCodeBlock
.m_exceptionInfo
.release());
1487 m_globalData
->scopeNodeBeingReparsed
= 0;
1492 EvalNode
* ownerEvalNode
= static_cast<EvalNode
*>(m_ownerNode
);
1493 RefPtr
<EvalNode
> newEvalBody
= m_globalData
->parser
->reparse
<EvalNode
>(m_globalData
, ownerEvalNode
);
1495 m_globalData
->scopeNodeBeingReparsed
= newEvalBody
.get();
1497 EvalCodeBlock
& newCodeBlock
= newEvalBody
->bytecodeForExceptionInfoReparse(scopeChain
, this);
1498 ASSERT(newCodeBlock
.m_exceptionInfo
);
1499 ASSERT(newCodeBlock
.m_instructionCount
== m_instructionCount
);
1502 JIT::compile(m_globalData
, &newCodeBlock
);
1503 ASSERT(newEvalBody
->generatedJITCode().size() == ownerNode()->generatedJITCode().size());
1506 m_exceptionInfo
.set(newCodeBlock
.m_exceptionInfo
.release());
1508 m_globalData
->scopeNodeBeingReparsed
= 0;
1513 // CodeBlocks for Global code blocks are transient and therefore to not gain from
1514 // from throwing out there exception information.
1515 ASSERT_NOT_REACHED();
1519 HandlerInfo
* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset
)
1521 ASSERT(m_codeType
!= NativeCode
);
1522 ASSERT(bytecodeOffset
< m_instructionCount
);
1527 Vector
<HandlerInfo
>& exceptionHandlers
= m_rareData
->m_exceptionHandlers
;
1528 for (size_t i
= 0; i
< exceptionHandlers
.size(); ++i
) {
1529 // Handlers are ordered innermost first, so the first handler we encounter
1530 // that contains the source address is the correct handler to use.
1531 if (exceptionHandlers
[i
].start
<= bytecodeOffset
&& exceptionHandlers
[i
].end
>= bytecodeOffset
)
1532 return &exceptionHandlers
[i
];
1538 int CodeBlock::lineNumberForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
)
1540 ASSERT(m_codeType
!= NativeCode
);
1541 ASSERT(bytecodeOffset
< m_instructionCount
);
1543 reparseForExceptionInfoIfNecessary(callFrame
);
1544 ASSERT(m_exceptionInfo
);
1546 if (!m_exceptionInfo
->m_lineInfo
.size())
1547 return m_ownerNode
->source().firstLine(); // Empty function
1550 int high
= m_exceptionInfo
->m_lineInfo
.size();
1551 while (low
< high
) {
1552 int mid
= low
+ (high
- low
) / 2;
1553 if (m_exceptionInfo
->m_lineInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1560 return m_ownerNode
->source().firstLine();
1561 return m_exceptionInfo
->m_lineInfo
[low
- 1].lineNumber
;
1564 int CodeBlock::expressionRangeForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
, int& divot
, int& startOffset
, int& endOffset
)
1566 ASSERT(m_codeType
!= NativeCode
);
1567 ASSERT(bytecodeOffset
< m_instructionCount
);
1569 reparseForExceptionInfoIfNecessary(callFrame
);
1570 ASSERT(m_exceptionInfo
);
1572 if (!m_exceptionInfo
->m_expressionInfo
.size()) {
1573 // We didn't think anything could throw. Apparently we were wrong.
1577 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1581 int high
= m_exceptionInfo
->m_expressionInfo
.size();
1582 while (low
< high
) {
1583 int mid
= low
+ (high
- low
) / 2;
1584 if (m_exceptionInfo
->m_expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
1595 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1598 startOffset
= m_exceptionInfo
->m_expressionInfo
[low
- 1].startOffset
;
1599 endOffset
= m_exceptionInfo
->m_expressionInfo
[low
- 1].endOffset
;
1600 divot
= m_exceptionInfo
->m_expressionInfo
[low
- 1].divotPoint
+ m_sourceOffset
;
1601 return lineNumberForBytecodeOffset(callFrame
, bytecodeOffset
);
1604 bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame
* callFrame
, unsigned bytecodeOffset
, OpcodeID
& opcodeID
)
1606 ASSERT(m_codeType
!= NativeCode
);
1607 ASSERT(bytecodeOffset
< m_instructionCount
);
1609 reparseForExceptionInfoIfNecessary(callFrame
);
1610 ASSERT(m_exceptionInfo
);
1612 if (!m_exceptionInfo
->m_getByIdExceptionInfo
.size())
1616 int high
= m_exceptionInfo
->m_getByIdExceptionInfo
.size();
1617 while (low
< high
) {
1618 int mid
= low
+ (high
- low
) / 2;
1619 if (m_exceptionInfo
->m_getByIdExceptionInfo
[mid
].bytecodeOffset
<= bytecodeOffset
)
1625 if (!low
|| m_exceptionInfo
->m_getByIdExceptionInfo
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1628 opcodeID
= m_exceptionInfo
->m_getByIdExceptionInfo
[low
- 1].isOpConstruct
? op_construct
: op_instanceof
;
1633 bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset
, int& functionRegisterIndex
)
1635 ASSERT(m_codeType
!= NativeCode
);
1636 ASSERT(bytecodeOffset
< m_instructionCount
);
1638 if (!m_rareData
|| !m_rareData
->m_functionRegisterInfos
.size())
1642 int high
= m_rareData
->m_functionRegisterInfos
.size();
1643 while (low
< high
) {
1644 int mid
= low
+ (high
- low
) / 2;
1645 if (m_rareData
->m_functionRegisterInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
1651 if (!low
|| m_rareData
->m_functionRegisterInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1654 functionRegisterIndex
= m_rareData
->m_functionRegisterInfos
[low
- 1].functionRegisterIndex
;
1660 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset
)
1662 ASSERT(m_codeType
!= NativeCode
);
1663 if (m_globalResolveInstructions
.isEmpty())
1667 int high
= m_globalResolveInstructions
.size();
1668 while (low
< high
) {
1669 int mid
= low
+ (high
- low
) / 2;
1670 if (m_globalResolveInstructions
[mid
] <= bytecodeOffset
)
1676 if (!low
|| m_globalResolveInstructions
[low
- 1] != bytecodeOffset
)
1681 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset
)
1683 ASSERT(m_codeType
!= NativeCode
);
1684 if (m_globalResolveInfos
.isEmpty())
1688 int high
= m_globalResolveInfos
.size();
1689 while (low
< high
) {
1690 int mid
= low
+ (high
- low
) / 2;
1691 if (m_globalResolveInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
1697 if (!low
|| m_globalResolveInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
1704 void CodeBlock::setJITCode(JITCode jitCode
)
1706 ASSERT(m_codeType
!= NativeCode
);
1707 ownerNode()->setJITCode(jitCode
);
1708 #if !ENABLE(OPCODE_SAMPLING)
1709 if (!BytecodeGenerator::dumpsGeneratedCode())
1710 m_instructions
.clear();
1715 void CodeBlock::shrinkToFit()
1717 m_instructions
.shrinkToFit();
1720 m_propertyAccessInstructions
.shrinkToFit();
1721 m_globalResolveInstructions
.shrinkToFit();
1723 m_structureStubInfos
.shrinkToFit();
1724 m_globalResolveInfos
.shrinkToFit();
1725 m_callLinkInfos
.shrinkToFit();
1726 m_linkedCallerList
.shrinkToFit();
1729 m_identifiers
.shrinkToFit();
1730 m_functionExpressions
.shrinkToFit();
1731 m_constantRegisters
.shrinkToFit();
1733 if (m_exceptionInfo
) {
1734 m_exceptionInfo
->m_expressionInfo
.shrinkToFit();
1735 m_exceptionInfo
->m_lineInfo
.shrinkToFit();
1736 m_exceptionInfo
->m_getByIdExceptionInfo
.shrinkToFit();
1740 m_rareData
->m_exceptionHandlers
.shrinkToFit();
1741 m_rareData
->m_functions
.shrinkToFit();
1742 m_rareData
->m_regexps
.shrinkToFit();
1743 m_rareData
->m_immediateSwitchJumpTables
.shrinkToFit();
1744 m_rareData
->m_characterSwitchJumpTables
.shrinkToFit();
1745 m_rareData
->m_stringSwitchJumpTables
.shrinkToFit();
1747 m_rareData
->m_functionRegisterInfos
.shrinkToFit();