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"
34 #include "DFGCapabilities.h"
36 #include "DFGRepatch.h"
38 #include "Interpreter.h"
41 #include "JSActivation.h"
42 #include "JSFunction.h"
43 #include "JSStaticScopeObject.h"
45 #include "LowLevelInterpreter.h"
46 #include "RepatchBuffer.h"
47 #include "UStringConcatenate.h"
49 #include <wtf/StringExtras.h>
52 #include "DFGOperations.h"
55 #define DUMP_CODE_BLOCK_STATISTICS 0
63 static UString
escapeQuotes(const UString
& str
)
67 while ((pos
= result
.find('\"', pos
)) != notFound
) {
68 result
= makeUString(result
.substringSharingImpl(0, pos
), "\"\\\"\"", result
.substringSharingImpl(pos
+ 1));
74 static UString
valueToSourceString(ExecState
* exec
, JSValue val
)
80 return makeUString("\"", escapeQuotes(val
.toString(exec
)->value(exec
)), "\"");
82 return val
.description();
85 static CString
constantName(ExecState
* exec
, int k
, JSValue value
)
87 return makeUString(valueToSourceString(exec
, value
), "(@k", UString::number(k
- FirstConstantRegisterIndex
), ")").utf8();
90 static CString
idName(int id0
, const Identifier
& ident
)
92 return makeUString(ident
.ustring(), "(@id", UString::number(id0
), ")").utf8();
95 CString
CodeBlock::registerName(ExecState
* exec
, int r
) const
97 if (r
== missingThisObjectMarker())
100 if (isConstantRegisterIndex(r
))
101 return constantName(exec
, r
, getConstant(r
));
103 return makeUString("r", UString::number(r
)).utf8();
106 static UString
regexpToSourceString(RegExp
* regExp
)
108 char postfix
[5] = { '/', 0, 0, 0, 0 };
110 if (regExp
->global())
111 postfix
[index
++] = 'g';
112 if (regExp
->ignoreCase())
113 postfix
[index
++] = 'i';
114 if (regExp
->multiline())
115 postfix
[index
] = 'm';
117 return makeUString("/", regExp
->pattern(), postfix
);
120 static CString
regexpName(int re
, RegExp
* regexp
)
122 return makeUString(regexpToSourceString(regexp
), "(@re", UString::number(re
), ")").utf8();
125 static UString
pointerToSourceString(void* p
)
127 char buffer
[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
128 snprintf(buffer
, sizeof(buffer
), "%p", p
);
132 NEVER_INLINE
static const char* debugHookName(int debugHookID
)
134 switch (static_cast<DebugHookID
>(debugHookID
)) {
135 case DidEnterCallFrame
:
136 return "didEnterCallFrame";
137 case WillLeaveCallFrame
:
138 return "willLeaveCallFrame";
139 case WillExecuteStatement
:
140 return "willExecuteStatement";
141 case WillExecuteProgram
:
142 return "willExecuteProgram";
143 case DidExecuteProgram
:
144 return "didExecuteProgram";
145 case DidReachBreakpoint
:
146 return "didReachBreakpoint";
149 ASSERT_NOT_REACHED();
153 void CodeBlock::printUnaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
155 int r0
= (++it
)->u
.operand
;
156 int r1
= (++it
)->u
.operand
;
158 dataLog("[%4d] %s\t\t %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
161 void CodeBlock::printBinaryOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
163 int r0
= (++it
)->u
.operand
;
164 int r1
= (++it
)->u
.operand
;
165 int r2
= (++it
)->u
.operand
;
166 dataLog("[%4d] %s\t\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
169 void CodeBlock::printConditionalJump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
&, Vector
<Instruction
>::const_iterator
& it
, int location
, const char* op
) const
171 int r0
= (++it
)->u
.operand
;
172 int offset
= (++it
)->u
.operand
;
173 dataLog("[%4d] %s\t\t %s, %d(->%d)\n", location
, op
, registerName(exec
, r0
).data(), offset
, location
+ offset
);
176 void CodeBlock::printGetByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
178 int r0
= (++it
)->u
.operand
;
179 int r1
= (++it
)->u
.operand
;
180 int id0
= (++it
)->u
.operand
;
181 dataLog("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
185 void CodeBlock::printCallOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
187 int func
= (++it
)->u
.operand
;
188 int argCount
= (++it
)->u
.operand
;
189 int registerOffset
= (++it
)->u
.operand
;
190 dataLog("[%4d] %s\t %s, %d, %d\n", location
, op
, registerName(exec
, func
).data(), argCount
, registerOffset
);
194 void CodeBlock::printPutByIdOp(ExecState
* exec
, int location
, Vector
<Instruction
>::const_iterator
& it
, const char* op
) const
196 int r0
= (++it
)->u
.operand
;
197 int id0
= (++it
)->u
.operand
;
198 int r1
= (++it
)->u
.operand
;
199 dataLog("[%4d] %s\t %s, %s, %s\n", location
, op
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
204 static bool isGlobalResolve(OpcodeID opcodeID
)
206 return opcodeID
== op_resolve_global
|| opcodeID
== op_resolve_global_dynamic
;
209 static bool isPropertyAccess(OpcodeID opcodeID
)
212 case op_get_by_id_self
:
213 case op_get_by_id_proto
:
214 case op_get_by_id_chain
:
215 case op_put_by_id_transition
:
216 case op_put_by_id_replace
:
219 case op_get_by_id_generic
:
220 case op_put_by_id_generic
:
221 case op_get_array_length
:
222 case op_get_string_length
:
229 static unsigned instructionOffsetForNth(ExecState
* exec
, const RefCountedArray
<Instruction
>& instructions
, int nth
, bool (*predicate
)(OpcodeID
))
232 while (i
< instructions
.size()) {
233 OpcodeID currentOpcode
= exec
->interpreter()->getOpcodeID(instructions
[i
].u
.opcode
);
234 if (predicate(currentOpcode
)) {
238 i
+= opcodeLengths
[currentOpcode
];
241 ASSERT_NOT_REACHED();
245 static void printGlobalResolveInfo(const GlobalResolveInfo
& resolveInfo
, unsigned instructionOffset
)
247 dataLog(" [%4d] %s: %s\n", instructionOffset
, "resolve_global", pointerToSourceString(resolveInfo
.structure
).utf8().data());
250 static void printStructureStubInfo(const StructureStubInfo
& stubInfo
, unsigned instructionOffset
)
252 switch (stubInfo
.accessType
) {
253 case access_get_by_id_self
:
254 dataLog(" [%4d] %s: %s\n", instructionOffset
, "get_by_id_self", pointerToSourceString(stubInfo
.u
.getByIdSelf
.baseObjectStructure
).utf8().data());
256 case access_get_by_id_proto
:
257 dataLog(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(stubInfo
.u
.getByIdProto
.baseObjectStructure
).utf8().data(), pointerToSourceString(stubInfo
.u
.getByIdProto
.prototypeStructure
).utf8().data());
259 case access_get_by_id_chain
:
260 dataLog(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(stubInfo
.u
.getByIdChain
.baseObjectStructure
).utf8().data(), pointerToSourceString(stubInfo
.u
.getByIdChain
.chain
).utf8().data());
262 case access_get_by_id_self_list
:
263 dataLog(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_self_list", pointerToSourceString(stubInfo
.u
.getByIdSelfList
.structureList
).utf8().data(), stubInfo
.u
.getByIdSelfList
.listSize
);
265 case access_get_by_id_proto_list
:
266 dataLog(" [%4d] %s: %s (%d)\n", instructionOffset
, "op_get_by_id_proto_list", pointerToSourceString(stubInfo
.u
.getByIdProtoList
.structureList
).utf8().data(), stubInfo
.u
.getByIdProtoList
.listSize
);
268 case access_put_by_id_transition_normal
:
269 case access_put_by_id_transition_direct
:
270 dataLog(" [%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());
272 case access_put_by_id_replace
:
273 dataLog(" [%4d] %s: %s\n", instructionOffset
, "put_by_id_replace", pointerToSourceString(stubInfo
.u
.putByIdReplace
.baseObjectStructure
).utf8().data());
276 dataLog(" [%4d] %s\n", instructionOffset
, "unset");
278 case access_get_by_id_generic
:
279 dataLog(" [%4d] %s\n", instructionOffset
, "op_get_by_id_generic");
281 case access_put_by_id_generic
:
282 dataLog(" [%4d] %s\n", instructionOffset
, "op_put_by_id_generic");
284 case access_get_array_length
:
285 dataLog(" [%4d] %s\n", instructionOffset
, "op_get_array_length");
287 case access_get_string_length
:
288 dataLog(" [%4d] %s\n", instructionOffset
, "op_get_string_length");
291 ASSERT_NOT_REACHED();
296 void CodeBlock::printStructure(const char* name
, const Instruction
* vPC
, int operand
) const
298 unsigned instructionOffset
= vPC
- instructions().begin();
299 dataLog(" [%4d] %s: %s\n", instructionOffset
, name
, pointerToSourceString(vPC
[operand
].u
.structure
).utf8().data());
302 void CodeBlock::printStructures(const Instruction
* vPC
) const
304 Interpreter
* interpreter
= m_globalData
->interpreter
;
305 unsigned instructionOffset
= vPC
- instructions().begin();
307 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
)) {
308 printStructure("get_by_id", vPC
, 4);
311 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
312 printStructure("get_by_id_self", vPC
, 4);
315 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
316 dataLog(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structure
).utf8().data());
319 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
320 dataLog(" [%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());
323 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
324 dataLog(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structureChain
).utf8().data());
327 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
)) {
328 printStructure("put_by_id", vPC
, 4);
331 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
332 printStructure("put_by_id_replace", vPC
, 4);
335 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
)) {
336 printStructure("resolve_global", vPC
, 4);
339 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
340 printStructure("resolve_global_dynamic", vPC
, 4);
344 // These m_instructions doesn't ref Structures.
345 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
));
348 void CodeBlock::dump(ExecState
* exec
) const
350 size_t instructionCount
= 0;
352 for (size_t i
= 0; i
< instructions().size(); i
+= opcodeLengths
[exec
->interpreter()->getOpcodeID(instructions()[i
].u
.opcode
)])
355 dataLog("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s); %d variable(s)\n\n",
356 static_cast<unsigned long>(instructions().size()),
357 static_cast<unsigned long>(instructions().size() * sizeof(Instruction
)),
358 this, m_numParameters
, m_numCalleeRegisters
, m_numVars
);
360 Vector
<Instruction
>::const_iterator begin
= instructions().begin();
361 Vector
<Instruction
>::const_iterator end
= instructions().end();
362 for (Vector
<Instruction
>::const_iterator it
= begin
; it
!= end
; ++it
)
363 dump(exec
, begin
, it
);
365 if (!m_identifiers
.isEmpty()) {
366 dataLog("\nIdentifiers:\n");
369 dataLog(" id%u = %s\n", static_cast<unsigned>(i
), m_identifiers
[i
].ustring().utf8().data());
371 } while (i
!= m_identifiers
.size());
374 if (!m_constantRegisters
.isEmpty()) {
375 dataLog("\nConstants:\n");
378 dataLog(" k%u = %s\n", static_cast<unsigned>(i
), valueToSourceString(exec
, m_constantRegisters
[i
].get()).utf8().data());
380 } while (i
< m_constantRegisters
.size());
383 if (m_rareData
&& !m_rareData
->m_regexps
.isEmpty()) {
384 dataLog("\nm_regexps:\n");
387 dataLog(" re%u = %s\n", static_cast<unsigned>(i
), regexpToSourceString(m_rareData
->m_regexps
[i
].get()).utf8().data());
389 } while (i
< m_rareData
->m_regexps
.size());
393 if (!m_globalResolveInfos
.isEmpty() || !m_structureStubInfos
.isEmpty())
394 dataLog("\nStructures:\n");
396 if (!m_globalResolveInfos
.isEmpty()) {
399 printGlobalResolveInfo(m_globalResolveInfos
[i
], instructionOffsetForNth(exec
, instructions(), i
+ 1, isGlobalResolve
));
401 } while (i
< m_globalResolveInfos
.size());
403 if (!m_structureStubInfos
.isEmpty()) {
406 printStructureStubInfo(m_structureStubInfos
[i
], instructionOffsetForNth(exec
, instructions(), i
+ 1, isPropertyAccess
));
408 } while (i
< m_structureStubInfos
.size());
411 #if ENABLE(CLASSIC_INTERPRETER)
412 if (!m_globalResolveInstructions
.isEmpty() || !m_propertyAccessInstructions
.isEmpty())
413 dataLog("\nStructures:\n");
415 if (!m_globalResolveInstructions
.isEmpty()) {
418 printStructures(&instructions()[m_globalResolveInstructions
[i
]]);
420 } while (i
< m_globalResolveInstructions
.size());
422 if (!m_propertyAccessInstructions
.isEmpty()) {
425 printStructures(&instructions()[m_propertyAccessInstructions
[i
]]);
427 } while (i
< m_propertyAccessInstructions
.size());
431 if (m_rareData
&& !m_rareData
->m_exceptionHandlers
.isEmpty()) {
432 dataLog("\nException Handlers:\n");
435 dataLog("\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
);
437 } while (i
< m_rareData
->m_exceptionHandlers
.size());
440 if (m_rareData
&& !m_rareData
->m_immediateSwitchJumpTables
.isEmpty()) {
441 dataLog("Immediate Switch Jump Tables:\n");
444 dataLog(" %1d = {\n", i
);
446 Vector
<int32_t>::const_iterator end
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.end();
447 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
450 dataLog("\t\t%4d => %04d\n", entry
+ m_rareData
->m_immediateSwitchJumpTables
[i
].min
, *iter
);
454 } while (i
< m_rareData
->m_immediateSwitchJumpTables
.size());
457 if (m_rareData
&& !m_rareData
->m_characterSwitchJumpTables
.isEmpty()) {
458 dataLog("\nCharacter Switch Jump Tables:\n");
461 dataLog(" %1d = {\n", i
);
463 Vector
<int32_t>::const_iterator end
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.end();
464 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
467 ASSERT(!((i
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
) & ~0xFFFF));
468 UChar ch
= static_cast<UChar
>(entry
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
);
469 dataLog("\t\t\"%s\" => %04d\n", UString(&ch
, 1).utf8().data(), *iter
);
473 } while (i
< m_rareData
->m_characterSwitchJumpTables
.size());
476 if (m_rareData
&& !m_rareData
->m_stringSwitchJumpTables
.isEmpty()) {
477 dataLog("\nString Switch Jump Tables:\n");
480 dataLog(" %1d = {\n", i
);
481 StringJumpTable::StringOffsetTable::const_iterator end
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.end();
482 for (StringJumpTable::StringOffsetTable::const_iterator iter
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.begin(); iter
!= end
; ++iter
)
483 dataLog("\t\t\"%s\" => %04d\n", UString(iter
->first
).utf8().data(), iter
->second
.branchOffset
);
486 } while (i
< m_rareData
->m_stringSwitchJumpTables
.size());
492 void CodeBlock::dump(ExecState
* exec
, const Vector
<Instruction
>::const_iterator
& begin
, Vector
<Instruction
>::const_iterator
& it
) const
494 int location
= it
- begin
;
495 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
497 dataLog("[%4d] enter\n", location
);
500 case op_create_activation
: {
501 int r0
= (++it
)->u
.operand
;
502 dataLog("[%4d] create_activation %s\n", location
, registerName(exec
, r0
).data());
505 case op_create_arguments
: {
506 int r0
= (++it
)->u
.operand
;
507 dataLog("[%4d] create_arguments\t %s\n", location
, registerName(exec
, r0
).data());
510 case op_init_lazy_reg
: {
511 int r0
= (++it
)->u
.operand
;
512 dataLog("[%4d] init_lazy_reg\t %s\n", location
, registerName(exec
, r0
).data());
515 case op_get_callee
: {
516 int r0
= (++it
)->u
.operand
;
517 dataLog("[%4d] op_get_callee %s\n", location
, registerName(exec
, r0
).data());
520 case op_create_this
: {
521 int r0
= (++it
)->u
.operand
;
522 int r1
= (++it
)->u
.operand
;
523 dataLog("[%4d] create_this %s %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
526 case op_convert_this
: {
527 int r0
= (++it
)->u
.operand
;
528 dataLog("[%4d] convert_this\t %s\n", location
, registerName(exec
, r0
).data());
531 case op_new_object
: {
532 int r0
= (++it
)->u
.operand
;
533 dataLog("[%4d] new_object\t %s\n", location
, registerName(exec
, r0
).data());
537 int dst
= (++it
)->u
.operand
;
538 int argv
= (++it
)->u
.operand
;
539 int argc
= (++it
)->u
.operand
;
540 dataLog("[%4d] new_array\t %s, %s, %d\n", location
, registerName(exec
, dst
).data(), registerName(exec
, argv
).data(), argc
);
543 case op_new_array_buffer
: {
544 int dst
= (++it
)->u
.operand
;
545 int argv
= (++it
)->u
.operand
;
546 int argc
= (++it
)->u
.operand
;
547 dataLog("[%4d] new_array_buffer %s, %d, %d\n", location
, registerName(exec
, dst
).data(), argv
, argc
);
550 case op_new_regexp
: {
551 int r0
= (++it
)->u
.operand
;
552 int re0
= (++it
)->u
.operand
;
553 dataLog("[%4d] new_regexp\t %s, ", location
, registerName(exec
, r0
).data());
554 if (r0
>=0 && r0
< (int)numberOfRegExps())
555 dataLog("%s\n", regexpName(re0
, regexp(re0
)).data());
557 dataLog("bad_regexp(%d)\n", re0
);
561 int r0
= (++it
)->u
.operand
;
562 int r1
= (++it
)->u
.operand
;
563 dataLog("[%4d] mov\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
567 printUnaryOp(exec
, location
, it
, "not");
571 printBinaryOp(exec
, location
, it
, "eq");
575 printUnaryOp(exec
, location
, it
, "eq_null");
579 printBinaryOp(exec
, location
, it
, "neq");
583 printUnaryOp(exec
, location
, it
, "neq_null");
587 printBinaryOp(exec
, location
, it
, "stricteq");
591 printBinaryOp(exec
, location
, it
, "nstricteq");
595 printBinaryOp(exec
, location
, it
, "less");
599 printBinaryOp(exec
, location
, it
, "lesseq");
603 printBinaryOp(exec
, location
, it
, "greater");
607 printBinaryOp(exec
, location
, it
, "greatereq");
611 int r0
= (++it
)->u
.operand
;
612 dataLog("[%4d] pre_inc\t\t %s\n", location
, registerName(exec
, r0
).data());
616 int r0
= (++it
)->u
.operand
;
617 dataLog("[%4d] pre_dec\t\t %s\n", location
, registerName(exec
, r0
).data());
621 printUnaryOp(exec
, location
, it
, "post_inc");
625 printUnaryOp(exec
, location
, it
, "post_dec");
628 case op_to_jsnumber
: {
629 printUnaryOp(exec
, location
, it
, "to_jsnumber");
633 printUnaryOp(exec
, location
, it
, "negate");
637 printBinaryOp(exec
, location
, it
, "add");
642 printBinaryOp(exec
, location
, it
, "mul");
647 printBinaryOp(exec
, location
, it
, "div");
652 printBinaryOp(exec
, location
, it
, "mod");
656 printBinaryOp(exec
, location
, it
, "sub");
661 printBinaryOp(exec
, location
, it
, "lshift");
665 printBinaryOp(exec
, location
, it
, "rshift");
669 printBinaryOp(exec
, location
, it
, "urshift");
673 printBinaryOp(exec
, location
, it
, "bitand");
678 printBinaryOp(exec
, location
, it
, "bitxor");
683 printBinaryOp(exec
, location
, it
, "bitor");
687 case op_check_has_instance
: {
688 int base
= (++it
)->u
.operand
;
689 dataLog("[%4d] check_has_instance\t\t %s\n", location
, registerName(exec
, base
).data());
692 case op_instanceof
: {
693 int r0
= (++it
)->u
.operand
;
694 int r1
= (++it
)->u
.operand
;
695 int r2
= (++it
)->u
.operand
;
696 int r3
= (++it
)->u
.operand
;
697 dataLog("[%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());
701 printUnaryOp(exec
, location
, it
, "typeof");
704 case op_is_undefined
: {
705 printUnaryOp(exec
, location
, it
, "is_undefined");
708 case op_is_boolean
: {
709 printUnaryOp(exec
, location
, it
, "is_boolean");
713 printUnaryOp(exec
, location
, it
, "is_number");
717 printUnaryOp(exec
, location
, it
, "is_string");
721 printUnaryOp(exec
, location
, it
, "is_object");
724 case op_is_function
: {
725 printUnaryOp(exec
, location
, it
, "is_function");
729 printBinaryOp(exec
, location
, it
, "in");
733 int r0
= (++it
)->u
.operand
;
734 int id0
= (++it
)->u
.operand
;
735 dataLog("[%4d] resolve\t\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
739 case op_resolve_skip
: {
740 int r0
= (++it
)->u
.operand
;
741 int id0
= (++it
)->u
.operand
;
742 int skipLevels
= (++it
)->u
.operand
;
743 dataLog("[%4d] resolve_skip\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), skipLevels
);
747 case op_resolve_global
: {
748 int r0
= (++it
)->u
.operand
;
749 int id0
= (++it
)->u
.operand
;
750 dataLog("[%4d] resolve_global\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
754 case op_resolve_global_dynamic
: {
755 int r0
= (++it
)->u
.operand
;
756 int id0
= (++it
)->u
.operand
;
757 JSValue scope
= JSValue((++it
)->u
.jsCell
.get());
759 int depth
= (++it
)->u
.operand
;
760 dataLog("[%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
);
764 case op_get_scoped_var
: {
765 int r0
= (++it
)->u
.operand
;
766 int index
= (++it
)->u
.operand
;
767 int skipLevels
= (++it
)->u
.operand
;
768 dataLog("[%4d] get_scoped_var\t %s, %d, %d\n", location
, registerName(exec
, r0
).data(), index
, skipLevels
);
772 case op_put_scoped_var
: {
773 int index
= (++it
)->u
.operand
;
774 int skipLevels
= (++it
)->u
.operand
;
775 int r0
= (++it
)->u
.operand
;
776 dataLog("[%4d] put_scoped_var\t %d, %d, %s\n", location
, index
, skipLevels
, registerName(exec
, r0
).data());
779 case op_get_global_var
: {
780 int r0
= (++it
)->u
.operand
;
781 int index
= (++it
)->u
.operand
;
782 dataLog("[%4d] get_global_var\t %s, %d\n", location
, registerName(exec
, r0
).data(), index
);
786 case op_put_global_var
: {
787 int index
= (++it
)->u
.operand
;
788 int r0
= (++it
)->u
.operand
;
789 dataLog("[%4d] put_global_var\t %d, %s\n", location
, index
, registerName(exec
, r0
).data());
792 case op_resolve_base
: {
793 int r0
= (++it
)->u
.operand
;
794 int id0
= (++it
)->u
.operand
;
795 int isStrict
= (++it
)->u
.operand
;
796 dataLog("[%4d] resolve_base%s\t %s, %s\n", location
, isStrict
? "_strict" : "", registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
800 case op_ensure_property_exists
: {
801 int r0
= (++it
)->u
.operand
;
802 int id0
= (++it
)->u
.operand
;
803 dataLog("[%4d] ensure_property_exists\t %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data());
806 case op_resolve_with_base
: {
807 int r0
= (++it
)->u
.operand
;
808 int r1
= (++it
)->u
.operand
;
809 int id0
= (++it
)->u
.operand
;
810 dataLog("[%4d] resolve_with_base %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
814 case op_resolve_with_this
: {
815 int r0
= (++it
)->u
.operand
;
816 int r1
= (++it
)->u
.operand
;
817 int id0
= (++it
)->u
.operand
;
818 dataLog("[%4d] resolve_with_this %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
823 printGetByIdOp(exec
, location
, it
, "get_by_id");
826 case op_get_by_id_self
: {
827 printGetByIdOp(exec
, location
, it
, "get_by_id_self");
830 case op_get_by_id_proto
: {
831 printGetByIdOp(exec
, location
, it
, "get_by_id_proto");
834 case op_get_by_id_chain
: {
835 printGetByIdOp(exec
, location
, it
, "get_by_id_chain");
838 case op_get_by_id_getter_self
: {
839 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_self");
842 case op_get_by_id_getter_proto
: {
843 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_proto");
846 case op_get_by_id_getter_chain
: {
847 printGetByIdOp(exec
, location
, it
, "get_by_id_getter_chain");
850 case op_get_by_id_custom_self
: {
851 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_self");
854 case op_get_by_id_custom_proto
: {
855 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_proto");
858 case op_get_by_id_custom_chain
: {
859 printGetByIdOp(exec
, location
, it
, "get_by_id_custom_chain");
862 case op_get_by_id_generic
: {
863 printGetByIdOp(exec
, location
, it
, "get_by_id_generic");
866 case op_get_array_length
: {
867 printGetByIdOp(exec
, location
, it
, "get_array_length");
870 case op_get_string_length
: {
871 printGetByIdOp(exec
, location
, it
, "get_string_length");
874 case op_get_arguments_length
: {
875 printUnaryOp(exec
, location
, it
, "get_arguments_length");
880 printPutByIdOp(exec
, location
, it
, "put_by_id");
883 case op_put_by_id_replace
: {
884 printPutByIdOp(exec
, location
, it
, "put_by_id_replace");
887 case op_put_by_id_transition
: {
888 printPutByIdOp(exec
, location
, it
, "put_by_id_transition");
891 case op_put_by_id_transition_direct
: {
892 printPutByIdOp(exec
, location
, it
, "put_by_id_transition_direct");
895 case op_put_by_id_transition_normal
: {
896 printPutByIdOp(exec
, location
, it
, "put_by_id_transition_normal");
899 case op_put_by_id_generic
: {
900 printPutByIdOp(exec
, location
, it
, "put_by_id_generic");
903 case op_put_getter_setter
: {
904 int r0
= (++it
)->u
.operand
;
905 int id0
= (++it
)->u
.operand
;
906 int r1
= (++it
)->u
.operand
;
907 int r2
= (++it
)->u
.operand
;
908 dataLog("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
911 case op_method_check
: {
912 dataLog("[%4d] method_check\n", location
);
916 int r0
= (++it
)->u
.operand
;
917 int r1
= (++it
)->u
.operand
;
918 int id0
= (++it
)->u
.operand
;
919 dataLog("[%4d] del_by_id\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
922 case op_get_by_val
: {
923 int r0
= (++it
)->u
.operand
;
924 int r1
= (++it
)->u
.operand
;
925 int r2
= (++it
)->u
.operand
;
926 dataLog("[%4d] get_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
930 case op_get_argument_by_val
: {
931 int r0
= (++it
)->u
.operand
;
932 int r1
= (++it
)->u
.operand
;
933 int r2
= (++it
)->u
.operand
;
934 dataLog("[%4d] get_argument_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
938 case op_get_by_pname
: {
939 int r0
= (++it
)->u
.operand
;
940 int r1
= (++it
)->u
.operand
;
941 int r2
= (++it
)->u
.operand
;
942 int r3
= (++it
)->u
.operand
;
943 int r4
= (++it
)->u
.operand
;
944 int r5
= (++it
)->u
.operand
;
945 dataLog("[%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());
948 case op_put_by_val
: {
949 int r0
= (++it
)->u
.operand
;
950 int r1
= (++it
)->u
.operand
;
951 int r2
= (++it
)->u
.operand
;
952 dataLog("[%4d] put_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
955 case op_del_by_val
: {
956 int r0
= (++it
)->u
.operand
;
957 int r1
= (++it
)->u
.operand
;
958 int r2
= (++it
)->u
.operand
;
959 dataLog("[%4d] del_by_val\t %s, %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
962 case op_put_by_index
: {
963 int r0
= (++it
)->u
.operand
;
964 unsigned n0
= (++it
)->u
.operand
;
965 int r1
= (++it
)->u
.operand
;
966 dataLog("[%4d] put_by_index\t %s, %u, %s\n", location
, registerName(exec
, r0
).data(), n0
, registerName(exec
, r1
).data());
970 int offset
= (++it
)->u
.operand
;
971 dataLog("[%4d] jmp\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
975 int offset
= (++it
)->u
.operand
;
976 dataLog("[%4d] loop\t\t %d(->%d)\n", location
, offset
, location
+ offset
);
980 printConditionalJump(exec
, begin
, it
, location
, "jtrue");
983 case op_loop_if_true
: {
984 printConditionalJump(exec
, begin
, it
, location
, "loop_if_true");
987 case op_loop_if_false
: {
988 printConditionalJump(exec
, begin
, it
, location
, "loop_if_false");
992 printConditionalJump(exec
, begin
, it
, location
, "jfalse");
996 printConditionalJump(exec
, begin
, it
, location
, "jeq_null");
1000 printConditionalJump(exec
, begin
, it
, location
, "jneq_null");
1004 int r0
= (++it
)->u
.operand
;
1005 int r1
= (++it
)->u
.operand
;
1006 int offset
= (++it
)->u
.operand
;
1007 dataLog("[%4d] jneq_ptr\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 dataLog("[%4d] jless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1018 int r0
= (++it
)->u
.operand
;
1019 int r1
= (++it
)->u
.operand
;
1020 int offset
= (++it
)->u
.operand
;
1021 dataLog("[%4d] jlesseq\t\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 dataLog("[%4d] jgreater\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1031 case op_jgreatereq
: {
1032 int r0
= (++it
)->u
.operand
;
1033 int r1
= (++it
)->u
.operand
;
1034 int offset
= (++it
)->u
.operand
;
1035 dataLog("[%4d] jgreatereq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1039 int r0
= (++it
)->u
.operand
;
1040 int r1
= (++it
)->u
.operand
;
1041 int offset
= (++it
)->u
.operand
;
1042 dataLog("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1046 int r0
= (++it
)->u
.operand
;
1047 int r1
= (++it
)->u
.operand
;
1048 int offset
= (++it
)->u
.operand
;
1049 dataLog("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1052 case op_jngreater
: {
1053 int r0
= (++it
)->u
.operand
;
1054 int r1
= (++it
)->u
.operand
;
1055 int offset
= (++it
)->u
.operand
;
1056 dataLog("[%4d] jngreater\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1059 case op_jngreatereq
: {
1060 int r0
= (++it
)->u
.operand
;
1061 int r1
= (++it
)->u
.operand
;
1062 int offset
= (++it
)->u
.operand
;
1063 dataLog("[%4d] jngreatereq\t\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1066 case op_loop_if_less
: {
1067 int r0
= (++it
)->u
.operand
;
1068 int r1
= (++it
)->u
.operand
;
1069 int offset
= (++it
)->u
.operand
;
1070 dataLog("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1073 case op_loop_if_lesseq
: {
1074 int r0
= (++it
)->u
.operand
;
1075 int r1
= (++it
)->u
.operand
;
1076 int offset
= (++it
)->u
.operand
;
1077 dataLog("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1080 case op_loop_if_greater
: {
1081 int r0
= (++it
)->u
.operand
;
1082 int r1
= (++it
)->u
.operand
;
1083 int offset
= (++it
)->u
.operand
;
1084 dataLog("[%4d] loop_if_greater\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1087 case op_loop_if_greatereq
: {
1088 int r0
= (++it
)->u
.operand
;
1089 int r1
= (++it
)->u
.operand
;
1090 int offset
= (++it
)->u
.operand
;
1091 dataLog("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1094 case op_loop_hint
: {
1095 dataLog("[%4d] loop_hint\n", location
);
1098 case op_switch_imm
: {
1099 int tableIndex
= (++it
)->u
.operand
;
1100 int defaultTarget
= (++it
)->u
.operand
;
1101 int scrutineeRegister
= (++it
)->u
.operand
;
1102 dataLog("[%4d] switch_imm\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1105 case op_switch_char
: {
1106 int tableIndex
= (++it
)->u
.operand
;
1107 int defaultTarget
= (++it
)->u
.operand
;
1108 int scrutineeRegister
= (++it
)->u
.operand
;
1109 dataLog("[%4d] switch_char\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1112 case op_switch_string
: {
1113 int tableIndex
= (++it
)->u
.operand
;
1114 int defaultTarget
= (++it
)->u
.operand
;
1115 int scrutineeRegister
= (++it
)->u
.operand
;
1116 dataLog("[%4d] switch_string\t %d, %d(->%d), %s\n", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1120 int r0
= (++it
)->u
.operand
;
1121 int f0
= (++it
)->u
.operand
;
1122 int shouldCheck
= (++it
)->u
.operand
;
1123 dataLog("[%4d] new_func\t\t %s, f%d, %s\n", location
, registerName(exec
, r0
).data(), f0
, shouldCheck
? "<Checked>" : "<Unchecked>");
1126 case op_new_func_exp
: {
1127 int r0
= (++it
)->u
.operand
;
1128 int f0
= (++it
)->u
.operand
;
1129 dataLog("[%4d] new_func_exp\t %s, f%d\n", location
, registerName(exec
, r0
).data(), f0
);
1133 printCallOp(exec
, location
, it
, "call");
1136 case op_call_eval
: {
1137 printCallOp(exec
, location
, it
, "call_eval");
1140 case op_call_varargs
: {
1141 int callee
= (++it
)->u
.operand
;
1142 int thisValue
= (++it
)->u
.operand
;
1143 int arguments
= (++it
)->u
.operand
;
1144 int firstFreeRegister
= (++it
)->u
.operand
;
1145 dataLog("[%4d] call_varargs\t %s, %s, %s, %d\n", location
, registerName(exec
, callee
).data(), registerName(exec
, thisValue
).data(), registerName(exec
, arguments
).data(), firstFreeRegister
);
1148 case op_tear_off_activation
: {
1149 int r0
= (++it
)->u
.operand
;
1150 int r1
= (++it
)->u
.operand
;
1151 dataLog("[%4d] tear_off_activation\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1154 case op_tear_off_arguments
: {
1155 int r0
= (++it
)->u
.operand
;
1156 dataLog("[%4d] tear_off_arguments %s\n", location
, registerName(exec
, r0
).data());
1160 int r0
= (++it
)->u
.operand
;
1161 dataLog("[%4d] ret\t\t %s\n", location
, registerName(exec
, r0
).data());
1164 case op_call_put_result
: {
1165 int r0
= (++it
)->u
.operand
;
1166 dataLog("[%4d] op_call_put_result\t\t %s\n", location
, registerName(exec
, r0
).data());
1170 case op_ret_object_or_this
: {
1171 int r0
= (++it
)->u
.operand
;
1172 int r1
= (++it
)->u
.operand
;
1173 dataLog("[%4d] constructor_ret\t\t %s %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1176 case op_construct
: {
1177 printCallOp(exec
, location
, it
, "construct");
1181 int r0
= (++it
)->u
.operand
;
1182 int r1
= (++it
)->u
.operand
;
1183 int count
= (++it
)->u
.operand
;
1184 dataLog("[%4d] strcat\t\t %s, %s, %d\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), count
);
1187 case op_to_primitive
: {
1188 int r0
= (++it
)->u
.operand
;
1189 int r1
= (++it
)->u
.operand
;
1190 dataLog("[%4d] to_primitive\t %s, %s\n", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1193 case op_get_pnames
: {
1194 int r0
= it
[1].u
.operand
;
1195 int r1
= it
[2].u
.operand
;
1196 int r2
= it
[3].u
.operand
;
1197 int r3
= it
[4].u
.operand
;
1198 int offset
= it
[5].u
.operand
;
1199 dataLog("[%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
);
1200 it
+= OPCODE_LENGTH(op_get_pnames
) - 1;
1203 case op_next_pname
: {
1204 int dest
= it
[1].u
.operand
;
1205 int base
= it
[2].u
.operand
;
1206 int i
= it
[3].u
.operand
;
1207 int size
= it
[4].u
.operand
;
1208 int iter
= it
[5].u
.operand
;
1209 int offset
= it
[6].u
.operand
;
1210 dataLog("[%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
);
1211 it
+= OPCODE_LENGTH(op_next_pname
) - 1;
1214 case op_push_scope
: {
1215 int r0
= (++it
)->u
.operand
;
1216 dataLog("[%4d] push_scope\t %s\n", location
, registerName(exec
, r0
).data());
1219 case op_pop_scope
: {
1220 dataLog("[%4d] pop_scope\n", location
);
1223 case op_push_new_scope
: {
1224 int r0
= (++it
)->u
.operand
;
1225 int id0
= (++it
)->u
.operand
;
1226 int r1
= (++it
)->u
.operand
;
1227 dataLog("[%4d] push_new_scope \t%s, %s, %s\n", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
1230 case op_jmp_scopes
: {
1231 int scopeDelta
= (++it
)->u
.operand
;
1232 int offset
= (++it
)->u
.operand
;
1233 dataLog("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location
, scopeDelta
, offset
, location
+ offset
);
1237 int r0
= (++it
)->u
.operand
;
1238 dataLog("[%4d] catch\t\t %s\n", location
, registerName(exec
, r0
).data());
1242 int r0
= (++it
)->u
.operand
;
1243 dataLog("[%4d] throw\t\t %s\n", location
, registerName(exec
, r0
).data());
1246 case op_throw_reference_error
: {
1247 int k0
= (++it
)->u
.operand
;
1248 dataLog("[%4d] throw_reference_error\t %s\n", location
, constantName(exec
, k0
, getConstant(k0
)).data());
1252 int debugHookID
= (++it
)->u
.operand
;
1253 int firstLine
= (++it
)->u
.operand
;
1254 int lastLine
= (++it
)->u
.operand
;
1255 dataLog("[%4d] debug\t\t %s, %d, %d\n", location
, debugHookName(debugHookID
), firstLine
, lastLine
);
1258 case op_profile_will_call
: {
1259 int function
= (++it
)->u
.operand
;
1260 dataLog("[%4d] profile_will_call %s\n", location
, registerName(exec
, function
).data());
1263 case op_profile_did_call
: {
1264 int function
= (++it
)->u
.operand
;
1265 dataLog("[%4d] profile_did_call\t %s\n", location
, registerName(exec
, function
).data());
1269 int r0
= (++it
)->u
.operand
;
1270 dataLog("[%4d] end\t\t %s\n", location
, registerName(exec
, r0
).data());
1276 #if DUMP_CODE_BLOCK_STATISTICS
1277 static HashSet
<CodeBlock
*> liveCodeBlockSet
;
1280 #define FOR_EACH_MEMBER_VECTOR(macro) \
1281 macro(instructions) \
1282 macro(globalResolveInfos) \
1283 macro(structureStubInfos) \
1284 macro(callLinkInfos) \
1285 macro(linkedCallerList) \
1286 macro(identifiers) \
1287 macro(functionExpressions) \
1288 macro(constantRegisters)
1290 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1293 macro(exceptionHandlers) \
1294 macro(immediateSwitchJumpTables) \
1295 macro(characterSwitchJumpTables) \
1296 macro(stringSwitchJumpTables) \
1297 macro(evalCodeCache) \
1298 macro(expressionInfo) \
1300 macro(callReturnIndexVector)
1302 template<typename T
>
1303 static size_t sizeInBytes(const Vector
<T
>& vector
)
1305 return vector
.capacity() * sizeof(T
);
1308 void CodeBlock::dumpStatistics()
1310 #if DUMP_CODE_BLOCK_STATISTICS
1311 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1312 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS
)
1313 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS
)
1316 // Non-vector data members
1317 size_t evalCodeCacheIsNotEmpty
= 0;
1319 size_t symbolTableIsNotEmpty
= 0;
1320 size_t symbolTableTotalSize
= 0;
1322 size_t hasRareData
= 0;
1324 size_t isFunctionCode
= 0;
1325 size_t isGlobalCode
= 0;
1326 size_t isEvalCode
= 0;
1328 HashSet
<CodeBlock
*>::const_iterator end
= liveCodeBlockSet
.end();
1329 for (HashSet
<CodeBlock
*>::const_iterator it
= liveCodeBlockSet
.begin(); it
!= end
; ++it
) {
1330 CodeBlock
* codeBlock
= *it
;
1332 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1333 FOR_EACH_MEMBER_VECTOR(GET_STATS
)
1336 if (!codeBlock
->m_symbolTable
.isEmpty()) {
1337 symbolTableIsNotEmpty
++;
1338 symbolTableTotalSize
+= (codeBlock
->m_symbolTable
.capacity() * (sizeof(SymbolTable::KeyType
) + sizeof(SymbolTable::MappedType
)));
1341 if (codeBlock
->m_rareData
) {
1343 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1344 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS
)
1347 if (!codeBlock
->m_rareData
->m_evalCodeCache
.isEmpty())
1348 evalCodeCacheIsNotEmpty
++;
1351 switch (codeBlock
->codeType()) {
1364 size_t totalSize
= 0;
1366 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1367 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE
)
1368 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE
)
1369 #undef GET_TOTAL_SIZE
1371 totalSize
+= symbolTableTotalSize
;
1372 totalSize
+= (liveCodeBlockSet
.size() * sizeof(CodeBlock
));
1374 dataLog("Number of live CodeBlocks: %d\n", liveCodeBlockSet
.size());
1375 dataLog("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock
));
1376 dataLog("Size of all CodeBlocks: %zu\n", totalSize
);
1377 dataLog("Average size of a CodeBlock: %zu\n", totalSize
/ liveCodeBlockSet
.size());
1379 dataLog("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode
, static_cast<double>(isFunctionCode
) * 100.0 / liveCodeBlockSet
.size());
1380 dataLog("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode
, static_cast<double>(isGlobalCode
) * 100.0 / liveCodeBlockSet
.size());
1381 dataLog("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode
, static_cast<double>(isEvalCode
) * 100.0 / liveCodeBlockSet
.size());
1383 dataLog("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData
, static_cast<double>(hasRareData
) * 100.0 / liveCodeBlockSet
.size());
1385 #define PRINT_STATS(name) dataLog("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLog("Size of all " #name ": %zu\n", name##TotalSize);
1386 FOR_EACH_MEMBER_VECTOR(PRINT_STATS
)
1387 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS
)
1390 dataLog("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty
);
1391 dataLog("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty
);
1393 dataLog("Size of all symbolTables: %zu\n", symbolTableTotalSize
);
1396 dataLog("Dumping CodeBlock statistics is not enabled.\n");
1400 CodeBlock::CodeBlock(CopyParsedBlockTag
, CodeBlock
& other
, SymbolTable
* symTab
)
1401 : m_globalObject(other
.m_globalObject
)
1402 , m_heap(other
.m_heap
)
1403 , m_numCalleeRegisters(other
.m_numCalleeRegisters
)
1404 , m_numVars(other
.m_numVars
)
1405 , m_numCapturedVars(other
.m_numCapturedVars
)
1406 , m_isConstructor(other
.m_isConstructor
)
1407 , m_ownerExecutable(*other
.m_globalData
, other
.m_ownerExecutable
.get(), other
.m_ownerExecutable
.get())
1408 , m_globalData(other
.m_globalData
)
1409 , m_instructions(other
.m_instructions
)
1410 , m_thisRegister(other
.m_thisRegister
)
1411 , m_argumentsRegister(other
.m_argumentsRegister
)
1412 , m_activationRegister(other
.m_activationRegister
)
1413 , m_needsFullScopeChain(other
.m_needsFullScopeChain
)
1414 , m_usesEval(other
.m_usesEval
)
1415 , m_isNumericCompareFunction(other
.m_isNumericCompareFunction
)
1416 , m_isStrictMode(other
.m_isStrictMode
)
1417 , m_codeType(other
.m_codeType
)
1418 , m_source(other
.m_source
)
1419 , m_sourceOffset(other
.m_sourceOffset
)
1421 , m_globalResolveInfos(other
.m_globalResolveInfos
)
1423 #if ENABLE(VALUE_PROFILER)
1424 , m_executionEntryCount(0)
1426 , m_jumpTargets(other
.m_jumpTargets
)
1427 , m_loopTargets(other
.m_loopTargets
)
1428 , m_identifiers(other
.m_identifiers
)
1429 , m_constantRegisters(other
.m_constantRegisters
)
1430 , m_functionDecls(other
.m_functionDecls
)
1431 , m_functionExprs(other
.m_functionExprs
)
1432 , m_symbolTable(symTab
)
1433 , m_speculativeSuccessCounter(0)
1434 , m_speculativeFailCounter(0)
1435 , m_forcedOSRExitCounter(0)
1436 , m_optimizationDelayCounter(0)
1437 , m_reoptimizationRetryCounter(0)
1439 , m_canCompileWithDFGState(CompileWithDFGUnset
)
1442 setNumParameters(other
.numParameters());
1443 optimizeAfterWarmUp();
1446 if (other
.m_rareData
) {
1447 createRareDataIfNecessary();
1449 m_rareData
->m_exceptionHandlers
= other
.m_rareData
->m_exceptionHandlers
;
1450 m_rareData
->m_regexps
= other
.m_rareData
->m_regexps
;
1451 m_rareData
->m_constantBuffers
= other
.m_rareData
->m_constantBuffers
;
1452 m_rareData
->m_immediateSwitchJumpTables
= other
.m_rareData
->m_immediateSwitchJumpTables
;
1453 m_rareData
->m_characterSwitchJumpTables
= other
.m_rareData
->m_characterSwitchJumpTables
;
1454 m_rareData
->m_stringSwitchJumpTables
= other
.m_rareData
->m_stringSwitchJumpTables
;
1455 m_rareData
->m_expressionInfo
= other
.m_rareData
->m_expressionInfo
;
1456 m_rareData
->m_lineInfo
= other
.m_rareData
->m_lineInfo
;
1460 CodeBlock::CodeBlock(ScriptExecutable
* ownerExecutable
, CodeType codeType
, JSGlobalObject
*globalObject
, PassRefPtr
<SourceProvider
> sourceProvider
, unsigned sourceOffset
, SymbolTable
* symTab
, bool isConstructor
, PassOwnPtr
<CodeBlock
> alternative
)
1461 : m_globalObject(globalObject
->globalData(), ownerExecutable
, globalObject
)
1462 , m_heap(&m_globalObject
->globalData().heap
)
1463 , m_numCalleeRegisters(0)
1465 , m_isConstructor(isConstructor
)
1466 , m_numParameters(0)
1467 , m_ownerExecutable(globalObject
->globalData(), ownerExecutable
, ownerExecutable
)
1469 , m_argumentsRegister(-1)
1470 , m_needsFullScopeChain(ownerExecutable
->needsActivation())
1471 , m_usesEval(ownerExecutable
->usesEval())
1472 , m_isNumericCompareFunction(false)
1473 , m_isStrictMode(ownerExecutable
->isStrictMode())
1474 , m_codeType(codeType
)
1475 , m_source(sourceProvider
)
1476 , m_sourceOffset(sourceOffset
)
1477 #if ENABLE(VALUE_PROFILER)
1478 , m_executionEntryCount(0)
1480 , m_symbolTable(symTab
)
1481 , m_alternative(alternative
)
1482 , m_speculativeSuccessCounter(0)
1483 , m_speculativeFailCounter(0)
1484 , m_optimizationDelayCounter(0)
1485 , m_reoptimizationRetryCounter(0)
1489 optimizeAfterWarmUp();
1492 #if DUMP_CODE_BLOCK_STATISTICS
1493 liveCodeBlockSet
.add(this);
1497 CodeBlock::~CodeBlock()
1500 // Remove myself from the set of DFG code blocks. Note that I may not be in this set
1501 // (because I'm not a DFG code block), in which case this is a no-op anyway.
1502 m_globalData
->heap
.m_dfgCodeBlocks
.m_set
.remove(this);
1505 #if ENABLE(VERBOSE_VALUE_PROFILE)
1506 dumpValueProfiles();
1510 while (m_incomingLLIntCalls
.begin() != m_incomingLLIntCalls
.end())
1511 m_incomingLLIntCalls
.begin()->remove();
1512 #endif // ENABLE(LLINT)
1514 // We may be destroyed before any CodeBlocks that refer to us are destroyed.
1515 // Consider that two CodeBlocks become unreachable at the same time. There
1516 // is no guarantee about the order in which the CodeBlocks are destroyed.
1517 // So, if we don't remove incoming calls, and get destroyed before the
1518 // CodeBlock(s) that have calls into us, then the CallLinkInfo vector's
1519 // destructor will try to remove nodes from our (no longer valid) linked list.
1520 while (m_incomingCalls
.begin() != m_incomingCalls
.end())
1521 m_incomingCalls
.begin()->remove();
1523 // Note that our outgoing calls will be removed from other CodeBlocks'
1524 // m_incomingCalls linked lists through the execution of the ~CallLinkInfo
1527 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
1528 m_structureStubInfos
[i
].deref();
1529 #endif // ENABLE(JIT)
1531 #if DUMP_CODE_BLOCK_STATISTICS
1532 liveCodeBlockSet
.remove(this);
1536 void CodeBlock::setNumParameters(int newValue
)
1538 m_numParameters
= newValue
;
1540 #if ENABLE(VALUE_PROFILER)
1541 m_argumentValueProfiles
.resize(newValue
);
1545 void CodeBlock::addParameter()
1549 #if ENABLE(VALUE_PROFILER)
1550 m_argumentValueProfiles
.append(ValueProfile());
1554 void CodeBlock::visitStructures(SlotVisitor
& visitor
, Instruction
* vPC
) const
1556 Interpreter
* interpreter
= m_globalData
->interpreter
;
1558 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
) && vPC
[4].u
.structure
) {
1559 visitor
.append(&vPC
[4].u
.structure
);
1563 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
)) {
1564 visitor
.append(&vPC
[4].u
.structure
);
1567 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
)) {
1568 visitor
.append(&vPC
[4].u
.structure
);
1569 visitor
.append(&vPC
[5].u
.structure
);
1572 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
)) {
1573 visitor
.append(&vPC
[4].u
.structure
);
1574 if (vPC
[5].u
.structureChain
)
1575 visitor
.append(&vPC
[5].u
.structureChain
);
1578 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
1579 visitor
.append(&vPC
[4].u
.structure
);
1580 visitor
.append(&vPC
[5].u
.structure
);
1581 if (vPC
[6].u
.structureChain
)
1582 visitor
.append(&vPC
[6].u
.structureChain
);
1585 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
) && vPC
[4].u
.structure
) {
1586 visitor
.append(&vPC
[4].u
.structure
);
1589 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
1590 visitor
.append(&vPC
[4].u
.structure
);
1593 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global
) || vPC
[0].u
.opcode
== interpreter
->getOpcode(op_resolve_global_dynamic
)) {
1594 if (vPC
[3].u
.structure
)
1595 visitor
.append(&vPC
[3].u
.structure
);
1599 // These instructions don't ref their Structures.
1600 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
));
1603 void EvalCodeCache::visitAggregate(SlotVisitor
& visitor
)
1605 EvalCacheMap::iterator end
= m_cacheMap
.end();
1606 for (EvalCacheMap::iterator ptr
= m_cacheMap
.begin(); ptr
!= end
; ++ptr
)
1607 visitor
.append(&ptr
->second
);
1610 void CodeBlock::visitAggregate(SlotVisitor
& visitor
)
1612 #if ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
1614 // I may be asked to scan myself more than once, and it may even happen concurrently.
1615 // To this end, use a CAS loop to check if I've been called already. Only one thread
1616 // may proceed past this point - whichever one wins the CAS race.
1619 oldValue
= m_dfgData
->visitAggregateHasBeenCalled
;
1621 // Looks like someone else won! Return immediately to ensure that we don't
1622 // trace the same CodeBlock concurrently. Doing so is hazardous since we will
1623 // be mutating the state of ValueProfiles, which contain JSValues, which can
1624 // have word-tearing on 32-bit, leading to awesome timing-dependent crashes
1625 // that are nearly impossible to track down.
1627 // Also note that it must be safe to return early as soon as we see the
1628 // value true (well, (unsigned)1), since once a GC thread is in this method
1629 // and has won the CAS race (i.e. was responsible for setting the value true)
1630 // it will definitely complete the rest of this method before declaring
1634 } while (!WTF::weakCompareAndSwap(&m_dfgData
->visitAggregateHasBeenCalled
, 0, 1));
1636 #endif // ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
1638 if (!!m_alternative
)
1639 m_alternative
->visitAggregate(visitor
);
1641 // There are three things that may use unconditional finalizers: lazy bytecode freeing,
1642 // inline cache clearing, and jettisoning. The probability of us wanting to do at
1643 // least one of those things is probably quite close to 1. So we add one no matter what
1644 // and when it runs, it figures out whether it has any work to do.
1645 visitor
.addUnconditionalFinalizer(this);
1647 if (shouldImmediatelyAssumeLivenessDuringScan()) {
1648 // This code block is live, so scan all references strongly and return.
1649 stronglyVisitStrongReferences(visitor
);
1650 stronglyVisitWeakReferences(visitor
);
1655 // We get here if we're live in the sense that our owner executable is live,
1656 // but we're not yet live for sure in another sense: we may yet decide that this
1657 // code block should be jettisoned based on its outgoing weak references being
1658 // stale. Set a flag to indicate that we're still assuming that we're dead, and
1659 // perform one round of determining if we're live. The GC may determine, based on
1660 // either us marking additional objects, or by other objects being marked for
1661 // other reasons, that this iteration should run again; it will notify us of this
1662 // decision by calling harvestWeakReferences().
1664 m_dfgData
->livenessHasBeenProved
= false;
1665 m_dfgData
->allTransitionsHaveBeenMarked
= false;
1667 performTracingFixpointIteration(visitor
);
1669 // GC doesn't have enough information yet for us to decide whether to keep our DFG
1670 // data, so we need to register a handler to run again at the end of GC, when more
1671 // information is available.
1672 if (!(m_dfgData
->livenessHasBeenProved
&& m_dfgData
->allTransitionsHaveBeenMarked
))
1673 visitor
.addWeakReferenceHarvester(this);
1675 #else // ENABLE(DFG_JIT)
1676 ASSERT_NOT_REACHED();
1677 #endif // ENABLE(DFG_JIT)
1680 void CodeBlock::performTracingFixpointIteration(SlotVisitor
& visitor
)
1682 UNUSED_PARAM(visitor
);
1685 // Evaluate our weak reference transitions, if there are still some to evaluate.
1686 if (!m_dfgData
->allTransitionsHaveBeenMarked
) {
1687 bool allAreMarkedSoFar
= true;
1688 for (unsigned i
= 0; i
< m_dfgData
->transitions
.size(); ++i
) {
1689 if ((!m_dfgData
->transitions
[i
].m_codeOrigin
1690 || Heap::isMarked(m_dfgData
->transitions
[i
].m_codeOrigin
.get()))
1691 && Heap::isMarked(m_dfgData
->transitions
[i
].m_from
.get())) {
1692 // If the following three things are live, then the target of the
1693 // transition is also live:
1694 // - This code block. We know it's live already because otherwise
1695 // we wouldn't be scanning ourselves.
1696 // - The code origin of the transition. Transitions may arise from
1697 // code that was inlined. They are not relevant if the user's
1698 // object that is required for the inlinee to run is no longer
1700 // - The source of the transition. The transition checks if some
1701 // heap location holds the source, and if so, stores the target.
1702 // Hence the source must be live for the transition to be live.
1703 visitor
.append(&m_dfgData
->transitions
[i
].m_to
);
1705 allAreMarkedSoFar
= false;
1708 if (allAreMarkedSoFar
)
1709 m_dfgData
->allTransitionsHaveBeenMarked
= true;
1712 // Check if we have any remaining work to do.
1713 if (m_dfgData
->livenessHasBeenProved
)
1716 // Now check all of our weak references. If all of them are live, then we
1717 // have proved liveness and so we scan our strong references. If at end of
1718 // GC we still have not proved liveness, then this code block is toast.
1719 bool allAreLiveSoFar
= true;
1720 for (unsigned i
= 0; i
< m_dfgData
->weakReferences
.size(); ++i
) {
1721 if (!Heap::isMarked(m_dfgData
->weakReferences
[i
].get())) {
1722 allAreLiveSoFar
= false;
1727 // If some weak references are dead, then this fixpoint iteration was
1729 if (!allAreLiveSoFar
)
1732 // All weak references are live. Record this information so we don't
1733 // come back here again, and scan the strong references.
1734 m_dfgData
->livenessHasBeenProved
= true;
1735 stronglyVisitStrongReferences(visitor
);
1736 #endif // ENABLE(DFG_JIT)
1739 void CodeBlock::visitWeakReferences(SlotVisitor
& visitor
)
1741 performTracingFixpointIteration(visitor
);
1744 void CodeBlock::finalizeUnconditionally()
1747 #if ENABLE(JIT_VERBOSE_OSR)
1748 static const bool verboseUnlinking
= true;
1750 static const bool verboseUnlinking
= false;
1752 #endif // ENABLE(JIT)
1755 Interpreter
* interpreter
= m_globalData
->interpreter
;
1756 // interpreter->classicEnabled() returns true if the old C++ interpreter is enabled. If that's enabled
1757 // then we're not using LLInt.
1758 if (!interpreter
->classicEnabled() && !!numberOfInstructions()) {
1759 for (size_t size
= m_propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
) {
1760 Instruction
* curInstruction
= &instructions()[m_propertyAccessInstructions
[i
]];
1761 switch (interpreter
->getOpcodeID(curInstruction
[0].u
.opcode
)) {
1764 if (!curInstruction
[4].u
.structure
|| Heap::isMarked(curInstruction
[4].u
.structure
.get()))
1766 if (verboseUnlinking
)
1767 dataLog("Clearing LLInt property access with structure %p.\n", curInstruction
[4].u
.structure
.get());
1768 curInstruction
[4].u
.structure
.clear();
1769 curInstruction
[5].u
.operand
= 0;
1771 case op_put_by_id_transition_direct
:
1772 case op_put_by_id_transition_normal
:
1773 if (Heap::isMarked(curInstruction
[4].u
.structure
.get())
1774 && Heap::isMarked(curInstruction
[6].u
.structure
.get())
1775 && Heap::isMarked(curInstruction
[7].u
.structureChain
.get()))
1777 if (verboseUnlinking
) {
1778 dataLog("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
1779 curInstruction
[4].u
.structure
.get(),
1780 curInstruction
[6].u
.structure
.get(),
1781 curInstruction
[7].u
.structureChain
.get());
1783 curInstruction
[4].u
.structure
.clear();
1784 curInstruction
[6].u
.structure
.clear();
1785 curInstruction
[7].u
.structureChain
.clear();
1786 curInstruction
[0].u
.opcode
= interpreter
->getOpcode(op_put_by_id
);
1789 ASSERT_NOT_REACHED();
1792 for (size_t size
= m_globalResolveInstructions
.size(), i
= 0; i
< size
; ++i
) {
1793 Instruction
* curInstruction
= &instructions()[m_globalResolveInstructions
[i
]];
1794 ASSERT(interpreter
->getOpcodeID(curInstruction
[0].u
.opcode
) == op_resolve_global
1795 || interpreter
->getOpcodeID(curInstruction
[0].u
.opcode
) == op_resolve_global_dynamic
);
1796 if (!curInstruction
[3].u
.structure
|| Heap::isMarked(curInstruction
[3].u
.structure
.get()))
1798 if (verboseUnlinking
)
1799 dataLog("Clearing LLInt global resolve cache with structure %p.\n", curInstruction
[3].u
.structure
.get());
1800 curInstruction
[3].u
.structure
.clear();
1801 curInstruction
[4].u
.operand
= 0;
1803 for (unsigned i
= 0; i
< m_llintCallLinkInfos
.size(); ++i
) {
1804 if (m_llintCallLinkInfos
[i
].isLinked() && !Heap::isMarked(m_llintCallLinkInfos
[i
].callee
.get())) {
1805 if (verboseUnlinking
)
1806 dataLog("Clearing LLInt call from %p.\n", this);
1807 m_llintCallLinkInfos
[i
].unlink();
1809 if (!!m_llintCallLinkInfos
[i
].lastSeenCallee
&& !Heap::isMarked(m_llintCallLinkInfos
[i
].lastSeenCallee
.get()))
1810 m_llintCallLinkInfos
[i
].lastSeenCallee
.clear();
1813 #endif // ENABLE(LLINT)
1816 // Check if we're not live. If we are, then jettison.
1817 if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData
->livenessHasBeenProved
)) {
1818 if (verboseUnlinking
)
1819 dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this);
1821 // Make sure that the baseline JIT knows that it should re-warm-up before
1823 alternative()->optimizeAfterWarmUp();
1828 #endif // ENABLE(DFG_JIT)
1831 // Handle inline caches.
1832 if (!!getJITCode()) {
1833 RepatchBuffer
repatchBuffer(this);
1834 for (unsigned i
= 0; i
< numberOfCallLinkInfos(); ++i
) {
1835 if (callLinkInfo(i
).isLinked() && !Heap::isMarked(callLinkInfo(i
).callee
.get())) {
1836 if (verboseUnlinking
)
1837 dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i
).callee
.get());
1838 callLinkInfo(i
).unlink(*m_globalData
, repatchBuffer
);
1840 if (!!callLinkInfo(i
).lastSeenCallee
1841 && !Heap::isMarked(callLinkInfo(i
).lastSeenCallee
.get()))
1842 callLinkInfo(i
).lastSeenCallee
.clear();
1844 for (size_t size
= m_globalResolveInfos
.size(), i
= 0; i
< size
; ++i
) {
1845 if (m_globalResolveInfos
[i
].structure
&& !Heap::isMarked(m_globalResolveInfos
[i
].structure
.get())) {
1846 if (verboseUnlinking
)
1847 dataLog("Clearing resolve info in %p.\n", this);
1848 m_globalResolveInfos
[i
].structure
.clear();
1852 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
) {
1853 StructureStubInfo
& stubInfo
= m_structureStubInfos
[i
];
1855 AccessType accessType
= static_cast<AccessType
>(stubInfo
.accessType
);
1857 if (stubInfo
.visitWeakReferences())
1860 if (verboseUnlinking
)
1861 dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo
.accessType
, this);
1863 if (isGetByIdAccess(accessType
)) {
1864 if (getJITCode().jitType() == JITCode::DFGJIT
)
1865 DFG::dfgResetGetByID(repatchBuffer
, stubInfo
);
1867 JIT::resetPatchGetById(repatchBuffer
, &stubInfo
);
1869 ASSERT(isPutByIdAccess(accessType
));
1870 if (getJITCode().jitType() == JITCode::DFGJIT
)
1871 DFG::dfgResetPutByID(repatchBuffer
, stubInfo
);
1873 JIT::resetPatchPutById(repatchBuffer
, &stubInfo
);
1879 for (size_t size
= m_methodCallLinkInfos
.size(), i
= 0; i
< size
; ++i
) {
1880 if (!m_methodCallLinkInfos
[i
].cachedStructure
)
1883 ASSERT(m_methodCallLinkInfos
[i
].seenOnce());
1884 ASSERT(!!m_methodCallLinkInfos
[i
].cachedPrototypeStructure
);
1886 if (!Heap::isMarked(m_methodCallLinkInfos
[i
].cachedStructure
.get())
1887 || !Heap::isMarked(m_methodCallLinkInfos
[i
].cachedPrototypeStructure
.get())
1888 || !Heap::isMarked(m_methodCallLinkInfos
[i
].cachedFunction
.get())
1889 || !Heap::isMarked(m_methodCallLinkInfos
[i
].cachedPrototype
.get())) {
1890 if (verboseUnlinking
)
1891 dataLog("Clearing method call in %p.\n", this);
1892 m_methodCallLinkInfos
[i
].reset(repatchBuffer
, getJITType());
1894 StructureStubInfo
& stubInfo
= getStubInfo(m_methodCallLinkInfos
[i
].bytecodeIndex
);
1896 AccessType accessType
= static_cast<AccessType
>(stubInfo
.accessType
);
1898 if (accessType
!= access_unset
) {
1899 ASSERT(isGetByIdAccess(accessType
));
1900 if (getJITCode().jitType() == JITCode::DFGJIT
)
1901 DFG::dfgResetGetByID(repatchBuffer
, stubInfo
);
1903 JIT::resetPatchGetById(repatchBuffer
, &stubInfo
);
1912 void CodeBlock::stronglyVisitStrongReferences(SlotVisitor
& visitor
)
1914 visitor
.append(&m_globalObject
);
1915 visitor
.append(&m_ownerExecutable
);
1917 m_rareData
->m_evalCodeCache
.visitAggregate(visitor
);
1918 size_t regExpCount
= m_rareData
->m_regexps
.size();
1919 WriteBarrier
<RegExp
>* regexps
= m_rareData
->m_regexps
.data();
1920 for (size_t i
= 0; i
< regExpCount
; i
++)
1921 visitor
.append(regexps
+ i
);
1923 visitor
.appendValues(m_constantRegisters
.data(), m_constantRegisters
.size());
1924 for (size_t i
= 0; i
< m_functionExprs
.size(); ++i
)
1925 visitor
.append(&m_functionExprs
[i
]);
1926 for (size_t i
= 0; i
< m_functionDecls
.size(); ++i
)
1927 visitor
.append(&m_functionDecls
[i
]);
1928 #if ENABLE(CLASSIC_INTERPRETER)
1929 if (m_globalData
->interpreter
->classicEnabled() && !!numberOfInstructions()) {
1930 for (size_t size
= m_propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
)
1931 visitStructures(visitor
, &instructions()[m_propertyAccessInstructions
[i
]]);
1932 for (size_t size
= m_globalResolveInstructions
.size(), i
= 0; i
< size
; ++i
)
1933 visitStructures(visitor
, &instructions()[m_globalResolveInstructions
[i
]]);
1938 if (hasCodeOrigins()) {
1939 // Make sure that executables that we have inlined don't die.
1940 // FIXME: If they would have otherwise died, we should probably trigger recompilation.
1941 for (size_t i
= 0; i
< inlineCallFrames().size(); ++i
) {
1942 InlineCallFrame
& inlineCallFrame
= inlineCallFrames()[i
];
1943 visitor
.append(&inlineCallFrame
.executable
);
1944 visitor
.append(&inlineCallFrame
.callee
);
1948 m_lazyOperandValueProfiles
.computeUpdatedPredictions();
1951 #if ENABLE(VALUE_PROFILER)
1952 for (unsigned profileIndex
= 0; profileIndex
< numberOfArgumentValueProfiles(); ++profileIndex
)
1953 valueProfileForArgument(profileIndex
)->computeUpdatedPrediction();
1954 for (unsigned profileIndex
= 0; profileIndex
< numberOfValueProfiles(); ++profileIndex
)
1955 valueProfile(profileIndex
)->computeUpdatedPrediction();
1959 void CodeBlock::stronglyVisitWeakReferences(SlotVisitor
& visitor
)
1961 UNUSED_PARAM(visitor
);
1967 for (unsigned i
= 0; i
< m_dfgData
->transitions
.size(); ++i
) {
1968 if (!!m_dfgData
->transitions
[i
].m_codeOrigin
)
1969 visitor
.append(&m_dfgData
->transitions
[i
].m_codeOrigin
); // Almost certainly not necessary, since the code origin should also be a weak reference. Better to be safe, though.
1970 visitor
.append(&m_dfgData
->transitions
[i
].m_from
);
1971 visitor
.append(&m_dfgData
->transitions
[i
].m_to
);
1974 for (unsigned i
= 0; i
< m_dfgData
->weakReferences
.size(); ++i
)
1975 visitor
.append(&m_dfgData
->weakReferences
[i
]);
1979 HandlerInfo
* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset
)
1981 ASSERT(bytecodeOffset
< instructions().size());
1986 Vector
<HandlerInfo
>& exceptionHandlers
= m_rareData
->m_exceptionHandlers
;
1987 for (size_t i
= 0; i
< exceptionHandlers
.size(); ++i
) {
1988 // Handlers are ordered innermost first, so the first handler we encounter
1989 // that contains the source address is the correct handler to use.
1990 if (exceptionHandlers
[i
].start
<= bytecodeOffset
&& exceptionHandlers
[i
].end
>= bytecodeOffset
)
1991 return &exceptionHandlers
[i
];
1997 int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
1999 ASSERT(bytecodeOffset
< instructions().size());
2002 return m_ownerExecutable
->source().firstLine();
2004 Vector
<LineInfo
>& lineInfo
= m_rareData
->m_lineInfo
;
2007 int high
= lineInfo
.size();
2008 while (low
< high
) {
2009 int mid
= low
+ (high
- low
) / 2;
2010 if (lineInfo
[mid
].instructionOffset
<= bytecodeOffset
)
2017 return m_ownerExecutable
->source().firstLine();
2018 return lineInfo
[low
- 1].lineNumber
;
2021 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
, int& divot
, int& startOffset
, int& endOffset
)
2023 ASSERT(bytecodeOffset
< instructions().size());
2032 Vector
<ExpressionRangeInfo
>& expressionInfo
= m_rareData
->m_expressionInfo
;
2035 int high
= expressionInfo
.size();
2036 while (low
< high
) {
2037 int mid
= low
+ (high
- low
) / 2;
2038 if (expressionInfo
[mid
].instructionOffset
<= bytecodeOffset
)
2052 startOffset
= expressionInfo
[low
- 1].startOffset
;
2053 endOffset
= expressionInfo
[low
- 1].endOffset
;
2054 divot
= expressionInfo
[low
- 1].divotPoint
+ m_sourceOffset
;
2058 #if ENABLE(CLASSIC_INTERPRETER)
2059 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset
)
2061 if (m_globalResolveInstructions
.isEmpty())
2065 int high
= m_globalResolveInstructions
.size();
2066 while (low
< high
) {
2067 int mid
= low
+ (high
- low
) / 2;
2068 if (m_globalResolveInstructions
[mid
] <= bytecodeOffset
)
2074 if (!low
|| m_globalResolveInstructions
[low
- 1] != bytecodeOffset
)
2080 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset
)
2082 if (m_globalResolveInfos
.isEmpty())
2086 int high
= m_globalResolveInfos
.size();
2087 while (low
< high
) {
2088 int mid
= low
+ (high
- low
) / 2;
2089 if (m_globalResolveInfos
[mid
].bytecodeOffset
<= bytecodeOffset
)
2095 if (!low
|| m_globalResolveInfos
[low
- 1].bytecodeOffset
!= bytecodeOffset
)
2101 void CodeBlock::shrinkToFit()
2103 #if ENABLE(CLASSIC_INTERPRETER)
2104 m_propertyAccessInstructions
.shrinkToFit();
2105 m_globalResolveInstructions
.shrinkToFit();
2108 m_structureStubInfos
.shrinkToFit();
2109 m_globalResolveInfos
.shrinkToFit();
2110 m_callLinkInfos
.shrinkToFit();
2113 m_identifiers
.shrinkToFit();
2114 m_functionDecls
.shrinkToFit();
2115 m_functionExprs
.shrinkToFit();
2116 m_constantRegisters
.shrinkToFit();
2119 m_rareData
->m_exceptionHandlers
.shrinkToFit();
2120 m_rareData
->m_regexps
.shrinkToFit();
2121 m_rareData
->m_immediateSwitchJumpTables
.shrinkToFit();
2122 m_rareData
->m_characterSwitchJumpTables
.shrinkToFit();
2123 m_rareData
->m_stringSwitchJumpTables
.shrinkToFit();
2124 m_rareData
->m_expressionInfo
.shrinkToFit();
2125 m_rareData
->m_lineInfo
.shrinkToFit();
2129 void CodeBlock::createActivation(CallFrame
* callFrame
)
2131 ASSERT(codeType() == FunctionCode
);
2132 ASSERT(needsFullScopeChain());
2133 ASSERT(!callFrame
->uncheckedR(activationRegister()).jsValue());
2134 JSActivation
* activation
= JSActivation::create(callFrame
->globalData(), callFrame
, static_cast<FunctionExecutable
*>(ownerExecutable()));
2135 callFrame
->uncheckedR(activationRegister()) = JSValue(activation
);
2136 callFrame
->setScopeChain(callFrame
->scopeChain()->push(activation
));
2139 unsigned CodeBlock::addOrFindConstant(JSValue v
)
2141 unsigned numberOfConstants
= numberOfConstantRegisters();
2142 for (unsigned i
= 0; i
< numberOfConstants
; ++i
) {
2143 if (getConstant(FirstConstantRegisterIndex
+ i
) == v
)
2146 return addConstant(v
);
2150 void CodeBlock::unlinkCalls()
2152 if (!!m_alternative
)
2153 m_alternative
->unlinkCalls();
2155 for (size_t i
= 0; i
< m_llintCallLinkInfos
.size(); ++i
) {
2156 if (m_llintCallLinkInfos
[i
].isLinked())
2157 m_llintCallLinkInfos
[i
].unlink();
2160 if (!(m_callLinkInfos
.size() || m_methodCallLinkInfos
.size()))
2162 if (!m_globalData
->canUseJIT())
2164 RepatchBuffer
repatchBuffer(this);
2165 for (size_t i
= 0; i
< m_callLinkInfos
.size(); i
++) {
2166 if (!m_callLinkInfos
[i
].isLinked())
2168 m_callLinkInfos
[i
].unlink(*m_globalData
, repatchBuffer
);
2172 void CodeBlock::unlinkIncomingCalls()
2175 while (m_incomingLLIntCalls
.begin() != m_incomingLLIntCalls
.end())
2176 m_incomingLLIntCalls
.begin()->unlink();
2178 if (m_incomingCalls
.isEmpty())
2180 RepatchBuffer
repatchBuffer(this);
2181 while (m_incomingCalls
.begin() != m_incomingCalls
.end())
2182 m_incomingCalls
.begin()->unlink(*m_globalData
, repatchBuffer
);
2185 unsigned CodeBlock::bytecodeOffset(ExecState
* exec
, ReturnAddressPtr returnAddress
)
2188 if (returnAddress
.value() >= bitwise_cast
<void*>(&llint_begin
)
2189 && returnAddress
.value() <= bitwise_cast
<void*>(&llint_end
)) {
2190 ASSERT(exec
->codeBlock());
2191 ASSERT(exec
->codeBlock() == this);
2192 ASSERT(JITCode::isBaselineCode(getJITType()));
2193 Instruction
* instruction
= exec
->currentVPC();
2194 ASSERT(instruction
);
2196 // The LLInt stores the PC after the call instruction rather than the PC of
2197 // the call instruction. This requires some correcting. We rely on the fact
2198 // that the preceding instruction must be one of the call instructions, so
2199 // either it's a call_varargs or it's a call, construct, or eval.
2200 ASSERT(OPCODE_LENGTH(op_call_varargs
) <= OPCODE_LENGTH(op_call
));
2201 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_construct
));
2202 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_call_eval
));
2203 if (instruction
[-OPCODE_LENGTH(op_call_varargs
)].u
.pointer
== bitwise_cast
<void*>(llint_op_call_varargs
)) {
2204 // We know that the preceding instruction must be op_call_varargs because there is no way that
2205 // the pointer to the call_varargs could be an operand to the call.
2206 instruction
-= OPCODE_LENGTH(op_call_varargs
);
2207 ASSERT(instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
!= bitwise_cast
<void*>(llint_op_call
)
2208 && instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
!= bitwise_cast
<void*>(llint_op_construct
)
2209 && instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
!= bitwise_cast
<void*>(llint_op_call_eval
));
2211 // Must be that the last instruction was some op_call.
2212 ASSERT(instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
== bitwise_cast
<void*>(llint_op_call
)
2213 || instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
== bitwise_cast
<void*>(llint_op_construct
)
2214 || instruction
[-OPCODE_LENGTH(op_call
)].u
.pointer
== bitwise_cast
<void*>(llint_op_call_eval
));
2215 instruction
-= OPCODE_LENGTH(op_call
);
2218 return bytecodeOffset(instruction
);
2225 Vector
<CallReturnOffsetToBytecodeOffset
>& callIndices
= m_rareData
->m_callReturnIndexVector
;
2226 if (!callIndices
.size())
2228 return binarySearch
<CallReturnOffsetToBytecodeOffset
, unsigned, getCallReturnOffset
>(callIndices
.begin(), callIndices
.size(), getJITCode().offsetOf(returnAddress
.value()))->bytecodeOffset
;
2232 void CodeBlock::clearEvalCache()
2234 if (!!m_alternative
)
2235 m_alternative
->clearEvalCache();
2238 m_rareData
->m_evalCodeCache
.clear();
2241 template<typename T
>
2242 inline void replaceExistingEntries(Vector
<T
>& target
, Vector
<T
>& source
)
2244 ASSERT(target
.size() <= source
.size());
2245 for (size_t i
= 0; i
< target
.size(); ++i
)
2246 target
[i
] = source
[i
];
2249 void CodeBlock::copyPostParseDataFrom(CodeBlock
* alternative
)
2254 replaceExistingEntries(m_constantRegisters
, alternative
->m_constantRegisters
);
2255 replaceExistingEntries(m_functionDecls
, alternative
->m_functionDecls
);
2256 replaceExistingEntries(m_functionExprs
, alternative
->m_functionExprs
);
2257 if (!!m_rareData
&& !!alternative
->m_rareData
)
2258 replaceExistingEntries(m_rareData
->m_constantBuffers
, alternative
->m_rareData
->m_constantBuffers
);
2261 void CodeBlock::copyPostParseDataFromAlternative()
2263 copyPostParseDataFrom(m_alternative
.get());
2267 CodeBlock
* ProgramCodeBlock::replacement()
2269 return &static_cast<ProgramExecutable
*>(ownerExecutable())->generatedBytecode();
2272 CodeBlock
* EvalCodeBlock::replacement()
2274 return &static_cast<EvalExecutable
*>(ownerExecutable())->generatedBytecode();
2277 CodeBlock
* FunctionCodeBlock::replacement()
2279 return &static_cast<FunctionExecutable
*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor
? CodeForConstruct
: CodeForCall
);
2282 JSObject
* ProgramCodeBlock::compileOptimized(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
2284 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2286 JSObject
* error
= static_cast<ProgramExecutable
*>(ownerExecutable())->compileOptimized(exec
, scopeChainNode
);
2290 JSObject
* EvalCodeBlock::compileOptimized(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
2292 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2294 JSObject
* error
= static_cast<EvalExecutable
*>(ownerExecutable())->compileOptimized(exec
, scopeChainNode
);
2298 JSObject
* FunctionCodeBlock::compileOptimized(ExecState
* exec
, ScopeChainNode
* scopeChainNode
)
2300 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2302 JSObject
* error
= static_cast<FunctionExecutable
*>(ownerExecutable())->compileOptimizedFor(exec
, scopeChainNode
, m_isConstructor
? CodeForConstruct
: CodeForCall
);
2306 bool ProgramCodeBlock::canCompileWithDFGInternal()
2308 return DFG::canCompileProgram(this);
2311 bool EvalCodeBlock::canCompileWithDFGInternal()
2313 return DFG::canCompileEval(this);
2316 bool FunctionCodeBlock::canCompileWithDFGInternal()
2318 if (m_isConstructor
)
2319 return DFG::canCompileFunctionForConstruct(this);
2320 return DFG::canCompileFunctionForCall(this);
2323 void ProgramCodeBlock::jettison()
2325 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2326 ASSERT(this == replacement());
2327 static_cast<ProgramExecutable
*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
2330 void EvalCodeBlock::jettison()
2332 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2333 ASSERT(this == replacement());
2334 static_cast<EvalExecutable
*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
2337 void FunctionCodeBlock::jettison()
2339 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2340 ASSERT(this == replacement());
2341 static_cast<FunctionExecutable
*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor
? CodeForConstruct
: CodeForCall
);
2344 bool ProgramCodeBlock::jitCompileImpl(JSGlobalData
& globalData
)
2346 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2347 ASSERT(this == replacement());
2348 return static_cast<ProgramExecutable
*>(ownerExecutable())->jitCompile(globalData
);
2351 bool EvalCodeBlock::jitCompileImpl(JSGlobalData
& globalData
)
2353 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2354 ASSERT(this == replacement());
2355 return static_cast<EvalExecutable
*>(ownerExecutable())->jitCompile(globalData
);
2358 bool FunctionCodeBlock::jitCompileImpl(JSGlobalData
& globalData
)
2360 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2361 ASSERT(this == replacement());
2362 return static_cast<FunctionExecutable
*>(ownerExecutable())->jitCompileFor(globalData
, m_isConstructor
? CodeForConstruct
: CodeForCall
);
2366 #if ENABLE(VALUE_PROFILER)
2367 bool CodeBlock::shouldOptimizeNow()
2369 #if ENABLE(JIT_VERBOSE_OSR)
2370 dataLog("Considering optimizing %p...\n", this);
2373 #if ENABLE(VERBOSE_VALUE_PROFILE)
2374 dumpValueProfiles();
2377 if (m_optimizationDelayCounter
>= Options::maximumOptimizationDelay
)
2380 unsigned numberOfLiveNonArgumentValueProfiles
= 0;
2381 unsigned numberOfSamplesInProfiles
= 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
2382 for (unsigned i
= 0; i
< totalNumberOfValueProfiles(); ++i
) {
2383 ValueProfile
* profile
= getFromAllValueProfiles(i
);
2384 unsigned numSamples
= profile
->totalNumberOfSamples();
2385 if (numSamples
> ValueProfile::numberOfBuckets
)
2386 numSamples
= ValueProfile::numberOfBuckets
; // We don't want profiles that are extremely hot to be given more weight.
2387 numberOfSamplesInProfiles
+= numSamples
;
2388 if (profile
->m_bytecodeOffset
< 0) {
2389 profile
->computeUpdatedPrediction();
2392 if (profile
->numberOfSamples() || profile
->m_prediction
!= PredictNone
)
2393 numberOfLiveNonArgumentValueProfiles
++;
2394 profile
->computeUpdatedPrediction();
2397 #if ENABLE(JIT_VERBOSE_OSR)
2398 dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles
/ numberOfValueProfiles(), (double)numberOfSamplesInProfiles
/ ValueProfile::numberOfBuckets
/ numberOfValueProfiles());
2401 if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles
/ numberOfValueProfiles() >= Options::desiredProfileLivenessRate
)
2402 && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles
/ ValueProfile::numberOfBuckets
/ totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate
)
2403 && static_cast<unsigned>(m_optimizationDelayCounter
) + 1 >= Options::minimumOptimizationDelay
)
2406 ASSERT(m_optimizationDelayCounter
< std::numeric_limits
<uint8_t>::max());
2407 m_optimizationDelayCounter
++;
2408 optimizeAfterWarmUp();
2414 void CodeBlock::tallyFrequentExitSites()
2416 ASSERT(getJITType() == JITCode::DFGJIT
);
2417 ASSERT(alternative()->getJITType() == JITCode::BaselineJIT
);
2418 ASSERT(!!m_dfgData
);
2420 CodeBlock
* profiledBlock
= alternative();
2422 for (unsigned i
= 0; i
< m_dfgData
->osrExit
.size(); ++i
) {
2423 DFG::OSRExit
& exit
= m_dfgData
->osrExit
[i
];
2425 if (!exit
.considerAddingAsFrequentExitSite(this, profiledBlock
))
2428 #if DFG_ENABLE(DEBUG_VERBOSE)
2429 dataLog("OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i
, exit
.m_codeOrigin
.bytecodeIndex
, exit
.m_nodeIndex
, DFG::exitKindToString(exit
.m_kind
), this);
2433 #endif // ENABLE(DFG_JIT)
2435 #if ENABLE(VERBOSE_VALUE_PROFILE)
2436 void CodeBlock::dumpValueProfiles()
2438 dataLog("ValueProfile for %p:\n", this);
2439 for (unsigned i
= 0; i
< totalNumberOfValueProfiles(); ++i
) {
2440 ValueProfile
* profile
= getFromAllValueProfiles(i
);
2441 if (profile
->m_bytecodeOffset
< 0) {
2442 ASSERT(profile
->m_bytecodeOffset
== -1);
2443 dataLog(" arg = %u: ", i
);
2445 dataLog(" bc = %d: ", profile
->m_bytecodeOffset
);
2446 if (!profile
->numberOfSamples() && profile
->m_prediction
== PredictNone
) {
2447 dataLog("<empty>\n");
2450 profile
->dump(WTF::dataFile());
2453 dataLog("RareCaseProfile for %p:\n", this);
2454 for (unsigned i
= 0; i
< numberOfRareCaseProfiles(); ++i
) {
2455 RareCaseProfile
* profile
= rareCaseProfile(i
);
2456 dataLog(" bc = %d: %u\n", profile
->m_bytecodeOffset
, profile
->m_counter
);
2458 dataLog("SpecialFastCaseProfile for %p:\n", this);
2459 for (unsigned i
= 0; i
< numberOfSpecialFastCaseProfiles(); ++i
) {
2460 RareCaseProfile
* profile
= specialFastCaseProfile(i
);
2461 dataLog(" bc = %d: %u\n", profile
->m_bytecodeOffset
, profile
->m_counter
);
2466 size_t CodeBlock::predictedMachineCodeSize()
2468 // This will be called from CodeBlock::CodeBlock before either m_globalData or the
2469 // instructions have been initialized. It's OK to return 0 because what will really
2470 // matter is the recomputation of this value when the slow path is triggered.
2474 if (!m_globalData
->machineCodeBytesPerBytecodeWordForBaselineJIT
)
2475 return 0; // It's as good of a prediction as we'll get.
2477 // Be conservative: return a size that will be an overestimation 84% of the time.
2478 double multiplier
= m_globalData
->machineCodeBytesPerBytecodeWordForBaselineJIT
.mean() +
2479 m_globalData
->machineCodeBytesPerBytecodeWordForBaselineJIT
.standardDeviation();
2481 // Be paranoid: silently reject bogus multipiers. Silently doing the "wrong" thing
2482 // here is OK, since this whole method is just a heuristic.
2483 if (multiplier
< 0 || multiplier
> 1000)
2486 double doubleResult
= multiplier
* m_instructions
.size();
2488 // Be even more paranoid: silently reject values that won't fit into a size_t. If
2489 // the function is so huge that we can't even fit it into virtual memory then we
2490 // should probably have some other guards in place to prevent us from even getting
2492 if (doubleResult
> std::numeric_limits
<size_t>::max())
2495 return static_cast<size_t>(doubleResult
);
2498 bool CodeBlock::usesOpcode(OpcodeID opcodeID
)
2500 Interpreter
* interpreter
= globalData()->interpreter
;
2501 Instruction
* instructionsBegin
= instructions().begin();
2502 unsigned instructionCount
= instructions().size();
2504 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
; ) {
2505 switch (interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
)) {
2506 #define DEFINE_OP(curOpcode, length) \
2508 if (curOpcode == opcodeID) \
2510 bytecodeOffset += length; \
2512 FOR_EACH_OPCODE_ID(DEFINE_OP
)
2515 ASSERT_NOT_REACHED();