2 * Copyright (C) 2008, 2009, 2010, 2012, 2013 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 "CallLinkStatus.h"
35 #include "DFGCapabilities.h"
36 #include "DFGCommon.h"
38 #include "DFGRepatch.h"
40 #include "Interpreter.h"
43 #include "JSActivation.h"
44 #include "JSCJSValue.h"
45 #include "JSFunction.h"
46 #include "JSNameScope.h"
47 #include "LowLevelInterpreter.h"
48 #include "Operations.h"
49 #include "ReduceWhitespace.h"
50 #include "RepatchBuffer.h"
51 #include "SlotVisitorInlines.h"
53 #include <wtf/CommaPrinter.h>
54 #include <wtf/StringExtras.h>
55 #include <wtf/StringPrintStream.h>
58 #include "DFGOperations.h"
61 #define DUMP_CODE_BLOCK_STATISTICS 0
69 String
CodeBlock::inferredName() const
77 return jsCast
<FunctionExecutable
*>(ownerExecutable())->inferredName().string();
84 CodeBlockHash
CodeBlock::hash() const
86 return CodeBlockHash(ownerExecutable()->source(), specializationKind());
89 String
CodeBlock::sourceCodeForTools() const
91 if (codeType() != FunctionCode
)
92 return ownerExecutable()->source().toString();
94 SourceProvider
* provider
= source();
95 FunctionExecutable
* executable
= jsCast
<FunctionExecutable
*>(ownerExecutable());
96 UnlinkedFunctionExecutable
* unlinked
= executable
->unlinkedExecutable();
97 unsigned unlinkedStartOffset
= unlinked
->startOffset();
98 unsigned linkedStartOffset
= executable
->source().startOffset();
99 int delta
= linkedStartOffset
- unlinkedStartOffset
;
100 StringBuilder builder
;
101 builder
.append("function ");
102 builder
.append(provider
->getRange(
103 delta
+ unlinked
->functionStartOffset(),
104 delta
+ unlinked
->startOffset() + unlinked
->sourceLength()));
105 return builder
.toString();
108 String
CodeBlock::sourceCodeOnOneLine() const
110 return reduceWhitespace(sourceCodeForTools());
113 void CodeBlock::dumpAssumingJITType(PrintStream
& out
, JITCode::JITType jitType
) const
115 out
.print(inferredName(), "#", hash(), ":[", RawPointer(this), "->", RawPointer(ownerExecutable()), ", ", jitType
, codeType());
116 if (codeType() == FunctionCode
)
117 out
.print(specializationKind());
121 void CodeBlock::dump(PrintStream
& out
) const
123 dumpAssumingJITType(out
, getJITType());
126 static String
escapeQuotes(const String
& str
)
130 while ((pos
= result
.find('\"', pos
)) != notFound
) {
131 result
= makeString(result
.substringSharingImpl(0, pos
), "\"\\\"\"", result
.substringSharingImpl(pos
+ 1));
137 static String
valueToSourceString(ExecState
* exec
, JSValue val
)
140 return ASCIILiteral("0");
143 return makeString("\"", escapeQuotes(val
.toString(exec
)->value(exec
)), "\"");
145 return toString(val
);
148 static CString
constantName(ExecState
* exec
, int k
, JSValue value
)
150 return makeString(valueToSourceString(exec
, value
), "(@k", String::number(k
- FirstConstantRegisterIndex
), ")").utf8();
153 static CString
idName(int id0
, const Identifier
& ident
)
155 return makeString(ident
.string(), "(@id", String::number(id0
), ")").utf8();
158 CString
CodeBlock::registerName(ExecState
* exec
, int r
) const
160 if (r
== missingThisObjectMarker())
163 if (isConstantRegisterIndex(r
))
164 return constantName(exec
, r
, getConstant(r
));
166 return makeString("r", String::number(r
)).utf8();
169 static String
regexpToSourceString(RegExp
* regExp
)
171 char postfix
[5] = { '/', 0, 0, 0, 0 };
173 if (regExp
->global())
174 postfix
[index
++] = 'g';
175 if (regExp
->ignoreCase())
176 postfix
[index
++] = 'i';
177 if (regExp
->multiline())
178 postfix
[index
] = 'm';
180 return makeString("/", regExp
->pattern(), postfix
);
183 static CString
regexpName(int re
, RegExp
* regexp
)
185 return makeString(regexpToSourceString(regexp
), "(@re", String::number(re
), ")").utf8();
188 static String
pointerToSourceString(void* p
)
190 char buffer
[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
191 snprintf(buffer
, sizeof(buffer
), "%p", p
);
195 NEVER_INLINE
static const char* debugHookName(int debugHookID
)
197 switch (static_cast<DebugHookID
>(debugHookID
)) {
198 case DidEnterCallFrame
:
199 return "didEnterCallFrame";
200 case WillLeaveCallFrame
:
201 return "willLeaveCallFrame";
202 case WillExecuteStatement
:
203 return "willExecuteStatement";
204 case WillExecuteProgram
:
205 return "willExecuteProgram";
206 case DidExecuteProgram
:
207 return "didExecuteProgram";
208 case DidReachBreakpoint
:
209 return "didReachBreakpoint";
212 RELEASE_ASSERT_NOT_REACHED();
216 void CodeBlock::printUnaryOp(PrintStream
& out
, ExecState
* exec
, int location
, const Instruction
*& it
, const char* op
)
218 int r0
= (++it
)->u
.operand
;
219 int r1
= (++it
)->u
.operand
;
221 out
.printf("[%4d] %s\t\t %s, %s", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
224 void CodeBlock::printBinaryOp(PrintStream
& out
, ExecState
* exec
, int location
, const Instruction
*& it
, const char* op
)
226 int r0
= (++it
)->u
.operand
;
227 int r1
= (++it
)->u
.operand
;
228 int r2
= (++it
)->u
.operand
;
229 out
.printf("[%4d] %s\t\t %s, %s, %s", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
232 void CodeBlock::printConditionalJump(PrintStream
& out
, ExecState
* exec
, const Instruction
*, const Instruction
*& it
, int location
, const char* op
)
234 int r0
= (++it
)->u
.operand
;
235 int offset
= (++it
)->u
.operand
;
236 out
.printf("[%4d] %s\t\t %s, %d(->%d)", location
, op
, registerName(exec
, r0
).data(), offset
, location
+ offset
);
239 void CodeBlock::printGetByIdOp(PrintStream
& out
, ExecState
* exec
, int location
, const Instruction
*& it
)
242 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
246 case op_get_by_id_out_of_line
:
247 op
= "get_by_id_out_of_line";
249 case op_get_by_id_self
:
250 op
= "get_by_id_self";
252 case op_get_by_id_proto
:
253 op
= "get_by_id_proto";
255 case op_get_by_id_chain
:
256 op
= "get_by_id_chain";
258 case op_get_by_id_getter_self
:
259 op
= "get_by_id_getter_self";
261 case op_get_by_id_getter_proto
:
262 op
= "get_by_id_getter_proto";
264 case op_get_by_id_getter_chain
:
265 op
= "get_by_id_getter_chain";
267 case op_get_by_id_custom_self
:
268 op
= "get_by_id_custom_self";
270 case op_get_by_id_custom_proto
:
271 op
= "get_by_id_custom_proto";
273 case op_get_by_id_custom_chain
:
274 op
= "get_by_id_custom_chain";
276 case op_get_by_id_generic
:
277 op
= "get_by_id_generic";
279 case op_get_array_length
:
282 case op_get_string_length
:
283 op
= "string_length";
286 RELEASE_ASSERT_NOT_REACHED();
289 int r0
= (++it
)->u
.operand
;
290 int r1
= (++it
)->u
.operand
;
291 int id0
= (++it
)->u
.operand
;
292 out
.printf("[%4d] %s\t %s, %s, %s", location
, op
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
293 it
+= 4; // Increment up to the value profiler.
296 #if ENABLE(JIT) || ENABLE(LLINT) // unused in some configurations
297 static void dumpStructure(PrintStream
& out
, const char* name
, ExecState
* exec
, Structure
* structure
, Identifier
& ident
)
302 out
.printf("%s = %p", name
, structure
);
304 PropertyOffset offset
= structure
->get(exec
->vm(), ident
);
305 if (offset
!= invalidOffset
)
306 out
.printf(" (offset = %d)", offset
);
310 #if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings
311 static void dumpChain(PrintStream
& out
, ExecState
* exec
, StructureChain
* chain
, Identifier
& ident
)
313 out
.printf("chain = %p: [", chain
);
315 for (WriteBarrier
<Structure
>* currentStructure
= chain
->head();
317 ++currentStructure
) {
322 dumpStructure(out
, "struct", exec
, currentStructure
->get(), ident
);
328 void CodeBlock::printGetByIdCacheStatus(PrintStream
& out
, ExecState
* exec
, int location
)
330 Instruction
* instruction
= instructions().begin() + location
;
332 Identifier
& ident
= identifier(instruction
[3].u
.operand
);
334 UNUSED_PARAM(ident
); // tell the compiler to shut up in certain platform configurations.
337 if (exec
->interpreter()->getOpcodeID(instruction
[0].u
.opcode
) == op_get_array_length
)
338 out
.printf(" llint(array_length)");
339 else if (Structure
* structure
= instruction
[4].u
.structure
.get()) {
340 out
.printf(" llint(");
341 dumpStructure(out
, "struct", exec
, structure
, ident
);
347 if (numberOfStructureStubInfos()) {
348 StructureStubInfo
& stubInfo
= getStubInfo(location
);
352 Structure
* baseStructure
= 0;
353 Structure
* prototypeStructure
= 0;
354 StructureChain
* chain
= 0;
355 PolymorphicAccessStructureList
* structureList
= 0;
358 switch (stubInfo
.accessType
) {
359 case access_get_by_id_self
:
361 baseStructure
= stubInfo
.u
.getByIdSelf
.baseObjectStructure
.get();
363 case access_get_by_id_proto
:
365 baseStructure
= stubInfo
.u
.getByIdProto
.baseObjectStructure
.get();
366 prototypeStructure
= stubInfo
.u
.getByIdProto
.prototypeStructure
.get();
368 case access_get_by_id_chain
:
370 baseStructure
= stubInfo
.u
.getByIdChain
.baseObjectStructure
.get();
371 chain
= stubInfo
.u
.getByIdChain
.chain
.get();
373 case access_get_by_id_self_list
:
374 out
.printf("self_list");
375 structureList
= stubInfo
.u
.getByIdSelfList
.structureList
;
376 listSize
= stubInfo
.u
.getByIdSelfList
.listSize
;
378 case access_get_by_id_proto_list
:
379 out
.printf("proto_list");
380 structureList
= stubInfo
.u
.getByIdProtoList
.structureList
;
381 listSize
= stubInfo
.u
.getByIdProtoList
.listSize
;
386 case access_get_by_id_generic
:
387 out
.printf("generic");
389 case access_get_array_length
:
390 out
.printf("array_length");
392 case access_get_string_length
:
393 out
.printf("string_length");
396 RELEASE_ASSERT_NOT_REACHED();
402 dumpStructure(out
, "struct", exec
, baseStructure
, ident
);
405 if (prototypeStructure
) {
407 dumpStructure(out
, "prototypeStruct", exec
, baseStructure
, ident
);
412 dumpChain(out
, exec
, chain
, ident
);
416 out
.printf(", list = %p: [", structureList
);
417 for (int i
= 0; i
< listSize
; ++i
) {
421 dumpStructure(out
, "base", exec
, structureList
->list
[i
].base
.get(), ident
);
422 if (structureList
->list
[i
].isChain
) {
423 if (structureList
->list
[i
].u
.chain
.get()) {
425 dumpChain(out
, exec
, structureList
->list
[i
].u
.chain
.get(), ident
);
428 if (structureList
->list
[i
].u
.proto
.get()) {
430 dumpStructure(out
, "proto", exec
, structureList
->list
[i
].u
.proto
.get(), ident
);
443 void CodeBlock::printCallOp(PrintStream
& out
, ExecState
* exec
, int location
, const Instruction
*& it
, const char* op
, CacheDumpMode cacheDumpMode
)
445 int func
= (++it
)->u
.operand
;
446 int argCount
= (++it
)->u
.operand
;
447 int registerOffset
= (++it
)->u
.operand
;
448 out
.printf("[%4d] %s\t %s, %d, %d", location
, op
, registerName(exec
, func
).data(), argCount
, registerOffset
);
449 if (cacheDumpMode
== DumpCaches
) {
451 LLIntCallLinkInfo
* callLinkInfo
= it
[1].u
.callLinkInfo
;
452 if (callLinkInfo
->lastSeenCallee
) {
454 " llint(%p, exec %p)",
455 callLinkInfo
->lastSeenCallee
.get(),
456 callLinkInfo
->lastSeenCallee
->executable());
460 if (numberOfCallLinkInfos()) {
461 JSFunction
* target
= getCallLinkInfo(location
).lastSeenCallee
.get();
463 out
.printf(" jit(%p, exec %p)", target
, target
->executable());
466 out
.print(" status(", CallLinkStatus::computeFor(this, location
), ")");
471 void CodeBlock::printPutByIdOp(PrintStream
& out
, ExecState
* exec
, int location
, const Instruction
*& it
, const char* op
)
473 int r0
= (++it
)->u
.operand
;
474 int id0
= (++it
)->u
.operand
;
475 int r1
= (++it
)->u
.operand
;
476 out
.printf("[%4d] %s\t %s, %s, %s", location
, op
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data());
480 void CodeBlock::printStructure(PrintStream
& out
, const char* name
, const Instruction
* vPC
, int operand
)
482 unsigned instructionOffset
= vPC
- instructions().begin();
483 out
.printf(" [%4d] %s: %s\n", instructionOffset
, name
, pointerToSourceString(vPC
[operand
].u
.structure
).utf8().data());
486 void CodeBlock::printStructures(PrintStream
& out
, const Instruction
* vPC
)
488 Interpreter
* interpreter
= m_vm
->interpreter
;
489 unsigned instructionOffset
= vPC
- instructions().begin();
491 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
)) {
492 printStructure(out
, "get_by_id", vPC
, 4);
495 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_self
)) {
496 printStructure(out
, "get_by_id_self", vPC
, 4);
499 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_proto
)) {
500 out
.printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_proto", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structure
).utf8().data());
503 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
504 out
.printf(" [%4d] %s: %s, %s, %s\n", instructionOffset
, "put_by_id_transition", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structure
).utf8().data(), pointerToSourceString(vPC
[6].u
.structureChain
).utf8().data());
507 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id_chain
)) {
508 out
.printf(" [%4d] %s: %s, %s\n", instructionOffset
, "get_by_id_chain", pointerToSourceString(vPC
[4].u
.structure
).utf8().data(), pointerToSourceString(vPC
[5].u
.structureChain
).utf8().data());
511 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
)) {
512 printStructure(out
, "put_by_id", vPC
, 4);
515 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
516 printStructure(out
, "put_by_id_replace", vPC
, 4);
520 // These m_instructions doesn't ref Structures.
521 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
));
524 void CodeBlock::dumpBytecode(PrintStream
& out
)
526 // We only use the ExecState* for things that don't actually lead to JS execution,
527 // like converting a JSString to a String. Hence the globalExec is appropriate.
528 ExecState
* exec
= m_globalObject
->globalExec();
530 size_t instructionCount
= 0;
532 for (size_t i
= 0; i
< instructions().size(); i
+= opcodeLengths
[exec
->interpreter()->getOpcodeID(instructions()[i
].u
.opcode
)])
537 ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
538 static_cast<unsigned long>(instructions().size()),
539 static_cast<unsigned long>(instructions().size() * sizeof(Instruction
)),
540 m_numParameters
, m_numCalleeRegisters
, m_numVars
);
541 if (symbolTable() && symbolTable()->captureCount()) {
543 "; %d captured var(s) (from r%d to r%d, inclusive)",
544 symbolTable()->captureCount(), symbolTable()->captureStart(), symbolTable()->captureEnd() - 1);
546 if (usesArguments()) {
548 "; uses arguments, in r%d, r%d",
550 unmodifiedArgumentsRegister(argumentsRegister()));
552 if (needsFullScopeChain() && codeType() == FunctionCode
)
553 out
.printf("; activation in r%d", activationRegister());
554 out
.print("\n\nSource: ", sourceCodeOnOneLine(), "\n\n");
556 const Instruction
* begin
= instructions().begin();
557 const Instruction
* end
= instructions().end();
558 for (const Instruction
* it
= begin
; it
!= end
; ++it
)
559 dumpBytecode(out
, exec
, begin
, it
);
561 if (!m_identifiers
.isEmpty()) {
562 out
.printf("\nIdentifiers:\n");
565 out
.printf(" id%u = %s\n", static_cast<unsigned>(i
), m_identifiers
[i
].string().utf8().data());
567 } while (i
!= m_identifiers
.size());
570 if (!m_constantRegisters
.isEmpty()) {
571 out
.printf("\nConstants:\n");
574 out
.printf(" k%u = %s\n", static_cast<unsigned>(i
), valueToSourceString(exec
, m_constantRegisters
[i
].get()).utf8().data());
576 } while (i
< m_constantRegisters
.size());
579 if (size_t count
= m_unlinkedCode
->numberOfRegExps()) {
580 out
.printf("\nm_regexps:\n");
583 out
.printf(" re%u = %s\n", static_cast<unsigned>(i
), regexpToSourceString(m_unlinkedCode
->regexp(i
)).utf8().data());
589 if (!m_structureStubInfos
.isEmpty())
590 out
.printf("\nStructures:\n");
593 if (m_rareData
&& !m_rareData
->m_exceptionHandlers
.isEmpty()) {
594 out
.printf("\nException Handlers:\n");
597 out
.printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] depth: [%4d] }\n", i
+ 1, m_rareData
->m_exceptionHandlers
[i
].start
, m_rareData
->m_exceptionHandlers
[i
].end
, m_rareData
->m_exceptionHandlers
[i
].target
, m_rareData
->m_exceptionHandlers
[i
].scopeDepth
);
599 } while (i
< m_rareData
->m_exceptionHandlers
.size());
602 if (m_rareData
&& !m_rareData
->m_immediateSwitchJumpTables
.isEmpty()) {
603 out
.printf("Immediate Switch Jump Tables:\n");
606 out
.printf(" %1d = {\n", i
);
608 Vector
<int32_t>::const_iterator end
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.end();
609 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_immediateSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
612 out
.printf("\t\t%4d => %04d\n", entry
+ m_rareData
->m_immediateSwitchJumpTables
[i
].min
, *iter
);
616 } while (i
< m_rareData
->m_immediateSwitchJumpTables
.size());
619 if (m_rareData
&& !m_rareData
->m_characterSwitchJumpTables
.isEmpty()) {
620 out
.printf("\nCharacter Switch Jump Tables:\n");
623 out
.printf(" %1d = {\n", i
);
625 Vector
<int32_t>::const_iterator end
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.end();
626 for (Vector
<int32_t>::const_iterator iter
= m_rareData
->m_characterSwitchJumpTables
[i
].branchOffsets
.begin(); iter
!= end
; ++iter
, ++entry
) {
629 ASSERT(!((i
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
) & ~0xFFFF));
630 UChar ch
= static_cast<UChar
>(entry
+ m_rareData
->m_characterSwitchJumpTables
[i
].min
);
631 out
.printf("\t\t\"%s\" => %04d\n", String(&ch
, 1).utf8().data(), *iter
);
635 } while (i
< m_rareData
->m_characterSwitchJumpTables
.size());
638 if (m_rareData
&& !m_rareData
->m_stringSwitchJumpTables
.isEmpty()) {
639 out
.printf("\nString Switch Jump Tables:\n");
642 out
.printf(" %1d = {\n", i
);
643 StringJumpTable::StringOffsetTable::const_iterator end
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.end();
644 for (StringJumpTable::StringOffsetTable::const_iterator iter
= m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.begin(); iter
!= end
; ++iter
)
645 out
.printf("\t\t\"%s\" => %04d\n", String(iter
->key
).utf8().data(), iter
->value
.branchOffset
);
648 } while (i
< m_rareData
->m_stringSwitchJumpTables
.size());
654 void CodeBlock::beginDumpProfiling(PrintStream
& out
, bool& hasPrintedProfiling
)
656 if (hasPrintedProfiling
) {
662 hasPrintedProfiling
= true;
665 void CodeBlock::dumpValueProfiling(PrintStream
& out
, const Instruction
*& it
, bool& hasPrintedProfiling
)
668 #if ENABLE(VALUE_PROFILER)
669 CString description
= it
->u
.profile
->briefDescription();
670 if (!description
.length())
672 beginDumpProfiling(out
, hasPrintedProfiling
);
673 out
.print(description
);
676 UNUSED_PARAM(hasPrintedProfiling
);
680 void CodeBlock::dumpArrayProfiling(PrintStream
& out
, const Instruction
*& it
, bool& hasPrintedProfiling
)
683 #if ENABLE(VALUE_PROFILER)
684 CString description
= it
->u
.arrayProfile
->briefDescription(this);
685 if (!description
.length())
687 beginDumpProfiling(out
, hasPrintedProfiling
);
688 out
.print(description
);
691 UNUSED_PARAM(hasPrintedProfiling
);
695 #if ENABLE(VALUE_PROFILER)
696 void CodeBlock::dumpRareCaseProfile(PrintStream
& out
, const char* name
, RareCaseProfile
* profile
, bool& hasPrintedProfiling
)
698 if (!profile
|| !profile
->m_counter
)
701 beginDumpProfiling(out
, hasPrintedProfiling
);
702 out
.print(name
, profile
->m_counter
);
706 void CodeBlock::dumpBytecode(PrintStream
& out
, ExecState
* exec
, const Instruction
* begin
, const Instruction
*& it
)
708 int location
= it
- begin
;
709 bool hasPrintedProfiling
= false;
710 switch (exec
->interpreter()->getOpcodeID(it
->u
.opcode
)) {
712 out
.printf("[%4d] enter", location
);
715 case op_create_activation
: {
716 int r0
= (++it
)->u
.operand
;
717 out
.printf("[%4d] create_activation %s", location
, registerName(exec
, r0
).data());
720 case op_create_arguments
: {
721 int r0
= (++it
)->u
.operand
;
722 out
.printf("[%4d] create_arguments\t %s", location
, registerName(exec
, r0
).data());
725 case op_init_lazy_reg
: {
726 int r0
= (++it
)->u
.operand
;
727 out
.printf("[%4d] init_lazy_reg\t %s", location
, registerName(exec
, r0
).data());
730 case op_get_callee
: {
731 int r0
= (++it
)->u
.operand
;
732 out
.printf("[%4d] op_get_callee %s\n", location
, registerName(exec
, r0
).data());
736 case op_create_this
: {
737 int r0
= (++it
)->u
.operand
;
738 int r1
= (++it
)->u
.operand
;
739 unsigned inferredInlineCapacity
= (++it
)->u
.operand
;
740 out
.printf("[%4d] create_this %s, %s, %u", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), inferredInlineCapacity
);
743 case op_convert_this
: {
744 int r0
= (++it
)->u
.operand
;
745 out
.printf("[%4d] convert_this\t %s", location
, registerName(exec
, r0
).data());
746 ++it
; // Skip value profile.
749 case op_new_object
: {
750 int r0
= (++it
)->u
.operand
;
751 unsigned inferredInlineCapacity
= (++it
)->u
.operand
;
752 out
.printf("[%4d] new_object\t %s, %u", location
, registerName(exec
, r0
).data(), inferredInlineCapacity
);
753 ++it
; // Skip object allocation profile.
757 int dst
= (++it
)->u
.operand
;
758 int argv
= (++it
)->u
.operand
;
759 int argc
= (++it
)->u
.operand
;
760 out
.printf("[%4d] new_array\t %s, %s, %d", location
, registerName(exec
, dst
).data(), registerName(exec
, argv
).data(), argc
);
761 ++it
; // Skip array allocation profile.
764 case op_new_array_with_size
: {
765 int dst
= (++it
)->u
.operand
;
766 int length
= (++it
)->u
.operand
;
767 out
.printf("[%4d] new_array_with_size\t %s, %s", location
, registerName(exec
, dst
).data(), registerName(exec
, length
).data());
768 ++it
; // Skip array allocation profile.
771 case op_new_array_buffer
: {
772 int dst
= (++it
)->u
.operand
;
773 int argv
= (++it
)->u
.operand
;
774 int argc
= (++it
)->u
.operand
;
775 out
.printf("[%4d] new_array_buffer\t %s, %d, %d", location
, registerName(exec
, dst
).data(), argv
, argc
);
776 ++it
; // Skip array allocation profile.
779 case op_new_regexp
: {
780 int r0
= (++it
)->u
.operand
;
781 int re0
= (++it
)->u
.operand
;
782 out
.printf("[%4d] new_regexp\t %s, ", location
, registerName(exec
, r0
).data());
783 if (r0
>=0 && r0
< (int)m_unlinkedCode
->numberOfRegExps())
784 out
.printf("%s", regexpName(re0
, regexp(re0
)).data());
786 out
.printf("bad_regexp(%d)", re0
);
790 int r0
= (++it
)->u
.operand
;
791 int r1
= (++it
)->u
.operand
;
792 out
.printf("[%4d] mov\t\t %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
796 printUnaryOp(out
, exec
, location
, it
, "not");
800 printBinaryOp(out
, exec
, location
, it
, "eq");
804 printUnaryOp(out
, exec
, location
, it
, "eq_null");
808 printBinaryOp(out
, exec
, location
, it
, "neq");
812 printUnaryOp(out
, exec
, location
, it
, "neq_null");
816 printBinaryOp(out
, exec
, location
, it
, "stricteq");
820 printBinaryOp(out
, exec
, location
, it
, "nstricteq");
824 printBinaryOp(out
, exec
, location
, it
, "less");
828 printBinaryOp(out
, exec
, location
, it
, "lesseq");
832 printBinaryOp(out
, exec
, location
, it
, "greater");
836 printBinaryOp(out
, exec
, location
, it
, "greatereq");
840 int r0
= (++it
)->u
.operand
;
841 out
.printf("[%4d] pre_inc\t\t %s", location
, registerName(exec
, r0
).data());
845 int r0
= (++it
)->u
.operand
;
846 out
.printf("[%4d] pre_dec\t\t %s", location
, registerName(exec
, r0
).data());
850 printUnaryOp(out
, exec
, location
, it
, "to_number");
854 printUnaryOp(out
, exec
, location
, it
, "negate");
858 printBinaryOp(out
, exec
, location
, it
, "add");
863 printBinaryOp(out
, exec
, location
, it
, "mul");
868 printBinaryOp(out
, exec
, location
, it
, "div");
873 printBinaryOp(out
, exec
, location
, it
, "mod");
877 printBinaryOp(out
, exec
, location
, it
, "sub");
882 printBinaryOp(out
, exec
, location
, it
, "lshift");
886 printBinaryOp(out
, exec
, location
, it
, "rshift");
890 printBinaryOp(out
, exec
, location
, it
, "urshift");
894 printBinaryOp(out
, exec
, location
, it
, "bitand");
899 printBinaryOp(out
, exec
, location
, it
, "bitxor");
904 printBinaryOp(out
, exec
, location
, it
, "bitor");
908 case op_check_has_instance
: {
909 int r0
= (++it
)->u
.operand
;
910 int r1
= (++it
)->u
.operand
;
911 int r2
= (++it
)->u
.operand
;
912 int offset
= (++it
)->u
.operand
;
913 out
.printf("[%4d] check_has_instance\t\t %s, %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data(), offset
, location
+ offset
);
916 case op_instanceof
: {
917 int r0
= (++it
)->u
.operand
;
918 int r1
= (++it
)->u
.operand
;
919 int r2
= (++it
)->u
.operand
;
920 out
.printf("[%4d] instanceof\t\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
924 printUnaryOp(out
, exec
, location
, it
, "typeof");
927 case op_is_undefined
: {
928 printUnaryOp(out
, exec
, location
, it
, "is_undefined");
931 case op_is_boolean
: {
932 printUnaryOp(out
, exec
, location
, it
, "is_boolean");
936 printUnaryOp(out
, exec
, location
, it
, "is_number");
940 printUnaryOp(out
, exec
, location
, it
, "is_string");
944 printUnaryOp(out
, exec
, location
, it
, "is_object");
947 case op_is_function
: {
948 printUnaryOp(out
, exec
, location
, it
, "is_function");
952 printBinaryOp(out
, exec
, location
, it
, "in");
955 case op_put_to_base_variable
:
956 case op_put_to_base
: {
957 int base
= (++it
)->u
.operand
;
958 int id0
= (++it
)->u
.operand
;
959 int value
= (++it
)->u
.operand
;
960 int resolveInfo
= (++it
)->u
.operand
;
961 out
.printf("[%4d] put_to_base\t %s, %s, %s, %d", location
, registerName(exec
, base
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, value
).data(), resolveInfo
);
965 case op_resolve_global_property
:
966 case op_resolve_global_var
:
967 case op_resolve_scoped_var
:
968 case op_resolve_scoped_var_on_top_scope
:
969 case op_resolve_scoped_var_with_top_scope_check
: {
970 int r0
= (++it
)->u
.operand
;
971 int id0
= (++it
)->u
.operand
;
972 int resolveInfo
= (++it
)->u
.operand
;
973 out
.printf("[%4d] resolve\t\t %s, %s, %d", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), resolveInfo
);
974 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
977 case op_get_scoped_var
: {
978 int r0
= (++it
)->u
.operand
;
979 int index
= (++it
)->u
.operand
;
980 int skipLevels
= (++it
)->u
.operand
;
981 out
.printf("[%4d] get_scoped_var\t %s, %d, %d", location
, registerName(exec
, r0
).data(), index
, skipLevels
);
982 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
985 case op_put_scoped_var
: {
986 int index
= (++it
)->u
.operand
;
987 int skipLevels
= (++it
)->u
.operand
;
988 int r0
= (++it
)->u
.operand
;
989 out
.printf("[%4d] put_scoped_var\t %d, %d, %s", location
, index
, skipLevels
, registerName(exec
, r0
).data());
992 case op_init_global_const_nop
: {
993 out
.printf("[%4d] init_global_const_nop\t", location
);
1000 case op_init_global_const
: {
1001 WriteBarrier
<Unknown
>* registerPointer
= (++it
)->u
.registerPointer
;
1002 int r0
= (++it
)->u
.operand
;
1003 out
.printf("[%4d] init_global_const\t g%d(%p), %s", location
, m_globalObject
->findRegisterIndex(registerPointer
), registerPointer
, registerName(exec
, r0
).data());
1008 case op_init_global_const_check
: {
1009 WriteBarrier
<Unknown
>* registerPointer
= (++it
)->u
.registerPointer
;
1010 int r0
= (++it
)->u
.operand
;
1011 out
.printf("[%4d] init_global_const_check\t g%d(%p), %s", location
, m_globalObject
->findRegisterIndex(registerPointer
), registerPointer
, registerName(exec
, r0
).data());
1016 case op_resolve_base_to_global
:
1017 case op_resolve_base_to_global_dynamic
:
1018 case op_resolve_base_to_scope
:
1019 case op_resolve_base_to_scope_with_top_scope_check
:
1020 case op_resolve_base
: {
1021 int r0
= (++it
)->u
.operand
;
1022 int id0
= (++it
)->u
.operand
;
1023 int isStrict
= (++it
)->u
.operand
;
1024 int resolveInfo
= (++it
)->u
.operand
;
1025 int putToBaseInfo
= (++it
)->u
.operand
;
1026 out
.printf("[%4d] resolve_base%s\t %s, %s, %d, %d", location
, isStrict
? "_strict" : "", registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), resolveInfo
, putToBaseInfo
);
1027 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1030 case op_resolve_with_base
: {
1031 int r0
= (++it
)->u
.operand
;
1032 int r1
= (++it
)->u
.operand
;
1033 int id0
= (++it
)->u
.operand
;
1034 int resolveInfo
= (++it
)->u
.operand
;
1035 int putToBaseInfo
= (++it
)->u
.operand
;
1036 out
.printf("[%4d] resolve_with_base %s, %s, %s, %d, %d", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data(), resolveInfo
, putToBaseInfo
);
1037 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1040 case op_resolve_with_this
: {
1041 int r0
= (++it
)->u
.operand
;
1042 int r1
= (++it
)->u
.operand
;
1043 int id0
= (++it
)->u
.operand
;
1044 int resolveInfo
= (++it
)->u
.operand
;
1045 out
.printf("[%4d] resolve_with_this %s, %s, %s, %d", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data(), resolveInfo
);
1046 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1050 case op_get_by_id_out_of_line
:
1051 case op_get_by_id_self
:
1052 case op_get_by_id_proto
:
1053 case op_get_by_id_chain
:
1054 case op_get_by_id_getter_self
:
1055 case op_get_by_id_getter_proto
:
1056 case op_get_by_id_getter_chain
:
1057 case op_get_by_id_custom_self
:
1058 case op_get_by_id_custom_proto
:
1059 case op_get_by_id_custom_chain
:
1060 case op_get_by_id_generic
:
1061 case op_get_array_length
:
1062 case op_get_string_length
: {
1063 printGetByIdOp(out
, exec
, location
, it
);
1064 printGetByIdCacheStatus(out
, exec
, location
);
1065 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1068 case op_get_arguments_length
: {
1069 printUnaryOp(out
, exec
, location
, it
, "get_arguments_length");
1073 case op_put_by_id
: {
1074 printPutByIdOp(out
, exec
, location
, it
, "put_by_id");
1077 case op_put_by_id_out_of_line
: {
1078 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_out_of_line");
1081 case op_put_by_id_replace
: {
1082 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_replace");
1085 case op_put_by_id_transition
: {
1086 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_transition");
1089 case op_put_by_id_transition_direct
: {
1090 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_transition_direct");
1093 case op_put_by_id_transition_direct_out_of_line
: {
1094 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_transition_direct_out_of_line");
1097 case op_put_by_id_transition_normal
: {
1098 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_transition_normal");
1101 case op_put_by_id_transition_normal_out_of_line
: {
1102 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_transition_normal_out_of_line");
1105 case op_put_by_id_generic
: {
1106 printPutByIdOp(out
, exec
, location
, it
, "put_by_id_generic");
1109 case op_put_getter_setter
: {
1110 int r0
= (++it
)->u
.operand
;
1111 int id0
= (++it
)->u
.operand
;
1112 int r1
= (++it
)->u
.operand
;
1113 int r2
= (++it
)->u
.operand
;
1114 out
.printf("[%4d] put_getter_setter\t %s, %s, %s, %s", location
, registerName(exec
, r0
).data(), idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
1117 case op_del_by_id
: {
1118 int r0
= (++it
)->u
.operand
;
1119 int r1
= (++it
)->u
.operand
;
1120 int id0
= (++it
)->u
.operand
;
1121 out
.printf("[%4d] del_by_id\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), idName(id0
, m_identifiers
[id0
]).data());
1124 case op_get_by_val
: {
1125 int r0
= (++it
)->u
.operand
;
1126 int r1
= (++it
)->u
.operand
;
1127 int r2
= (++it
)->u
.operand
;
1128 out
.printf("[%4d] get_by_val\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
1129 dumpArrayProfiling(out
, it
, hasPrintedProfiling
);
1130 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1133 case op_get_argument_by_val
: {
1134 int r0
= (++it
)->u
.operand
;
1135 int r1
= (++it
)->u
.operand
;
1136 int r2
= (++it
)->u
.operand
;
1137 out
.printf("[%4d] get_argument_by_val\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
1139 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1142 case op_get_by_pname
: {
1143 int r0
= (++it
)->u
.operand
;
1144 int r1
= (++it
)->u
.operand
;
1145 int r2
= (++it
)->u
.operand
;
1146 int r3
= (++it
)->u
.operand
;
1147 int r4
= (++it
)->u
.operand
;
1148 int r5
= (++it
)->u
.operand
;
1149 out
.printf("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s", 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());
1152 case op_put_by_val
: {
1153 int r0
= (++it
)->u
.operand
;
1154 int r1
= (++it
)->u
.operand
;
1155 int r2
= (++it
)->u
.operand
;
1156 out
.printf("[%4d] put_by_val\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
1157 dumpArrayProfiling(out
, it
, hasPrintedProfiling
);
1160 case op_del_by_val
: {
1161 int r0
= (++it
)->u
.operand
;
1162 int r1
= (++it
)->u
.operand
;
1163 int r2
= (++it
)->u
.operand
;
1164 out
.printf("[%4d] del_by_val\t %s, %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data());
1167 case op_put_by_index
: {
1168 int r0
= (++it
)->u
.operand
;
1169 unsigned n0
= (++it
)->u
.operand
;
1170 int r1
= (++it
)->u
.operand
;
1171 out
.printf("[%4d] put_by_index\t %s, %u, %s", location
, registerName(exec
, r0
).data(), n0
, registerName(exec
, r1
).data());
1175 int offset
= (++it
)->u
.operand
;
1176 out
.printf("[%4d] jmp\t\t %d(->%d)", location
, offset
, location
+ offset
);
1180 printConditionalJump(out
, exec
, begin
, it
, location
, "jtrue");
1184 printConditionalJump(out
, exec
, begin
, it
, location
, "jfalse");
1188 printConditionalJump(out
, exec
, begin
, it
, location
, "jeq_null");
1191 case op_jneq_null
: {
1192 printConditionalJump(out
, exec
, begin
, it
, location
, "jneq_null");
1196 int r0
= (++it
)->u
.operand
;
1197 Special::Pointer pointer
= (++it
)->u
.specialPointer
;
1198 int offset
= (++it
)->u
.operand
;
1199 out
.printf("[%4d] jneq_ptr\t\t %s, %d (%p), %d(->%d)", location
, registerName(exec
, r0
).data(), pointer
, m_globalObject
->actualPointerFor(pointer
), offset
, location
+ offset
);
1203 int r0
= (++it
)->u
.operand
;
1204 int r1
= (++it
)->u
.operand
;
1205 int offset
= (++it
)->u
.operand
;
1206 out
.printf("[%4d] jless\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1210 int r0
= (++it
)->u
.operand
;
1211 int r1
= (++it
)->u
.operand
;
1212 int offset
= (++it
)->u
.operand
;
1213 out
.printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1217 int r0
= (++it
)->u
.operand
;
1218 int r1
= (++it
)->u
.operand
;
1219 int offset
= (++it
)->u
.operand
;
1220 out
.printf("[%4d] jgreater\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1223 case op_jgreatereq
: {
1224 int r0
= (++it
)->u
.operand
;
1225 int r1
= (++it
)->u
.operand
;
1226 int offset
= (++it
)->u
.operand
;
1227 out
.printf("[%4d] jgreatereq\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1231 int r0
= (++it
)->u
.operand
;
1232 int r1
= (++it
)->u
.operand
;
1233 int offset
= (++it
)->u
.operand
;
1234 out
.printf("[%4d] jnless\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1238 int r0
= (++it
)->u
.operand
;
1239 int r1
= (++it
)->u
.operand
;
1240 int offset
= (++it
)->u
.operand
;
1241 out
.printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1244 case op_jngreater
: {
1245 int r0
= (++it
)->u
.operand
;
1246 int r1
= (++it
)->u
.operand
;
1247 int offset
= (++it
)->u
.operand
;
1248 out
.printf("[%4d] jngreater\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1251 case op_jngreatereq
: {
1252 int r0
= (++it
)->u
.operand
;
1253 int r1
= (++it
)->u
.operand
;
1254 int offset
= (++it
)->u
.operand
;
1255 out
.printf("[%4d] jngreatereq\t\t %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), offset
, location
+ offset
);
1258 case op_loop_hint
: {
1259 out
.printf("[%4d] loop_hint", location
);
1262 case op_switch_imm
: {
1263 int tableIndex
= (++it
)->u
.operand
;
1264 int defaultTarget
= (++it
)->u
.operand
;
1265 int scrutineeRegister
= (++it
)->u
.operand
;
1266 out
.printf("[%4d] switch_imm\t %d, %d(->%d), %s", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1269 case op_switch_char
: {
1270 int tableIndex
= (++it
)->u
.operand
;
1271 int defaultTarget
= (++it
)->u
.operand
;
1272 int scrutineeRegister
= (++it
)->u
.operand
;
1273 out
.printf("[%4d] switch_char\t %d, %d(->%d), %s", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1276 case op_switch_string
: {
1277 int tableIndex
= (++it
)->u
.operand
;
1278 int defaultTarget
= (++it
)->u
.operand
;
1279 int scrutineeRegister
= (++it
)->u
.operand
;
1280 out
.printf("[%4d] switch_string\t %d, %d(->%d), %s", location
, tableIndex
, defaultTarget
, location
+ defaultTarget
, registerName(exec
, scrutineeRegister
).data());
1284 int r0
= (++it
)->u
.operand
;
1285 int f0
= (++it
)->u
.operand
;
1286 int shouldCheck
= (++it
)->u
.operand
;
1287 out
.printf("[%4d] new_func\t\t %s, f%d, %s", location
, registerName(exec
, r0
).data(), f0
, shouldCheck
? "<Checked>" : "<Unchecked>");
1290 case op_new_func_exp
: {
1291 int r0
= (++it
)->u
.operand
;
1292 int f0
= (++it
)->u
.operand
;
1293 out
.printf("[%4d] new_func_exp\t %s, f%d", location
, registerName(exec
, r0
).data(), f0
);
1297 printCallOp(out
, exec
, location
, it
, "call", DumpCaches
);
1300 case op_call_eval
: {
1301 printCallOp(out
, exec
, location
, it
, "call_eval", DontDumpCaches
);
1304 case op_call_varargs
: {
1305 int callee
= (++it
)->u
.operand
;
1306 int thisValue
= (++it
)->u
.operand
;
1307 int arguments
= (++it
)->u
.operand
;
1308 int firstFreeRegister
= (++it
)->u
.operand
;
1309 out
.printf("[%4d] call_varargs\t %s, %s, %s, %d", location
, registerName(exec
, callee
).data(), registerName(exec
, thisValue
).data(), registerName(exec
, arguments
).data(), firstFreeRegister
);
1312 case op_tear_off_activation
: {
1313 int r0
= (++it
)->u
.operand
;
1314 out
.printf("[%4d] tear_off_activation\t %s", location
, registerName(exec
, r0
).data());
1317 case op_tear_off_arguments
: {
1318 int r0
= (++it
)->u
.operand
;
1319 int r1
= (++it
)->u
.operand
;
1320 out
.printf("[%4d] tear_off_arguments %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1324 int r0
= (++it
)->u
.operand
;
1325 out
.printf("[%4d] ret\t\t %s", location
, registerName(exec
, r0
).data());
1328 case op_call_put_result
: {
1329 int r0
= (++it
)->u
.operand
;
1330 out
.printf("[%4d] call_put_result\t\t %s", location
, registerName(exec
, r0
).data());
1331 dumpValueProfiling(out
, it
, hasPrintedProfiling
);
1334 case op_ret_object_or_this
: {
1335 int r0
= (++it
)->u
.operand
;
1336 int r1
= (++it
)->u
.operand
;
1337 out
.printf("[%4d] constructor_ret\t\t %s %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1340 case op_construct
: {
1341 printCallOp(out
, exec
, location
, it
, "construct", DumpCaches
);
1345 int r0
= (++it
)->u
.operand
;
1346 int r1
= (++it
)->u
.operand
;
1347 int count
= (++it
)->u
.operand
;
1348 out
.printf("[%4d] strcat\t\t %s, %s, %d", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), count
);
1351 case op_to_primitive
: {
1352 int r0
= (++it
)->u
.operand
;
1353 int r1
= (++it
)->u
.operand
;
1354 out
.printf("[%4d] to_primitive\t %s, %s", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data());
1357 case op_get_pnames
: {
1358 int r0
= it
[1].u
.operand
;
1359 int r1
= it
[2].u
.operand
;
1360 int r2
= it
[3].u
.operand
;
1361 int r3
= it
[4].u
.operand
;
1362 int offset
= it
[5].u
.operand
;
1363 out
.printf("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)", location
, registerName(exec
, r0
).data(), registerName(exec
, r1
).data(), registerName(exec
, r2
).data(), registerName(exec
, r3
).data(), offset
, location
+ offset
);
1364 it
+= OPCODE_LENGTH(op_get_pnames
) - 1;
1367 case op_next_pname
: {
1368 int dest
= it
[1].u
.operand
;
1369 int base
= it
[2].u
.operand
;
1370 int i
= it
[3].u
.operand
;
1371 int size
= it
[4].u
.operand
;
1372 int iter
= it
[5].u
.operand
;
1373 int offset
= it
[6].u
.operand
;
1374 out
.printf("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)", location
, registerName(exec
, dest
).data(), registerName(exec
, base
).data(), registerName(exec
, i
).data(), registerName(exec
, size
).data(), registerName(exec
, iter
).data(), offset
, location
+ offset
);
1375 it
+= OPCODE_LENGTH(op_next_pname
) - 1;
1378 case op_push_with_scope
: {
1379 int r0
= (++it
)->u
.operand
;
1380 out
.printf("[%4d] push_with_scope\t %s", location
, registerName(exec
, r0
).data());
1383 case op_pop_scope
: {
1384 out
.printf("[%4d] pop_scope", location
);
1387 case op_push_name_scope
: {
1388 int id0
= (++it
)->u
.operand
;
1389 int r1
= (++it
)->u
.operand
;
1390 unsigned attributes
= (++it
)->u
.operand
;
1391 out
.printf("[%4d] push_name_scope \t%s, %s, %u", location
, idName(id0
, m_identifiers
[id0
]).data(), registerName(exec
, r1
).data(), attributes
);
1395 int r0
= (++it
)->u
.operand
;
1396 out
.printf("[%4d] catch\t\t %s", location
, registerName(exec
, r0
).data());
1400 int r0
= (++it
)->u
.operand
;
1401 out
.printf("[%4d] throw\t\t %s", location
, registerName(exec
, r0
).data());
1404 case op_throw_static_error
: {
1405 int k0
= (++it
)->u
.operand
;
1406 int k1
= (++it
)->u
.operand
;
1407 out
.printf("[%4d] throw_static_error\t %s, %s", location
, constantName(exec
, k0
, getConstant(k0
)).data(), k1
? "true" : "false");
1411 int debugHookID
= (++it
)->u
.operand
;
1412 int firstLine
= (++it
)->u
.operand
;
1413 int lastLine
= (++it
)->u
.operand
;
1414 int column
= (++it
)->u
.operand
;
1415 out
.printf("[%4d] debug\t\t %s, %d, %d, %d", location
, debugHookName(debugHookID
), firstLine
, lastLine
, column
);
1418 case op_profile_will_call
: {
1419 int function
= (++it
)->u
.operand
;
1420 out
.printf("[%4d] profile_will_call %s", location
, registerName(exec
, function
).data());
1423 case op_profile_did_call
: {
1424 int function
= (++it
)->u
.operand
;
1425 out
.printf("[%4d] profile_did_call\t %s", location
, registerName(exec
, function
).data());
1429 int r0
= (++it
)->u
.operand
;
1430 out
.printf("[%4d] end\t\t %s", location
, registerName(exec
, r0
).data());
1433 #if ENABLE(LLINT_C_LOOP)
1435 RELEASE_ASSERT_NOT_REACHED();
1439 #if ENABLE(VALUE_PROFILER)
1440 dumpRareCaseProfile(out
, "rare case: ", rareCaseProfileForBytecodeOffset(location
), hasPrintedProfiling
);
1441 dumpRareCaseProfile(out
, "special fast case: ", specialFastCaseProfileForBytecodeOffset(location
), hasPrintedProfiling
);
1445 Vector
<FrequentExitSite
> exitSites
= exitProfile().exitSitesFor(location
);
1446 if (!exitSites
.isEmpty()) {
1447 out
.print(" !! frequent exits: ");
1449 for (unsigned i
= 0; i
< exitSites
.size(); ++i
)
1450 out
.print(comma
, exitSites
[i
].kind());
1452 #else // ENABLE(DFG_JIT)
1453 UNUSED_PARAM(location
);
1454 #endif // ENABLE(DFG_JIT)
1458 void CodeBlock::dumpBytecode(PrintStream
& out
, unsigned bytecodeOffset
)
1460 ExecState
* exec
= m_globalObject
->globalExec();
1461 const Instruction
* it
= instructions().begin() + bytecodeOffset
;
1462 dumpBytecode(out
, exec
, instructions().begin(), it
);
1465 #if DUMP_CODE_BLOCK_STATISTICS
1466 static HashSet
<CodeBlock
*> liveCodeBlockSet
;
1469 #define FOR_EACH_MEMBER_VECTOR(macro) \
1470 macro(instructions) \
1471 macro(globalResolveInfos) \
1472 macro(structureStubInfos) \
1473 macro(callLinkInfos) \
1474 macro(linkedCallerList) \
1475 macro(identifiers) \
1476 macro(functionExpressions) \
1477 macro(constantRegisters)
1479 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1482 macro(exceptionHandlers) \
1483 macro(immediateSwitchJumpTables) \
1484 macro(characterSwitchJumpTables) \
1485 macro(stringSwitchJumpTables) \
1486 macro(evalCodeCache) \
1487 macro(expressionInfo) \
1489 macro(callReturnIndexVector)
1491 template<typename T
>
1492 static size_t sizeInBytes(const Vector
<T
>& vector
)
1494 return vector
.capacity() * sizeof(T
);
1497 void CodeBlock::dumpStatistics()
1499 #if DUMP_CODE_BLOCK_STATISTICS
1500 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1501 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS
)
1502 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS
)
1505 // Non-vector data members
1506 size_t evalCodeCacheIsNotEmpty
= 0;
1508 size_t symbolTableIsNotEmpty
= 0;
1509 size_t symbolTableTotalSize
= 0;
1511 size_t hasRareData
= 0;
1513 size_t isFunctionCode
= 0;
1514 size_t isGlobalCode
= 0;
1515 size_t isEvalCode
= 0;
1517 HashSet
<CodeBlock
*>::const_iterator end
= liveCodeBlockSet
.end();
1518 for (HashSet
<CodeBlock
*>::const_iterator it
= liveCodeBlockSet
.begin(); it
!= end
; ++it
) {
1519 CodeBlock
* codeBlock
= *it
;
1521 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1522 FOR_EACH_MEMBER_VECTOR(GET_STATS
)
1525 if (codeBlock
->symbolTable() && !codeBlock
->symbolTable()->isEmpty()) {
1526 symbolTableIsNotEmpty
++;
1527 symbolTableTotalSize
+= (codeBlock
->symbolTable()->capacity() * (sizeof(SymbolTable::KeyType
) + sizeof(SymbolTable::MappedType
)));
1530 if (codeBlock
->m_rareData
) {
1532 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1533 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS
)
1536 if (!codeBlock
->m_rareData
->m_evalCodeCache
.isEmpty())
1537 evalCodeCacheIsNotEmpty
++;
1540 switch (codeBlock
->codeType()) {
1553 size_t totalSize
= 0;
1555 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1556 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE
)
1557 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE
)
1558 #undef GET_TOTAL_SIZE
1560 totalSize
+= symbolTableTotalSize
;
1561 totalSize
+= (liveCodeBlockSet
.size() * sizeof(CodeBlock
));
1563 dataLogF("Number of live CodeBlocks: %d\n", liveCodeBlockSet
.size());
1564 dataLogF("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock
));
1565 dataLogF("Size of all CodeBlocks: %zu\n", totalSize
);
1566 dataLogF("Average size of a CodeBlock: %zu\n", totalSize
/ liveCodeBlockSet
.size());
1568 dataLogF("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode
, static_cast<double>(isFunctionCode
) * 100.0 / liveCodeBlockSet
.size());
1569 dataLogF("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode
, static_cast<double>(isGlobalCode
) * 100.0 / liveCodeBlockSet
.size());
1570 dataLogF("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode
, static_cast<double>(isEvalCode
) * 100.0 / liveCodeBlockSet
.size());
1572 dataLogF("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData
, static_cast<double>(hasRareData
) * 100.0 / liveCodeBlockSet
.size());
1574 #define PRINT_STATS(name) dataLogF("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLogF("Size of all " #name ": %zu\n", name##TotalSize);
1575 FOR_EACH_MEMBER_VECTOR(PRINT_STATS
)
1576 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS
)
1579 dataLogF("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty
);
1580 dataLogF("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty
);
1582 dataLogF("Size of all symbolTables: %zu\n", symbolTableTotalSize
);
1585 dataLogF("Dumping CodeBlock statistics is not enabled.\n");
1589 CodeBlock::CodeBlock(CopyParsedBlockTag
, CodeBlock
& other
)
1590 : m_globalObject(other
.m_globalObject
)
1591 , m_heap(other
.m_heap
)
1592 , m_numCalleeRegisters(other
.m_numCalleeRegisters
)
1593 , m_numVars(other
.m_numVars
)
1594 , m_isConstructor(other
.m_isConstructor
)
1595 , m_unlinkedCode(*other
.m_vm
, other
.m_ownerExecutable
.get(), other
.m_unlinkedCode
.get())
1596 , m_ownerExecutable(*other
.m_vm
, other
.m_ownerExecutable
.get(), other
.m_ownerExecutable
.get())
1598 , m_instructions(other
.m_instructions
)
1599 , m_thisRegister(other
.m_thisRegister
)
1600 , m_argumentsRegister(other
.m_argumentsRegister
)
1601 , m_activationRegister(other
.m_activationRegister
)
1602 , m_isStrictMode(other
.m_isStrictMode
)
1603 , m_needsActivation(other
.m_needsActivation
)
1604 , m_source(other
.m_source
)
1605 , m_sourceOffset(other
.m_sourceOffset
)
1606 , m_firstLineColumnOffset(other
.m_firstLineColumnOffset
)
1607 , m_codeType(other
.m_codeType
)
1608 , m_identifiers(other
.m_identifiers
)
1609 , m_constantRegisters(other
.m_constantRegisters
)
1610 , m_functionDecls(other
.m_functionDecls
)
1611 , m_functionExprs(other
.m_functionExprs
)
1612 , m_osrExitCounter(0)
1613 , m_optimizationDelayCounter(0)
1614 , m_reoptimizationRetryCounter(0)
1615 , m_resolveOperations(other
.m_resolveOperations
)
1616 , m_putToBaseOperations(other
.m_putToBaseOperations
)
1618 , m_canCompileWithDFGState(DFG::CapabilityLevelNotSet
)
1621 setNumParameters(other
.numParameters());
1622 optimizeAfterWarmUp();
1625 if (other
.m_rareData
) {
1626 createRareDataIfNecessary();
1628 m_rareData
->m_exceptionHandlers
= other
.m_rareData
->m_exceptionHandlers
;
1629 m_rareData
->m_constantBuffers
= other
.m_rareData
->m_constantBuffers
;
1630 m_rareData
->m_immediateSwitchJumpTables
= other
.m_rareData
->m_immediateSwitchJumpTables
;
1631 m_rareData
->m_characterSwitchJumpTables
= other
.m_rareData
->m_characterSwitchJumpTables
;
1632 m_rareData
->m_stringSwitchJumpTables
= other
.m_rareData
->m_stringSwitchJumpTables
;
1636 CodeBlock::CodeBlock(ScriptExecutable
* ownerExecutable
, UnlinkedCodeBlock
* unlinkedCodeBlock
, JSGlobalObject
* globalObject
, unsigned baseScopeDepth
, PassRefPtr
<SourceProvider
> sourceProvider
, unsigned sourceOffset
, unsigned firstLineColumnOffset
, PassOwnPtr
<CodeBlock
> alternative
)
1637 : m_globalObject(globalObject
->vm(), ownerExecutable
, globalObject
)
1638 , m_heap(&m_globalObject
->vm().heap
)
1639 , m_numCalleeRegisters(unlinkedCodeBlock
->m_numCalleeRegisters
)
1640 , m_numVars(unlinkedCodeBlock
->m_numVars
)
1641 , m_isConstructor(unlinkedCodeBlock
->isConstructor())
1642 , m_unlinkedCode(globalObject
->vm(), ownerExecutable
, unlinkedCodeBlock
)
1643 , m_ownerExecutable(globalObject
->vm(), ownerExecutable
, ownerExecutable
)
1644 , m_vm(unlinkedCodeBlock
->vm())
1645 , m_thisRegister(unlinkedCodeBlock
->thisRegister())
1646 , m_argumentsRegister(unlinkedCodeBlock
->argumentsRegister())
1647 , m_activationRegister(unlinkedCodeBlock
->activationRegister())
1648 , m_isStrictMode(unlinkedCodeBlock
->isStrictMode())
1649 , m_needsActivation(unlinkedCodeBlock
->needsFullScopeChain())
1650 , m_source(sourceProvider
)
1651 , m_sourceOffset(sourceOffset
)
1652 , m_firstLineColumnOffset(firstLineColumnOffset
)
1653 , m_codeType(unlinkedCodeBlock
->codeType())
1654 , m_alternative(alternative
)
1655 , m_osrExitCounter(0)
1656 , m_optimizationDelayCounter(0)
1657 , m_reoptimizationRetryCounter(0)
1659 m_vm
->startedCompiling(this);
1662 setNumParameters(unlinkedCodeBlock
->numParameters());
1664 #if DUMP_CODE_BLOCK_STATISTICS
1665 liveCodeBlockSet
.add(this);
1667 setIdentifiers(unlinkedCodeBlock
->identifiers());
1668 setConstantRegisters(unlinkedCodeBlock
->constantRegisters());
1669 if (unlinkedCodeBlock
->usesGlobalObject())
1670 m_constantRegisters
[unlinkedCodeBlock
->globalObjectRegister()].set(*m_vm
, ownerExecutable
, globalObject
);
1671 m_functionDecls
.grow(unlinkedCodeBlock
->numberOfFunctionDecls());
1672 for (size_t count
= unlinkedCodeBlock
->numberOfFunctionDecls(), i
= 0; i
< count
; ++i
) {
1673 UnlinkedFunctionExecutable
* unlinkedExecutable
= unlinkedCodeBlock
->functionDecl(i
);
1674 unsigned lineCount
= unlinkedExecutable
->lineCount();
1675 unsigned firstLine
= ownerExecutable
->lineNo() + unlinkedExecutable
->firstLineOffset();
1676 unsigned startColumn
= unlinkedExecutable
->functionStartColumn();
1677 startColumn
+= (unlinkedExecutable
->firstLineOffset() ? 1 : ownerExecutable
->startColumn());
1678 unsigned startOffset
= sourceOffset
+ unlinkedExecutable
->startOffset();
1679 unsigned sourceLength
= unlinkedExecutable
->sourceLength();
1680 SourceCode
code(m_source
, startOffset
, startOffset
+ sourceLength
, firstLine
, startColumn
);
1681 FunctionExecutable
* executable
= FunctionExecutable::create(*m_vm
, code
, unlinkedExecutable
, firstLine
, firstLine
+ lineCount
, startColumn
);
1682 m_functionDecls
[i
].set(*m_vm
, ownerExecutable
, executable
);
1685 m_functionExprs
.grow(unlinkedCodeBlock
->numberOfFunctionExprs());
1686 for (size_t count
= unlinkedCodeBlock
->numberOfFunctionExprs(), i
= 0; i
< count
; ++i
) {
1687 UnlinkedFunctionExecutable
* unlinkedExecutable
= unlinkedCodeBlock
->functionExpr(i
);
1688 unsigned lineCount
= unlinkedExecutable
->lineCount();
1689 unsigned firstLine
= ownerExecutable
->lineNo() + unlinkedExecutable
->firstLineOffset();
1690 unsigned startColumn
= unlinkedExecutable
->functionStartColumn();
1691 startColumn
+= (unlinkedExecutable
->firstLineOffset() ? 1 : ownerExecutable
->startColumn());
1692 unsigned startOffset
= sourceOffset
+ unlinkedExecutable
->startOffset();
1693 unsigned sourceLength
= unlinkedExecutable
->sourceLength();
1694 SourceCode
code(m_source
, startOffset
, startOffset
+ sourceLength
, firstLine
, startColumn
);
1695 FunctionExecutable
* executable
= FunctionExecutable::create(*m_vm
, code
, unlinkedExecutable
, firstLine
, firstLine
+ lineCount
, startColumn
);
1696 m_functionExprs
[i
].set(*m_vm
, ownerExecutable
, executable
);
1699 if (unlinkedCodeBlock
->hasRareData()) {
1700 createRareDataIfNecessary();
1701 if (size_t count
= unlinkedCodeBlock
->constantBufferCount()) {
1702 m_rareData
->m_constantBuffers
.grow(count
);
1703 for (size_t i
= 0; i
< count
; i
++) {
1704 const UnlinkedCodeBlock::ConstantBuffer
& buffer
= unlinkedCodeBlock
->constantBuffer(i
);
1705 m_rareData
->m_constantBuffers
[i
] = buffer
;
1708 if (size_t count
= unlinkedCodeBlock
->numberOfExceptionHandlers()) {
1709 m_rareData
->m_exceptionHandlers
.grow(count
);
1710 for (size_t i
= 0; i
< count
; i
++) {
1711 const UnlinkedHandlerInfo
& handler
= unlinkedCodeBlock
->exceptionHandler(i
);
1712 m_rareData
->m_exceptionHandlers
[i
].start
= handler
.start
;
1713 m_rareData
->m_exceptionHandlers
[i
].end
= handler
.end
;
1714 m_rareData
->m_exceptionHandlers
[i
].target
= handler
.target
;
1715 m_rareData
->m_exceptionHandlers
[i
].scopeDepth
= handler
.scopeDepth
+ baseScopeDepth
;
1716 #if ENABLE(JIT) && ENABLE(LLINT)
1717 m_rareData
->m_exceptionHandlers
[i
].nativeCode
= CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(llint_op_catch
)));
1722 if (size_t count
= unlinkedCodeBlock
->numberOfStringSwitchJumpTables()) {
1723 m_rareData
->m_stringSwitchJumpTables
.grow(count
);
1724 for (size_t i
= 0; i
< count
; i
++) {
1725 UnlinkedStringJumpTable::StringOffsetTable::iterator ptr
= unlinkedCodeBlock
->stringSwitchJumpTable(i
).offsetTable
.begin();
1726 UnlinkedStringJumpTable::StringOffsetTable::iterator end
= unlinkedCodeBlock
->stringSwitchJumpTable(i
).offsetTable
.end();
1727 for (; ptr
!= end
; ++ptr
) {
1728 OffsetLocation offset
;
1729 offset
.branchOffset
= ptr
->value
;
1730 m_rareData
->m_stringSwitchJumpTables
[i
].offsetTable
.add(ptr
->key
, offset
);
1735 if (size_t count
= unlinkedCodeBlock
->numberOfImmediateSwitchJumpTables()) {
1736 m_rareData
->m_immediateSwitchJumpTables
.grow(count
);
1737 for (size_t i
= 0; i
< count
; i
++) {
1738 UnlinkedSimpleJumpTable
& sourceTable
= unlinkedCodeBlock
->immediateSwitchJumpTable(i
);
1739 SimpleJumpTable
& destTable
= m_rareData
->m_immediateSwitchJumpTables
[i
];
1740 destTable
.branchOffsets
= sourceTable
.branchOffsets
;
1741 destTable
.min
= sourceTable
.min
;
1745 if (size_t count
= unlinkedCodeBlock
->numberOfCharacterSwitchJumpTables()) {
1746 m_rareData
->m_characterSwitchJumpTables
.grow(count
);
1747 for (size_t i
= 0; i
< count
; i
++) {
1748 UnlinkedSimpleJumpTable
& sourceTable
= unlinkedCodeBlock
->characterSwitchJumpTable(i
);
1749 SimpleJumpTable
& destTable
= m_rareData
->m_characterSwitchJumpTables
[i
];
1750 destTable
.branchOffsets
= sourceTable
.branchOffsets
;
1751 destTable
.min
= sourceTable
.min
;
1756 // Allocate metadata buffers for the bytecode
1758 if (size_t size
= unlinkedCodeBlock
->numberOfLLintCallLinkInfos())
1759 m_llintCallLinkInfos
.grow(size
);
1762 if (size_t size
= unlinkedCodeBlock
->numberOfArrayProfiles())
1763 m_arrayProfiles
.grow(size
);
1764 if (size_t size
= unlinkedCodeBlock
->numberOfArrayAllocationProfiles())
1765 m_arrayAllocationProfiles
.grow(size
);
1766 if (size_t size
= unlinkedCodeBlock
->numberOfValueProfiles())
1767 m_valueProfiles
.grow(size
);
1769 if (size_t size
= unlinkedCodeBlock
->numberOfObjectAllocationProfiles())
1770 m_objectAllocationProfiles
.grow(size
);
1771 if (size_t size
= unlinkedCodeBlock
->numberOfResolveOperations())
1772 m_resolveOperations
.grow(size
);
1773 if (size_t putToBaseCount
= unlinkedCodeBlock
->numberOfPutToBaseOperations()) {
1774 m_putToBaseOperations
.reserveInitialCapacity(putToBaseCount
);
1775 for (size_t i
= 0; i
< putToBaseCount
; ++i
)
1776 m_putToBaseOperations
.uncheckedAppend(PutToBaseOperation(isStrictMode()));
1779 // Copy and translate the UnlinkedInstructions
1780 size_t instructionCount
= unlinkedCodeBlock
->instructions().size();
1781 UnlinkedInstruction
* pc
= unlinkedCodeBlock
->instructions().data();
1782 Vector
<Instruction
, 0, UnsafeVectorOverflow
> instructions(instructionCount
);
1783 for (size_t i
= 0; i
< unlinkedCodeBlock
->instructions().size(); ) {
1784 unsigned opLength
= opcodeLength(pc
[i
].u
.opcode
);
1785 instructions
[i
] = vm()->interpreter
->getOpcode(pc
[i
].u
.opcode
);
1786 for (size_t j
= 1; j
< opLength
; ++j
) {
1787 if (sizeof(int32_t) != sizeof(intptr_t))
1788 instructions
[i
+ j
].u
.pointer
= 0;
1789 instructions
[i
+ j
].u
.operand
= pc
[i
+ j
].u
.operand
;
1791 switch (pc
[i
].u
.opcode
) {
1794 case op_get_argument_by_val
: {
1795 int arrayProfileIndex
= pc
[i
+ opLength
- 2].u
.operand
;
1796 m_arrayProfiles
[arrayProfileIndex
] = ArrayProfile(i
);
1798 instructions
[i
+ opLength
- 2] = &m_arrayProfiles
[arrayProfileIndex
];
1801 case op_convert_this
:
1803 case op_call_put_result
:
1804 case op_get_callee
: {
1805 ValueProfile
* profile
= &m_valueProfiles
[pc
[i
+ opLength
- 1].u
.operand
];
1806 ASSERT(profile
->m_bytecodeOffset
== -1);
1807 profile
->m_bytecodeOffset
= i
;
1808 instructions
[i
+ opLength
- 1] = profile
;
1811 case op_put_by_val
: {
1812 int arrayProfileIndex
= pc
[i
+ opLength
- 1].u
.operand
;
1813 m_arrayProfiles
[arrayProfileIndex
] = ArrayProfile(i
);
1814 instructions
[i
+ opLength
- 1] = &m_arrayProfiles
[arrayProfileIndex
];
1819 case op_new_array_buffer
:
1820 case op_new_array_with_size
: {
1821 int arrayAllocationProfileIndex
= pc
[i
+ opLength
- 1].u
.operand
;
1822 instructions
[i
+ opLength
- 1] = &m_arrayAllocationProfiles
[arrayAllocationProfileIndex
];
1826 case op_resolve_base
:
1827 case op_resolve_base_to_global
:
1828 case op_resolve_base_to_global_dynamic
:
1829 case op_resolve_base_to_scope
:
1830 case op_resolve_base_to_scope_with_top_scope_check
: {
1831 instructions
[i
+ 4].u
.resolveOperations
= &m_resolveOperations
[pc
[i
+ 4].u
.operand
];
1832 instructions
[i
+ 5].u
.putToBaseOperation
= &m_putToBaseOperations
[pc
[i
+ 5].u
.operand
];
1834 ValueProfile
* profile
= &m_valueProfiles
[pc
[i
+ opLength
- 1].u
.operand
];
1835 ASSERT(profile
->m_bytecodeOffset
== -1);
1836 profile
->m_bytecodeOffset
= i
;
1837 ASSERT((opLength
- 1) > 5);
1838 instructions
[i
+ opLength
- 1] = profile
;
1842 case op_resolve_global_property
:
1843 case op_resolve_global_var
:
1844 case op_resolve_scoped_var
:
1845 case op_resolve_scoped_var_on_top_scope
:
1846 case op_resolve_scoped_var_with_top_scope_check
: {
1847 instructions
[i
+ 3].u
.resolveOperations
= &m_resolveOperations
[pc
[i
+ 3].u
.operand
];
1850 case op_put_to_base
:
1851 case op_put_to_base_variable
: {
1852 instructions
[i
+ 4].u
.putToBaseOperation
= &m_putToBaseOperations
[pc
[i
+ 4].u
.operand
];
1857 ValueProfile
* profile
= &m_valueProfiles
[pc
[i
+ opLength
- 1].u
.operand
];
1858 ASSERT(profile
->m_bytecodeOffset
== -1);
1859 profile
->m_bytecodeOffset
= i
;
1860 ASSERT((opLength
- 1) > 3);
1861 instructions
[i
+ opLength
- 1] = profile
;
1863 instructions
[i
+ 3].u
.resolveOperations
= &m_resolveOperations
[pc
[i
+ 3].u
.operand
];
1866 case op_resolve_with_base
:
1867 case op_resolve_with_this
: {
1868 instructions
[i
+ 4].u
.resolveOperations
= &m_resolveOperations
[pc
[i
+ 4].u
.operand
];
1869 if (pc
[i
].u
.opcode
!= op_resolve_with_this
)
1870 instructions
[i
+ 5].u
.putToBaseOperation
= &m_putToBaseOperations
[pc
[i
+ 5].u
.operand
];
1872 ValueProfile
* profile
= &m_valueProfiles
[pc
[i
+ opLength
- 1].u
.operand
];
1873 ASSERT(profile
->m_bytecodeOffset
== -1);
1874 profile
->m_bytecodeOffset
= i
;
1875 instructions
[i
+ opLength
- 1] = profile
;
1879 case op_new_object
: {
1880 int objectAllocationProfileIndex
= pc
[i
+ opLength
- 1].u
.operand
;
1881 ObjectAllocationProfile
* objectAllocationProfile
= &m_objectAllocationProfiles
[objectAllocationProfileIndex
];
1882 int inferredInlineCapacity
= pc
[i
+ opLength
- 2].u
.operand
;
1884 instructions
[i
+ opLength
- 1] = objectAllocationProfile
;
1885 objectAllocationProfile
->initialize(*vm(),
1886 m_ownerExecutable
.get(), m_globalObject
->objectPrototype(), inferredInlineCapacity
);
1890 case op_get_scoped_var
: {
1892 ValueProfile
* profile
= &m_valueProfiles
[pc
[i
+ opLength
- 1].u
.operand
];
1893 ASSERT(profile
->m_bytecodeOffset
== -1);
1894 profile
->m_bytecodeOffset
= i
;
1895 instructions
[i
+ opLength
- 1] = profile
;
1901 case op_call_eval
: {
1903 int arrayProfileIndex
= pc
[i
+ opLength
- 1].u
.operand
;
1904 m_arrayProfiles
[arrayProfileIndex
] = ArrayProfile(i
);
1905 instructions
[i
+ opLength
- 1] = &m_arrayProfiles
[arrayProfileIndex
];
1908 instructions
[i
+ 4] = &m_llintCallLinkInfos
[pc
[i
+ 4].u
.operand
];
1914 instructions
[i
+ 4] = &m_llintCallLinkInfos
[pc
[i
+ 4].u
.operand
];
1917 case op_get_by_id_out_of_line
:
1918 case op_get_by_id_self
:
1919 case op_get_by_id_proto
:
1920 case op_get_by_id_chain
:
1921 case op_get_by_id_getter_self
:
1922 case op_get_by_id_getter_proto
:
1923 case op_get_by_id_getter_chain
:
1924 case op_get_by_id_custom_self
:
1925 case op_get_by_id_custom_proto
:
1926 case op_get_by_id_custom_chain
:
1927 case op_get_by_id_generic
:
1928 case op_get_array_length
:
1929 case op_get_string_length
:
1932 case op_init_global_const_nop
: {
1933 ASSERT(codeType() == GlobalCode
);
1934 Identifier ident
= identifier(pc
[i
+ 4].u
.operand
);
1935 SymbolTableEntry entry
= globalObject
->symbolTable()->get(ident
.impl());
1939 if (entry
.couldBeWatched()) {
1940 instructions
[i
+ 0] = vm()->interpreter
->getOpcode(op_init_global_const_check
);
1941 instructions
[i
+ 1] = &globalObject
->registerAt(entry
.getIndex());
1942 instructions
[i
+ 3] = entry
.addressOfIsWatched();
1946 instructions
[i
+ 0] = vm()->interpreter
->getOpcode(op_init_global_const
);
1947 instructions
[i
+ 1] = &globalObject
->registerAt(entry
.getIndex());
1952 instructions
[i
+ 4] = columnNumberForBytecodeOffset(i
);
1961 m_instructions
= WTF::RefCountedArray
<Instruction
>(instructions
);
1963 // Set optimization thresholds only after m_instructions is initialized, since these
1964 // rely on the instruction count (and are in theory permitted to also inspect the
1965 // instruction stream to more accurate assess the cost of tier-up).
1966 optimizeAfterWarmUp();
1969 if (Options::dumpGeneratedBytecodes())
1971 m_vm
->finishedCompiling(this);
1974 CodeBlock::~CodeBlock()
1976 if (m_vm
->m_perBytecodeProfiler
)
1977 m_vm
->m_perBytecodeProfiler
->notifyDestruction(this);
1980 // Remove myself from the set of DFG code blocks. Note that I may not be in this set
1981 // (because I'm not a DFG code block), in which case this is a no-op anyway.
1982 m_vm
->heap
.m_dfgCodeBlocks
.m_set
.remove(this);
1985 #if ENABLE(VERBOSE_VALUE_PROFILE)
1986 dumpValueProfiles();
1990 while (m_incomingLLIntCalls
.begin() != m_incomingLLIntCalls
.end())
1991 m_incomingLLIntCalls
.begin()->remove();
1992 #endif // ENABLE(LLINT)
1994 // We may be destroyed before any CodeBlocks that refer to us are destroyed.
1995 // Consider that two CodeBlocks become unreachable at the same time. There
1996 // is no guarantee about the order in which the CodeBlocks are destroyed.
1997 // So, if we don't remove incoming calls, and get destroyed before the
1998 // CodeBlock(s) that have calls into us, then the CallLinkInfo vector's
1999 // destructor will try to remove nodes from our (no longer valid) linked list.
2000 while (m_incomingCalls
.begin() != m_incomingCalls
.end())
2001 m_incomingCalls
.begin()->remove();
2003 // Note that our outgoing calls will be removed from other CodeBlocks'
2004 // m_incomingCalls linked lists through the execution of the ~CallLinkInfo
2007 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
)
2008 m_structureStubInfos
[i
].deref();
2009 #endif // ENABLE(JIT)
2011 #if DUMP_CODE_BLOCK_STATISTICS
2012 liveCodeBlockSet
.remove(this);
2016 void CodeBlock::setNumParameters(int newValue
)
2018 m_numParameters
= newValue
;
2020 #if ENABLE(VALUE_PROFILER)
2021 m_argumentValueProfiles
.resizeToFit(newValue
);
2025 void CodeBlock::visitStructures(SlotVisitor
& visitor
, Instruction
* vPC
)
2027 Interpreter
* interpreter
= m_vm
->interpreter
;
2029 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_get_by_id
) && vPC
[4].u
.structure
) {
2030 visitor
.append(&vPC
[4].u
.structure
);
2034 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
)) {
2035 visitor
.append(&vPC
[4].u
.structure
);
2038 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
)) {
2039 visitor
.append(&vPC
[4].u
.structure
);
2040 visitor
.append(&vPC
[5].u
.structure
);
2043 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
)) {
2044 visitor
.append(&vPC
[4].u
.structure
);
2045 if (vPC
[5].u
.structureChain
)
2046 visitor
.append(&vPC
[5].u
.structureChain
);
2049 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_transition
)) {
2050 visitor
.append(&vPC
[4].u
.structure
);
2051 visitor
.append(&vPC
[5].u
.structure
);
2052 if (vPC
[6].u
.structureChain
)
2053 visitor
.append(&vPC
[6].u
.structureChain
);
2056 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id
) && vPC
[4].u
.structure
) {
2057 visitor
.append(&vPC
[4].u
.structure
);
2060 if (vPC
[0].u
.opcode
== interpreter
->getOpcode(op_put_by_id_replace
)) {
2061 visitor
.append(&vPC
[4].u
.structure
);
2065 // These instructions don't ref their Structures.
2066 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
));
2069 void EvalCodeCache::visitAggregate(SlotVisitor
& visitor
)
2071 EvalCacheMap::iterator end
= m_cacheMap
.end();
2072 for (EvalCacheMap::iterator ptr
= m_cacheMap
.begin(); ptr
!= end
; ++ptr
)
2073 visitor
.append(&ptr
->value
);
2076 void CodeBlock::visitAggregate(SlotVisitor
& visitor
)
2078 #if ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
2080 // I may be asked to scan myself more than once, and it may even happen concurrently.
2081 // To this end, use a CAS loop to check if I've been called already. Only one thread
2082 // may proceed past this point - whichever one wins the CAS race.
2085 oldValue
= m_dfgData
->visitAggregateHasBeenCalled
;
2087 // Looks like someone else won! Return immediately to ensure that we don't
2088 // trace the same CodeBlock concurrently. Doing so is hazardous since we will
2089 // be mutating the state of ValueProfiles, which contain JSValues, which can
2090 // have word-tearing on 32-bit, leading to awesome timing-dependent crashes
2091 // that are nearly impossible to track down.
2093 // Also note that it must be safe to return early as soon as we see the
2094 // value true (well, (unsigned)1), since once a GC thread is in this method
2095 // and has won the CAS race (i.e. was responsible for setting the value true)
2096 // it will definitely complete the rest of this method before declaring
2100 } while (!WTF::weakCompareAndSwap(&m_dfgData
->visitAggregateHasBeenCalled
, 0, 1));
2102 #endif // ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
2104 if (!!m_alternative
)
2105 m_alternative
->visitAggregate(visitor
);
2107 visitor
.append(&m_unlinkedCode
);
2109 // There are three things that may use unconditional finalizers: lazy bytecode freeing,
2110 // inline cache clearing, and jettisoning. The probability of us wanting to do at
2111 // least one of those things is probably quite close to 1. So we add one no matter what
2112 // and when it runs, it figures out whether it has any work to do.
2113 visitor
.addUnconditionalFinalizer(this);
2115 if (shouldImmediatelyAssumeLivenessDuringScan()) {
2116 // This code block is live, so scan all references strongly and return.
2117 stronglyVisitStrongReferences(visitor
);
2118 stronglyVisitWeakReferences(visitor
);
2123 // We get here if we're live in the sense that our owner executable is live,
2124 // but we're not yet live for sure in another sense: we may yet decide that this
2125 // code block should be jettisoned based on its outgoing weak references being
2126 // stale. Set a flag to indicate that we're still assuming that we're dead, and
2127 // perform one round of determining if we're live. The GC may determine, based on
2128 // either us marking additional objects, or by other objects being marked for
2129 // other reasons, that this iteration should run again; it will notify us of this
2130 // decision by calling harvestWeakReferences().
2132 m_dfgData
->livenessHasBeenProved
= false;
2133 m_dfgData
->allTransitionsHaveBeenMarked
= false;
2135 performTracingFixpointIteration(visitor
);
2137 // GC doesn't have enough information yet for us to decide whether to keep our DFG
2138 // data, so we need to register a handler to run again at the end of GC, when more
2139 // information is available.
2140 if (!(m_dfgData
->livenessHasBeenProved
&& m_dfgData
->allTransitionsHaveBeenMarked
))
2141 visitor
.addWeakReferenceHarvester(this);
2143 #else // ENABLE(DFG_JIT)
2144 RELEASE_ASSERT_NOT_REACHED();
2145 #endif // ENABLE(DFG_JIT)
2148 void CodeBlock::performTracingFixpointIteration(SlotVisitor
& visitor
)
2150 UNUSED_PARAM(visitor
);
2153 // Evaluate our weak reference transitions, if there are still some to evaluate.
2154 if (!m_dfgData
->allTransitionsHaveBeenMarked
) {
2155 bool allAreMarkedSoFar
= true;
2156 for (unsigned i
= 0; i
< m_dfgData
->transitions
.size(); ++i
) {
2157 if ((!m_dfgData
->transitions
[i
].m_codeOrigin
2158 || Heap::isMarked(m_dfgData
->transitions
[i
].m_codeOrigin
.get()))
2159 && Heap::isMarked(m_dfgData
->transitions
[i
].m_from
.get())) {
2160 // If the following three things are live, then the target of the
2161 // transition is also live:
2162 // - This code block. We know it's live already because otherwise
2163 // we wouldn't be scanning ourselves.
2164 // - The code origin of the transition. Transitions may arise from
2165 // code that was inlined. They are not relevant if the user's
2166 // object that is required for the inlinee to run is no longer
2168 // - The source of the transition. The transition checks if some
2169 // heap location holds the source, and if so, stores the target.
2170 // Hence the source must be live for the transition to be live.
2171 visitor
.append(&m_dfgData
->transitions
[i
].m_to
);
2173 allAreMarkedSoFar
= false;
2176 if (allAreMarkedSoFar
)
2177 m_dfgData
->allTransitionsHaveBeenMarked
= true;
2180 // Check if we have any remaining work to do.
2181 if (m_dfgData
->livenessHasBeenProved
)
2184 // Now check all of our weak references. If all of them are live, then we
2185 // have proved liveness and so we scan our strong references. If at end of
2186 // GC we still have not proved liveness, then this code block is toast.
2187 bool allAreLiveSoFar
= true;
2188 for (unsigned i
= 0; i
< m_dfgData
->weakReferences
.size(); ++i
) {
2189 if (!Heap::isMarked(m_dfgData
->weakReferences
[i
].get())) {
2190 allAreLiveSoFar
= false;
2195 // If some weak references are dead, then this fixpoint iteration was
2197 if (!allAreLiveSoFar
)
2200 // All weak references are live. Record this information so we don't
2201 // come back here again, and scan the strong references.
2202 m_dfgData
->livenessHasBeenProved
= true;
2203 stronglyVisitStrongReferences(visitor
);
2204 #endif // ENABLE(DFG_JIT)
2207 void CodeBlock::visitWeakReferences(SlotVisitor
& visitor
)
2209 performTracingFixpointIteration(visitor
);
2212 #if ENABLE(JIT_VERBOSE_OSR)
2213 static const bool verboseUnlinking
= true;
2215 static const bool verboseUnlinking
= false;
2218 void CodeBlock::finalizeUnconditionally()
2221 Interpreter
* interpreter
= m_vm
->interpreter
;
2222 if (!!numberOfInstructions()) {
2223 const Vector
<unsigned>& propertyAccessInstructions
= m_unlinkedCode
->propertyAccessInstructions();
2224 for (size_t size
= propertyAccessInstructions
.size(), i
= 0; i
< size
; ++i
) {
2225 Instruction
* curInstruction
= &instructions()[propertyAccessInstructions
[i
]];
2226 switch (interpreter
->getOpcodeID(curInstruction
[0].u
.opcode
)) {
2228 case op_get_by_id_out_of_line
:
2230 case op_put_by_id_out_of_line
:
2231 if (!curInstruction
[4].u
.structure
|| Heap::isMarked(curInstruction
[4].u
.structure
.get()))
2233 if (verboseUnlinking
)
2234 dataLogF("Clearing LLInt property access with structure %p.\n", curInstruction
[4].u
.structure
.get());
2235 curInstruction
[4].u
.structure
.clear();
2236 curInstruction
[5].u
.operand
= 0;
2238 case op_put_by_id_transition_direct
:
2239 case op_put_by_id_transition_normal
:
2240 case op_put_by_id_transition_direct_out_of_line
:
2241 case op_put_by_id_transition_normal_out_of_line
:
2242 if (Heap::isMarked(curInstruction
[4].u
.structure
.get())
2243 && Heap::isMarked(curInstruction
[6].u
.structure
.get())
2244 && Heap::isMarked(curInstruction
[7].u
.structureChain
.get()))
2246 if (verboseUnlinking
) {
2247 dataLogF("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
2248 curInstruction
[4].u
.structure
.get(),
2249 curInstruction
[6].u
.structure
.get(),
2250 curInstruction
[7].u
.structureChain
.get());
2252 curInstruction
[4].u
.structure
.clear();
2253 curInstruction
[6].u
.structure
.clear();
2254 curInstruction
[7].u
.structureChain
.clear();
2255 curInstruction
[0].u
.opcode
= interpreter
->getOpcode(op_put_by_id
);
2257 case op_get_array_length
:
2260 RELEASE_ASSERT_NOT_REACHED();
2264 for (unsigned i
= 0; i
< m_llintCallLinkInfos
.size(); ++i
) {
2265 if (m_llintCallLinkInfos
[i
].isLinked() && !Heap::isMarked(m_llintCallLinkInfos
[i
].callee
.get())) {
2266 if (verboseUnlinking
)
2267 dataLog("Clearing LLInt call from ", *this, "\n");
2268 m_llintCallLinkInfos
[i
].unlink();
2270 if (!!m_llintCallLinkInfos
[i
].lastSeenCallee
&& !Heap::isMarked(m_llintCallLinkInfos
[i
].lastSeenCallee
.get()))
2271 m_llintCallLinkInfos
[i
].lastSeenCallee
.clear();
2274 #endif // ENABLE(LLINT)
2277 // Check if we're not live. If we are, then jettison.
2278 if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData
->livenessHasBeenProved
)) {
2279 if (verboseUnlinking
)
2280 dataLog(*this, " has dead weak references, jettisoning during GC.\n");
2282 if (DFG::shouldShowDisassembly()) {
2283 dataLog(*this, " will be jettisoned because of the following dead references:\n");
2284 for (unsigned i
= 0; i
< m_dfgData
->transitions
.size(); ++i
) {
2285 WeakReferenceTransition
& transition
= m_dfgData
->transitions
[i
];
2286 JSCell
* origin
= transition
.m_codeOrigin
.get();
2287 JSCell
* from
= transition
.m_from
.get();
2288 JSCell
* to
= transition
.m_to
.get();
2289 if ((!origin
|| Heap::isMarked(origin
)) && Heap::isMarked(from
))
2291 dataLog(" Transition under ", JSValue(origin
), ", ", JSValue(from
), " -> ", JSValue(to
), ".\n");
2293 for (unsigned i
= 0; i
< m_dfgData
->weakReferences
.size(); ++i
) {
2294 JSCell
* weak
= m_dfgData
->weakReferences
[i
].get();
2295 if (Heap::isMarked(weak
))
2297 dataLog(" Weak reference ", JSValue(weak
), ".\n");
2304 #endif // ENABLE(DFG_JIT)
2306 for (size_t size
= m_putToBaseOperations
.size(), i
= 0; i
< size
; ++i
) {
2307 if (m_putToBaseOperations
[i
].m_structure
&& !Heap::isMarked(m_putToBaseOperations
[i
].m_structure
.get())) {
2308 if (verboseUnlinking
)
2309 dataLog("Clearing putToBase info in ", *this, "\n");
2310 m_putToBaseOperations
[i
].m_structure
.clear();
2313 for (size_t size
= m_resolveOperations
.size(), i
= 0; i
< size
; ++i
) {
2314 if (m_resolveOperations
[i
].isEmpty())
2317 for (size_t insnSize
= m_resolveOperations
[i
].size() - 1, k
= 0; k
< insnSize
; ++k
)
2318 ASSERT(!m_resolveOperations
[i
][k
].m_structure
);
2320 m_resolveOperations
[i
].last().m_structure
.clear();
2321 if (m_resolveOperations
[i
].last().m_structure
&& !Heap::isMarked(m_resolveOperations
[i
].last().m_structure
.get())) {
2322 if (verboseUnlinking
)
2323 dataLog("Clearing resolve info in ", *this, "\n");
2324 m_resolveOperations
[i
].last().m_structure
.clear();
2329 // Handle inline caches.
2330 if (!!getJITCode()) {
2331 RepatchBuffer
repatchBuffer(this);
2332 for (unsigned i
= 0; i
< numberOfCallLinkInfos(); ++i
) {
2333 if (callLinkInfo(i
).isLinked()) {
2334 if (ClosureCallStubRoutine
* stub
= callLinkInfo(i
).stub
.get()) {
2335 if (!Heap::isMarked(stub
->structure())
2336 || !Heap::isMarked(stub
->executable())) {
2337 if (verboseUnlinking
) {
2339 "Clearing closure call from ", *this, " to ",
2340 stub
->executable()->hashFor(callLinkInfo(i
).specializationKind()),
2341 ", stub routine ", RawPointer(stub
), ".\n");
2343 callLinkInfo(i
).unlink(*m_vm
, repatchBuffer
);
2345 } else if (!Heap::isMarked(callLinkInfo(i
).callee
.get())) {
2346 if (verboseUnlinking
) {
2348 "Clearing call from ", *this, " to ",
2349 RawPointer(callLinkInfo(i
).callee
.get()), " (",
2350 callLinkInfo(i
).callee
.get()->executable()->hashFor(
2351 callLinkInfo(i
).specializationKind()),
2354 callLinkInfo(i
).unlink(*m_vm
, repatchBuffer
);
2357 if (!!callLinkInfo(i
).lastSeenCallee
2358 && !Heap::isMarked(callLinkInfo(i
).lastSeenCallee
.get()))
2359 callLinkInfo(i
).lastSeenCallee
.clear();
2361 for (size_t size
= m_structureStubInfos
.size(), i
= 0; i
< size
; ++i
) {
2362 StructureStubInfo
& stubInfo
= m_structureStubInfos
[i
];
2364 if (stubInfo
.visitWeakReferences())
2367 resetStubDuringGCInternal(repatchBuffer
, stubInfo
);
2374 void CodeBlock::resetStub(StructureStubInfo
& stubInfo
)
2376 if (stubInfo
.accessType
== access_unset
)
2379 RepatchBuffer
repatchBuffer(this);
2380 resetStubInternal(repatchBuffer
, stubInfo
);
2383 void CodeBlock::resetStubInternal(RepatchBuffer
& repatchBuffer
, StructureStubInfo
& stubInfo
)
2385 AccessType accessType
= static_cast<AccessType
>(stubInfo
.accessType
);
2387 if (verboseUnlinking
)
2388 dataLog("Clearing structure cache (kind ", static_cast<int>(stubInfo
.accessType
), ") in ", *this, ".\n");
2390 if (isGetByIdAccess(accessType
)) {
2391 if (getJITCode().jitType() == JITCode::DFGJIT
)
2392 DFG::dfgResetGetByID(repatchBuffer
, stubInfo
);
2394 JIT::resetPatchGetById(repatchBuffer
, &stubInfo
);
2396 ASSERT(isPutByIdAccess(accessType
));
2397 if (getJITCode().jitType() == JITCode::DFGJIT
)
2398 DFG::dfgResetPutByID(repatchBuffer
, stubInfo
);
2400 JIT::resetPatchPutById(repatchBuffer
, &stubInfo
);
2406 void CodeBlock::resetStubDuringGCInternal(RepatchBuffer
& repatchBuffer
, StructureStubInfo
& stubInfo
)
2408 resetStubInternal(repatchBuffer
, stubInfo
);
2409 stubInfo
.resetByGC
= true;
2413 void CodeBlock::stronglyVisitStrongReferences(SlotVisitor
& visitor
)
2415 visitor
.append(&m_globalObject
);
2416 visitor
.append(&m_ownerExecutable
);
2417 visitor
.append(&m_unlinkedCode
);
2419 m_rareData
->m_evalCodeCache
.visitAggregate(visitor
);
2420 visitor
.appendValues(m_constantRegisters
.data(), m_constantRegisters
.size());
2421 for (size_t i
= 0; i
< m_functionExprs
.size(); ++i
)
2422 visitor
.append(&m_functionExprs
[i
]);
2423 for (size_t i
= 0; i
< m_functionDecls
.size(); ++i
)
2424 visitor
.append(&m_functionDecls
[i
]);
2425 for (unsigned i
= 0; i
< m_objectAllocationProfiles
.size(); ++i
)
2426 m_objectAllocationProfiles
[i
].visitAggregate(visitor
);
2428 updateAllPredictions(Collection
);
2431 void CodeBlock::stronglyVisitWeakReferences(SlotVisitor
& visitor
)
2433 UNUSED_PARAM(visitor
);
2439 for (unsigned i
= 0; i
< m_dfgData
->transitions
.size(); ++i
) {
2440 if (!!m_dfgData
->transitions
[i
].m_codeOrigin
)
2441 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.
2442 visitor
.append(&m_dfgData
->transitions
[i
].m_from
);
2443 visitor
.append(&m_dfgData
->transitions
[i
].m_to
);
2446 for (unsigned i
= 0; i
< m_dfgData
->weakReferences
.size(); ++i
)
2447 visitor
.append(&m_dfgData
->weakReferences
[i
]);
2451 HandlerInfo
* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset
)
2453 RELEASE_ASSERT(bytecodeOffset
< instructions().size());
2458 Vector
<HandlerInfo
>& exceptionHandlers
= m_rareData
->m_exceptionHandlers
;
2459 for (size_t i
= 0; i
< exceptionHandlers
.size(); ++i
) {
2460 // Handlers are ordered innermost first, so the first handler we encounter
2461 // that contains the source address is the correct handler to use.
2462 if (exceptionHandlers
[i
].start
<= bytecodeOffset
&& exceptionHandlers
[i
].end
> bytecodeOffset
)
2463 return &exceptionHandlers
[i
];
2469 unsigned CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset
)
2471 RELEASE_ASSERT(bytecodeOffset
< instructions().size());
2472 return m_ownerExecutable
->lineNo() + m_unlinkedCode
->lineNumberForBytecodeOffset(bytecodeOffset
);
2475 unsigned CodeBlock::columnNumberForBytecodeOffset(unsigned bytecodeOffset
)
2482 expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
2486 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset
, int& divot
, int& startOffset
, int& endOffset
, unsigned& line
, unsigned& column
)
2488 m_unlinkedCode
->expressionRangeForBytecodeOffset(bytecodeOffset
, divot
, startOffset
, endOffset
, line
, column
);
2489 divot
+= m_sourceOffset
;
2490 column
+= line
? 1 : firstLineColumnOffset();
2491 line
+= m_ownerExecutable
->lineNo();
2494 void CodeBlock::shrinkToFit(ShrinkMode shrinkMode
)
2497 m_llintCallLinkInfos
.shrinkToFit();
2500 m_structureStubInfos
.shrinkToFit();
2501 m_callLinkInfos
.shrinkToFit();
2503 #if ENABLE(VALUE_PROFILER)
2504 m_rareCaseProfiles
.shrinkToFit();
2505 m_specialFastCaseProfiles
.shrinkToFit();
2508 if (shrinkMode
== EarlyShrink
) {
2509 m_identifiers
.shrinkToFit();
2510 m_functionDecls
.shrinkToFit();
2511 m_functionExprs
.shrinkToFit();
2512 m_constantRegisters
.shrinkToFit();
2513 } // else don't shrink these, because we would have already pointed pointers into these tables.
2516 m_rareData
->m_exceptionHandlers
.shrinkToFit();
2517 m_rareData
->m_immediateSwitchJumpTables
.shrinkToFit();
2518 m_rareData
->m_characterSwitchJumpTables
.shrinkToFit();
2519 m_rareData
->m_stringSwitchJumpTables
.shrinkToFit();
2521 m_rareData
->m_callReturnIndexVector
.shrinkToFit();
2524 m_rareData
->m_inlineCallFrames
.shrinkToFit();
2525 m_rareData
->m_codeOrigins
.shrinkToFit();
2531 m_dfgData
->osrEntry
.shrinkToFit();
2532 m_dfgData
->osrExit
.shrinkToFit();
2533 m_dfgData
->speculationRecovery
.shrinkToFit();
2534 m_dfgData
->weakReferences
.shrinkToFit();
2535 m_dfgData
->transitions
.shrinkToFit();
2536 m_dfgData
->minifiedDFG
.prepareAndShrink();
2537 m_dfgData
->variableEventStream
.shrinkToFit();
2542 void CodeBlock::createActivation(CallFrame
* callFrame
)
2544 ASSERT(codeType() == FunctionCode
);
2545 ASSERT(needsFullScopeChain());
2546 ASSERT(!callFrame
->uncheckedR(activationRegister()).jsValue());
2547 JSActivation
* activation
= JSActivation::create(callFrame
->vm(), callFrame
, this);
2548 callFrame
->uncheckedR(activationRegister()) = JSValue(activation
);
2549 callFrame
->setScope(activation
);
2552 unsigned CodeBlock::addOrFindConstant(JSValue v
)
2554 unsigned numberOfConstants
= numberOfConstantRegisters();
2555 for (unsigned i
= 0; i
< numberOfConstants
; ++i
) {
2556 if (getConstant(FirstConstantRegisterIndex
+ i
) == v
)
2559 return addConstant(v
);
2563 void CodeBlock::unlinkCalls()
2565 if (!!m_alternative
)
2566 m_alternative
->unlinkCalls();
2568 for (size_t i
= 0; i
< m_llintCallLinkInfos
.size(); ++i
) {
2569 if (m_llintCallLinkInfos
[i
].isLinked())
2570 m_llintCallLinkInfos
[i
].unlink();
2573 if (!m_callLinkInfos
.size())
2575 if (!m_vm
->canUseJIT())
2577 RepatchBuffer
repatchBuffer(this);
2578 for (size_t i
= 0; i
< m_callLinkInfos
.size(); i
++) {
2579 if (!m_callLinkInfos
[i
].isLinked())
2581 m_callLinkInfos
[i
].unlink(*m_vm
, repatchBuffer
);
2585 void CodeBlock::unlinkIncomingCalls()
2588 while (m_incomingLLIntCalls
.begin() != m_incomingLLIntCalls
.end())
2589 m_incomingLLIntCalls
.begin()->unlink();
2591 if (m_incomingCalls
.isEmpty())
2593 RepatchBuffer
repatchBuffer(this);
2594 while (m_incomingCalls
.begin() != m_incomingCalls
.end())
2595 m_incomingCalls
.begin()->unlink(*m_vm
, repatchBuffer
);
2597 #endif // ENABLE(JIT)
2600 Instruction
* CodeBlock::adjustPCIfAtCallSite(Instruction
* potentialReturnPC
)
2602 ASSERT(potentialReturnPC
);
2604 unsigned returnPCOffset
= potentialReturnPC
- instructions().begin();
2605 Instruction
* adjustedPC
;
2606 unsigned opcodeLength
;
2608 // If we are at a callsite, the LLInt stores the PC after the call
2609 // instruction rather than the PC of the call instruction. This requires
2610 // some correcting. If so, we can rely on the fact that the preceding
2611 // instruction must be one of the call instructions, so either it's a
2612 // call_varargs or it's a call, construct, or eval.
2614 // If we are not at a call site, then we need to guard against the
2615 // possibility of peeking past the start of the bytecode range for this
2616 // codeBlock. Hence, we do a bounds check before we peek at the
2617 // potential "preceding" instruction.
2618 // The bounds check is done by comparing the offset of the potential
2619 // returnPC with the length of the opcode. If there is room for a call
2620 // instruction before the returnPC, then the offset of the returnPC must
2621 // be greater than the size of the call opcode we're looking for.
2623 // The determination of the call instruction present (if we are at a
2624 // callsite) depends on the following assumptions. So, assert that
2625 // they are still true:
2626 ASSERT(OPCODE_LENGTH(op_call_varargs
) <= OPCODE_LENGTH(op_call
));
2627 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_construct
));
2628 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_call_eval
));
2630 // Check for the case of a preceeding op_call_varargs:
2631 opcodeLength
= OPCODE_LENGTH(op_call_varargs
);
2632 adjustedPC
= potentialReturnPC
- opcodeLength
;
2633 if ((returnPCOffset
>= opcodeLength
)
2634 && (adjustedPC
->u
.pointer
== LLInt::getCodePtr(llint_op_call_varargs
))) {
2638 // Check for the case of the other 3 call instructions:
2639 opcodeLength
= OPCODE_LENGTH(op_call
);
2640 adjustedPC
= potentialReturnPC
- opcodeLength
;
2641 if ((returnPCOffset
>= opcodeLength
)
2642 && (adjustedPC
->u
.pointer
== LLInt::getCodePtr(llint_op_call
)
2643 || adjustedPC
->u
.pointer
== LLInt::getCodePtr(llint_op_construct
)
2644 || adjustedPC
->u
.pointer
== LLInt::getCodePtr(llint_op_call_eval
))) {
2648 // Not a call site. No need to adjust PC. Just return the original.
2649 return potentialReturnPC
;
2651 #endif // ENABLE(LLINT)
2654 ClosureCallStubRoutine
* CodeBlock::findClosureCallForReturnPC(ReturnAddressPtr returnAddress
)
2656 for (unsigned i
= m_callLinkInfos
.size(); i
--;) {
2657 CallLinkInfo
& info
= m_callLinkInfos
[i
];
2660 if (!info
.stub
->code().executableMemory()->contains(returnAddress
.value()))
2663 RELEASE_ASSERT(info
.stub
->codeOrigin().bytecodeIndex
< CodeOrigin::maximumBytecodeIndex
);
2664 return info
.stub
.get();
2667 // The stub routine may have been jettisoned. This is rare, but we have to handle it.
2668 const JITStubRoutineSet
& set
= m_vm
->heap
.jitStubRoutines();
2669 for (unsigned i
= set
.size(); i
--;) {
2670 GCAwareJITStubRoutine
* genericStub
= set
.at(i
);
2671 if (!genericStub
->isClosureCall())
2673 ClosureCallStubRoutine
* stub
= static_cast<ClosureCallStubRoutine
*>(genericStub
);
2674 if (!stub
->code().executableMemory()->contains(returnAddress
.value()))
2676 RELEASE_ASSERT(stub
->codeOrigin().bytecodeIndex
< CodeOrigin::maximumBytecodeIndex
);
2684 unsigned CodeBlock::bytecodeOffset(ExecState
* exec
, ReturnAddressPtr returnAddress
)
2687 UNUSED_PARAM(returnAddress
);
2689 #if !ENABLE(LLINT_C_LOOP)
2690 // When using the JIT, we could have addresses that are not bytecode
2691 // addresses. We check if the return address is in the LLint glue and
2692 // opcode handlers range here to ensure that we are looking at bytecode
2693 // before attempting to convert the return address into a bytecode offset.
2695 // In the case of the C Loop LLInt, the JIT is disabled, and the only
2696 // valid return addresses should be bytecode PCs. So, we can and need to
2697 // forego this check because when we do not ENABLE(COMPUTED_GOTO_OPCODES),
2698 // then the bytecode "PC"s are actually the opcodeIDs and are not bounded
2699 // by llint_begin and llint_end.
2700 if (returnAddress
.value() >= LLInt::getCodePtr(llint_begin
)
2701 && returnAddress
.value() <= LLInt::getCodePtr(llint_end
))
2704 RELEASE_ASSERT(exec
->codeBlock());
2705 RELEASE_ASSERT(exec
->codeBlock() == this);
2706 RELEASE_ASSERT(JITCode::isBaselineCode(getJITType()));
2707 Instruction
* instruction
= exec
->currentVPC();
2708 RELEASE_ASSERT(instruction
);
2710 instruction
= adjustPCIfAtCallSite(instruction
);
2711 return bytecodeOffset(instruction
);
2713 #endif // !ENABLE(LLINT)
2718 Vector
<CallReturnOffsetToBytecodeOffset
, 0, UnsafeVectorOverflow
>& callIndices
= m_rareData
->m_callReturnIndexVector
;
2719 if (!callIndices
.size())
2722 if (getJITCode().getExecutableMemory()->contains(returnAddress
.value())) {
2723 unsigned callReturnOffset
= getJITCode().offsetOf(returnAddress
.value());
2724 CallReturnOffsetToBytecodeOffset
* result
=
2725 binarySearch
<CallReturnOffsetToBytecodeOffset
, unsigned>(
2726 callIndices
, callIndices
.size(), callReturnOffset
, getCallReturnOffset
);
2727 RELEASE_ASSERT(result
->callReturnOffset
== callReturnOffset
);
2728 RELEASE_ASSERT(result
->bytecodeOffset
< instructionCount());
2729 return result
->bytecodeOffset
;
2731 ClosureCallStubRoutine
* closureInfo
= findClosureCallForReturnPC(returnAddress
);
2732 CodeOrigin origin
= closureInfo
->codeOrigin();
2733 while (InlineCallFrame
* inlineCallFrame
= origin
.inlineCallFrame
) {
2734 if (inlineCallFrame
->baselineCodeBlock() == this)
2736 origin
= inlineCallFrame
->caller
;
2737 RELEASE_ASSERT(origin
.bytecodeIndex
< CodeOrigin::maximumBytecodeIndex
);
2739 RELEASE_ASSERT(origin
.bytecodeIndex
< CodeOrigin::maximumBytecodeIndex
);
2740 unsigned bytecodeIndex
= origin
.bytecodeIndex
;
2741 RELEASE_ASSERT(bytecodeIndex
< instructionCount());
2742 return bytecodeIndex
;
2743 #endif // ENABLE(JIT)
2745 #if !ENABLE(LLINT) && !ENABLE(JIT)
2751 bool CodeBlock::codeOriginForReturn(ReturnAddressPtr returnAddress
, CodeOrigin
& codeOrigin
)
2753 if (!hasCodeOrigins())
2756 if (!getJITCode().getExecutableMemory()->contains(returnAddress
.value())) {
2757 ClosureCallStubRoutine
* stub
= findClosureCallForReturnPC(returnAddress
);
2761 codeOrigin
= stub
->codeOrigin();
2765 unsigned offset
= getJITCode().offsetOf(returnAddress
.value());
2766 CodeOriginAtCallReturnOffset
* entry
=
2767 tryBinarySearch
<CodeOriginAtCallReturnOffset
, unsigned>(
2768 codeOrigins(), codeOrigins().size(), offset
,
2769 getCallReturnOffsetForCodeOrigin
);
2772 codeOrigin
= entry
->codeOrigin
;
2775 #endif // ENABLE(DFG_JIT)
2777 void CodeBlock::clearEvalCache()
2779 if (!!m_alternative
)
2780 m_alternative
->clearEvalCache();
2783 m_rareData
->m_evalCodeCache
.clear();
2786 template<typename T
, size_t inlineCapacity
, typename U
, typename V
>
2787 inline void replaceExistingEntries(Vector
<T
, inlineCapacity
, U
>& target
, Vector
<T
, inlineCapacity
, V
>& source
)
2789 ASSERT(target
.size() <= source
.size());
2790 for (size_t i
= 0; i
< target
.size(); ++i
)
2791 target
[i
] = source
[i
];
2794 void CodeBlock::copyPostParseDataFrom(CodeBlock
* alternative
)
2799 replaceExistingEntries(m_constantRegisters
, alternative
->m_constantRegisters
);
2800 replaceExistingEntries(m_functionDecls
, alternative
->m_functionDecls
);
2801 replaceExistingEntries(m_functionExprs
, alternative
->m_functionExprs
);
2802 if (!!m_rareData
&& !!alternative
->m_rareData
)
2803 replaceExistingEntries(m_rareData
->m_constantBuffers
, alternative
->m_rareData
->m_constantBuffers
);
2806 void CodeBlock::copyPostParseDataFromAlternative()
2808 copyPostParseDataFrom(m_alternative
.get());
2812 void CodeBlock::reoptimize()
2814 ASSERT(replacement() != this);
2815 ASSERT(replacement()->alternative() == this);
2816 if (DFG::shouldShowDisassembly())
2817 dataLog(*replacement(), " will be jettisoned due to reoptimization of ", *this, ".\n");
2818 replacement()->jettison();
2819 countReoptimization();
2822 CodeBlock
* ProgramCodeBlock::replacement()
2824 return &static_cast<ProgramExecutable
*>(ownerExecutable())->generatedBytecode();
2827 CodeBlock
* EvalCodeBlock::replacement()
2829 return &static_cast<EvalExecutable
*>(ownerExecutable())->generatedBytecode();
2832 CodeBlock
* FunctionCodeBlock::replacement()
2834 return &static_cast<FunctionExecutable
*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor
? CodeForConstruct
: CodeForCall
);
2837 JSObject
* ProgramCodeBlock::compileOptimized(ExecState
* exec
, JSScope
* scope
, unsigned bytecodeIndex
)
2839 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2841 JSObject
* error
= static_cast<ProgramExecutable
*>(ownerExecutable())->compileOptimized(exec
, scope
, bytecodeIndex
);
2845 JSObject
* EvalCodeBlock::compileOptimized(ExecState
* exec
, JSScope
* scope
, unsigned bytecodeIndex
)
2847 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2849 JSObject
* error
= static_cast<EvalExecutable
*>(ownerExecutable())->compileOptimized(exec
, scope
, bytecodeIndex
);
2853 JSObject
* FunctionCodeBlock::compileOptimized(ExecState
* exec
, JSScope
* scope
, unsigned bytecodeIndex
)
2855 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2857 JSObject
* error
= static_cast<FunctionExecutable
*>(ownerExecutable())->compileOptimizedFor(exec
, scope
, bytecodeIndex
, m_isConstructor
? CodeForConstruct
: CodeForCall
);
2861 DFG::CapabilityLevel
ProgramCodeBlock::canCompileWithDFGInternal()
2863 return DFG::canCompileProgram(this);
2866 DFG::CapabilityLevel
EvalCodeBlock::canCompileWithDFGInternal()
2868 return DFG::canCompileEval(this);
2871 DFG::CapabilityLevel
FunctionCodeBlock::canCompileWithDFGInternal()
2873 if (m_isConstructor
)
2874 return DFG::canCompileFunctionForConstruct(this);
2875 return DFG::canCompileFunctionForCall(this);
2878 void CodeBlock::jettison()
2880 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2881 ASSERT(this == replacement());
2882 alternative()->optimizeAfterWarmUp();
2883 tallyFrequentExitSites();
2884 if (DFG::shouldShowDisassembly())
2885 dataLog("Jettisoning ", *this, ".\n");
2889 void ProgramCodeBlock::jettisonImpl()
2891 static_cast<ProgramExecutable
*>(ownerExecutable())->jettisonOptimizedCode(*vm());
2894 void EvalCodeBlock::jettisonImpl()
2896 static_cast<EvalExecutable
*>(ownerExecutable())->jettisonOptimizedCode(*vm());
2899 void FunctionCodeBlock::jettisonImpl()
2901 static_cast<FunctionExecutable
*>(ownerExecutable())->jettisonOptimizedCodeFor(*vm(), m_isConstructor
? CodeForConstruct
: CodeForCall
);
2904 bool ProgramCodeBlock::jitCompileImpl(ExecState
* exec
)
2906 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2907 ASSERT(this == replacement());
2908 return static_cast<ProgramExecutable
*>(ownerExecutable())->jitCompile(exec
);
2911 bool EvalCodeBlock::jitCompileImpl(ExecState
* exec
)
2913 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2914 ASSERT(this == replacement());
2915 return static_cast<EvalExecutable
*>(ownerExecutable())->jitCompile(exec
);
2918 bool FunctionCodeBlock::jitCompileImpl(ExecState
* exec
)
2920 ASSERT(getJITType() == JITCode::InterpreterThunk
);
2921 ASSERT(this == replacement());
2922 return static_cast<FunctionExecutable
*>(ownerExecutable())->jitCompileFor(exec
, m_isConstructor
? CodeForConstruct
: CodeForCall
);
2926 JSGlobalObject
* CodeBlock::globalObjectFor(CodeOrigin codeOrigin
)
2928 if (!codeOrigin
.inlineCallFrame
)
2929 return globalObject();
2930 return jsCast
<FunctionExecutable
*>(codeOrigin
.inlineCallFrame
->executable
.get())->generatedBytecode().globalObject();
2933 unsigned CodeBlock::reoptimizationRetryCounter() const
2935 ASSERT(m_reoptimizationRetryCounter
<= Options::reoptimizationRetryCounterMax());
2936 return m_reoptimizationRetryCounter
;
2939 void CodeBlock::countReoptimization()
2941 m_reoptimizationRetryCounter
++;
2942 if (m_reoptimizationRetryCounter
> Options::reoptimizationRetryCounterMax())
2943 m_reoptimizationRetryCounter
= Options::reoptimizationRetryCounterMax();
2946 int32_t CodeBlock::codeTypeThresholdMultiplier() const
2948 if (codeType() == EvalCode
)
2949 return Options::evalThresholdMultiplier();
2954 double CodeBlock::optimizationThresholdScalingFactor()
2956 // This expression arises from doing a least-squares fit of
2958 // F[x_] =: a * Sqrt[x + b] + Abs[c * x] + d
2960 // against the data points:
2963 // 10 0.9 (smallest reasonable code block)
2964 // 200 1.0 (typical small-ish code block)
2965 // 320 1.2 (something I saw in 3d-cube that I wanted to optimize)
2966 // 1268 5.0 (something I saw in 3d-cube that I didn't want to optimize)
2967 // 4000 5.5 (random large size, used to cause the function to converge to a shallow curve of some sort)
2968 // 10000 6.0 (similar to above)
2970 // I achieve the minimization using the following Mathematica code:
2972 // MyFunctionTemplate[x_, a_, b_, c_, d_] := a*Sqrt[x + b] + Abs[c*x] + d
2974 // samples = {{10, 0.9}, {200, 1}, {320, 1.2}, {1268, 5}, {4000, 5.5}, {10000, 6}}
2977 // Minimize[Plus @@ ((MyFunctionTemplate[#[[1]], a, b, c, d] - #[[2]])^2 & /@ samples),
2978 // {a, b, c, d}][[2]]
2980 // And the code below (to initialize a, b, c, d) is generated by:
2982 // Print["const double " <> ToString[#[[1]]] <> " = " <>
2983 // If[#[[2]] < 0.00001, "0.0", ToString[#[[2]]]] <> ";"] & /@ solution
2985 // We've long known the following to be true:
2986 // - Small code blocks are cheap to optimize and so we should do it sooner rather
2988 // - Large code blocks are expensive to optimize and so we should postpone doing so,
2989 // and sometimes have a large enough threshold that we never optimize them.
2990 // - The difference in cost is not totally linear because (a) just invoking the
2991 // DFG incurs some base cost and (b) for large code blocks there is enough slop
2992 // in the correlation between instruction count and the actual compilation cost
2993 // that for those large blocks, the instruction count should not have a strong
2994 // influence on our threshold.
2996 // I knew the goals but I didn't know how to achieve them; so I picked an interesting
2997 // example where the heuristics were right (code block in 3d-cube with instruction
2998 // count 320, which got compiled early as it should have been) and one where they were
2999 // totally wrong (code block in 3d-cube with instruction count 1268, which was expensive
3000 // to compile and didn't run often enough to warrant compilation in my opinion), and
3001 // then threw in additional data points that represented my own guess of what our
3002 // heuristics should do for some round-numbered examples.
3004 // The expression to which I decided to fit the data arose because I started with an
3005 // affine function, and then did two things: put the linear part in an Abs to ensure
3006 // that the fit didn't end up choosing a negative value of c (which would result in
3007 // the function turning over and going negative for large x) and I threw in a Sqrt
3008 // term because Sqrt represents my intution that the function should be more sensitive
3009 // to small changes in small values of x, but less sensitive when x gets large.
3011 // Note that the current fit essentially eliminates the linear portion of the
3012 // expression (c == 0.0).
3013 const double a
= 0.061504;
3014 const double b
= 1.02406;
3015 const double c
= 0.0;
3016 const double d
= 0.825914;
3018 double instructionCount
= this->instructionCount();
3020 ASSERT(instructionCount
); // Make sure this is called only after we have an instruction stream; otherwise it'll just return the value of d, which makes no sense.
3022 double result
= d
+ a
* sqrt(instructionCount
+ b
) + c
* instructionCount
;
3023 #if ENABLE(JIT_VERBOSE_OSR)
3024 dataLog(*this, ": instruction count is ", instructionCount
, ", scaling execution counter by ", result
, " * ", codeTypeThresholdMultiplier(), "\n");
3026 return result
* codeTypeThresholdMultiplier();
3029 static int32_t clipThreshold(double threshold
)
3031 if (threshold
< 1.0)
3034 if (threshold
> static_cast<double>(std::numeric_limits
<int32_t>::max()))
3035 return std::numeric_limits
<int32_t>::max();
3037 return static_cast<int32_t>(threshold
);
3040 int32_t CodeBlock::counterValueForOptimizeAfterWarmUp()
3042 return clipThreshold(
3043 Options::thresholdForOptimizeAfterWarmUp() *
3044 optimizationThresholdScalingFactor() *
3045 (1 << reoptimizationRetryCounter()));
3048 int32_t CodeBlock::counterValueForOptimizeAfterLongWarmUp()
3050 return clipThreshold(
3051 Options::thresholdForOptimizeAfterLongWarmUp() *
3052 optimizationThresholdScalingFactor() *
3053 (1 << reoptimizationRetryCounter()));
3056 int32_t CodeBlock::counterValueForOptimizeSoon()
3058 return clipThreshold(
3059 Options::thresholdForOptimizeSoon() *
3060 optimizationThresholdScalingFactor() *
3061 (1 << reoptimizationRetryCounter()));
3064 bool CodeBlock::checkIfOptimizationThresholdReached()
3066 return m_jitExecuteCounter
.checkIfThresholdCrossedAndSet(this);
3069 void CodeBlock::optimizeNextInvocation()
3071 m_jitExecuteCounter
.setNewThreshold(0, this);
3074 void CodeBlock::dontOptimizeAnytimeSoon()
3076 m_jitExecuteCounter
.deferIndefinitely();
3079 void CodeBlock::optimizeAfterWarmUp()
3081 m_jitExecuteCounter
.setNewThreshold(counterValueForOptimizeAfterWarmUp(), this);
3084 void CodeBlock::optimizeAfterLongWarmUp()
3086 m_jitExecuteCounter
.setNewThreshold(counterValueForOptimizeAfterLongWarmUp(), this);
3089 void CodeBlock::optimizeSoon()
3091 m_jitExecuteCounter
.setNewThreshold(counterValueForOptimizeSoon(), this);
3095 uint32_t CodeBlock::adjustedExitCountThreshold(uint32_t desiredThreshold
)
3097 ASSERT(getJITType() == JITCode::DFGJIT
);
3098 // Compute this the lame way so we don't saturate. This is called infrequently
3099 // enough that this loop won't hurt us.
3100 unsigned result
= desiredThreshold
;
3101 for (unsigned n
= baselineVersion()->reoptimizationRetryCounter(); n
--;) {
3102 unsigned newResult
= result
<< 1;
3103 if (newResult
< result
)
3104 return std::numeric_limits
<uint32_t>::max();
3110 uint32_t CodeBlock::exitCountThresholdForReoptimization()
3112 return adjustedExitCountThreshold(Options::osrExitCountForReoptimization() * codeTypeThresholdMultiplier());
3115 uint32_t CodeBlock::exitCountThresholdForReoptimizationFromLoop()
3117 return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop() * codeTypeThresholdMultiplier());
3120 bool CodeBlock::shouldReoptimizeNow()
3122 return osrExitCounter() >= exitCountThresholdForReoptimization();
3125 bool CodeBlock::shouldReoptimizeFromLoopNow()
3127 return osrExitCounter() >= exitCountThresholdForReoptimizationFromLoop();
3131 #if ENABLE(VALUE_PROFILER)
3132 ArrayProfile
* CodeBlock::getArrayProfile(unsigned bytecodeOffset
)
3134 for (unsigned i
= 0; i
< m_arrayProfiles
.size(); ++i
) {
3135 if (m_arrayProfiles
[i
].bytecodeOffset() == bytecodeOffset
)
3136 return &m_arrayProfiles
[i
];
3141 ArrayProfile
* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset
)
3143 ArrayProfile
* result
= getArrayProfile(bytecodeOffset
);
3146 return addArrayProfile(bytecodeOffset
);
3149 void CodeBlock::updateAllPredictionsAndCountLiveness(
3150 OperationInProgress operation
, unsigned& numberOfLiveNonArgumentValueProfiles
, unsigned& numberOfSamplesInProfiles
)
3152 numberOfLiveNonArgumentValueProfiles
= 0;
3153 numberOfSamplesInProfiles
= 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
3154 for (unsigned i
= 0; i
< totalNumberOfValueProfiles(); ++i
) {
3155 ValueProfile
* profile
= getFromAllValueProfiles(i
);
3156 unsigned numSamples
= profile
->totalNumberOfSamples();
3157 if (numSamples
> ValueProfile::numberOfBuckets
)
3158 numSamples
= ValueProfile::numberOfBuckets
; // We don't want profiles that are extremely hot to be given more weight.
3159 numberOfSamplesInProfiles
+= numSamples
;
3160 if (profile
->m_bytecodeOffset
< 0) {
3161 profile
->computeUpdatedPrediction(operation
);
3164 if (profile
->numberOfSamples() || profile
->m_prediction
!= SpecNone
)
3165 numberOfLiveNonArgumentValueProfiles
++;
3166 profile
->computeUpdatedPrediction(operation
);
3170 m_lazyOperandValueProfiles
.computeUpdatedPredictions(operation
);
3174 void CodeBlock::updateAllValueProfilePredictions(OperationInProgress operation
)
3176 unsigned ignoredValue1
, ignoredValue2
;
3177 updateAllPredictionsAndCountLiveness(operation
, ignoredValue1
, ignoredValue2
);
3180 void CodeBlock::updateAllArrayPredictions(OperationInProgress operation
)
3182 for (unsigned i
= m_arrayProfiles
.size(); i
--;)
3183 m_arrayProfiles
[i
].computeUpdatedPrediction(this, operation
);
3185 // Don't count these either, for similar reasons.
3186 for (unsigned i
= m_arrayAllocationProfiles
.size(); i
--;)
3187 m_arrayAllocationProfiles
[i
].updateIndexingType();
3190 void CodeBlock::updateAllPredictions(OperationInProgress operation
)
3192 updateAllValueProfilePredictions(operation
);
3193 updateAllArrayPredictions(operation
);
3196 bool CodeBlock::shouldOptimizeNow()
3198 #if ENABLE(JIT_VERBOSE_OSR)
3199 dataLog("Considering optimizing ", *this, "...\n");
3202 #if ENABLE(VERBOSE_VALUE_PROFILE)
3203 dumpValueProfiles();
3206 if (m_optimizationDelayCounter
>= Options::maximumOptimizationDelay())
3209 updateAllArrayPredictions();
3211 unsigned numberOfLiveNonArgumentValueProfiles
;
3212 unsigned numberOfSamplesInProfiles
;
3213 updateAllPredictionsAndCountLiveness(NoOperation
, numberOfLiveNonArgumentValueProfiles
, numberOfSamplesInProfiles
);
3215 #if ENABLE(JIT_VERBOSE_OSR)
3216 dataLogF("Profile hotness: %lf (%u / %u), %lf (%u / %u)\n", (double)numberOfLiveNonArgumentValueProfiles
/ numberOfValueProfiles(), numberOfLiveNonArgumentValueProfiles
, numberOfValueProfiles(), (double)numberOfSamplesInProfiles
/ ValueProfile::numberOfBuckets
/ numberOfValueProfiles(), numberOfSamplesInProfiles
, ValueProfile::numberOfBuckets
* numberOfValueProfiles());
3219 if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles
/ numberOfValueProfiles() >= Options::desiredProfileLivenessRate())
3220 && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles
/ ValueProfile::numberOfBuckets
/ totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate())
3221 && static_cast<unsigned>(m_optimizationDelayCounter
) + 1 >= Options::minimumOptimizationDelay())
3224 ASSERT(m_optimizationDelayCounter
< std::numeric_limits
<uint8_t>::max());
3225 m_optimizationDelayCounter
++;
3226 optimizeAfterWarmUp();
3232 void CodeBlock::tallyFrequentExitSites()
3234 ASSERT(getJITType() == JITCode::DFGJIT
);
3235 ASSERT(alternative()->getJITType() == JITCode::BaselineJIT
);
3236 ASSERT(!!m_dfgData
);
3238 CodeBlock
* profiledBlock
= alternative();
3240 for (unsigned i
= 0; i
< m_dfgData
->osrExit
.size(); ++i
) {
3241 DFG::OSRExit
& exit
= m_dfgData
->osrExit
[i
];
3243 if (!exit
.considerAddingAsFrequentExitSite(profiledBlock
))
3246 #if DFG_ENABLE(DEBUG_VERBOSE)
3247 dataLog("OSR exit #", i
, " (bc#", exit
.m_codeOrigin
.bytecodeIndex
, ", ", exit
.m_kind
, ") for ", *this, " occurred frequently: counting as frequent exit site.\n");
3251 #endif // ENABLE(DFG_JIT)
3253 #if ENABLE(VERBOSE_VALUE_PROFILE)
3254 void CodeBlock::dumpValueProfiles()
3256 dataLog("ValueProfile for ", *this, ":\n");
3257 for (unsigned i
= 0; i
< totalNumberOfValueProfiles(); ++i
) {
3258 ValueProfile
* profile
= getFromAllValueProfiles(i
);
3259 if (profile
->m_bytecodeOffset
< 0) {
3260 ASSERT(profile
->m_bytecodeOffset
== -1);
3261 dataLogF(" arg = %u: ", i
);
3263 dataLogF(" bc = %d: ", profile
->m_bytecodeOffset
);
3264 if (!profile
->numberOfSamples() && profile
->m_prediction
== SpecNone
) {
3265 dataLogF("<empty>\n");
3268 profile
->dump(WTF::dataFile());
3271 dataLog("RareCaseProfile for ", *this, ":\n");
3272 for (unsigned i
= 0; i
< numberOfRareCaseProfiles(); ++i
) {
3273 RareCaseProfile
* profile
= rareCaseProfile(i
);
3274 dataLogF(" bc = %d: %u\n", profile
->m_bytecodeOffset
, profile
->m_counter
);
3276 dataLog("SpecialFastCaseProfile for ", *this, ":\n");
3277 for (unsigned i
= 0; i
< numberOfSpecialFastCaseProfiles(); ++i
) {
3278 RareCaseProfile
* profile
= specialFastCaseProfile(i
);
3279 dataLogF(" bc = %d: %u\n", profile
->m_bytecodeOffset
, profile
->m_counter
);
3282 #endif // ENABLE(VERBOSE_VALUE_PROFILE)
3284 size_t CodeBlock::predictedMachineCodeSize()
3286 // This will be called from CodeBlock::CodeBlock before either m_vm or the
3287 // instructions have been initialized. It's OK to return 0 because what will really
3288 // matter is the recomputation of this value when the slow path is triggered.
3292 if (!m_vm
->machineCodeBytesPerBytecodeWordForBaselineJIT
)
3293 return 0; // It's as good of a prediction as we'll get.
3295 // Be conservative: return a size that will be an overestimation 84% of the time.
3296 double multiplier
= m_vm
->machineCodeBytesPerBytecodeWordForBaselineJIT
.mean() +
3297 m_vm
->machineCodeBytesPerBytecodeWordForBaselineJIT
.standardDeviation();
3299 // Be paranoid: silently reject bogus multipiers. Silently doing the "wrong" thing
3300 // here is OK, since this whole method is just a heuristic.
3301 if (multiplier
< 0 || multiplier
> 1000)
3304 double doubleResult
= multiplier
* m_instructions
.size();
3306 // Be even more paranoid: silently reject values that won't fit into a size_t. If
3307 // the function is so huge that we can't even fit it into virtual memory then we
3308 // should probably have some other guards in place to prevent us from even getting
3310 if (doubleResult
> std::numeric_limits
<size_t>::max())
3313 return static_cast<size_t>(doubleResult
);
3316 bool CodeBlock::usesOpcode(OpcodeID opcodeID
)
3318 Interpreter
* interpreter
= vm()->interpreter
;
3319 Instruction
* instructionsBegin
= instructions().begin();
3320 unsigned instructionCount
= instructions().size();
3322 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
; ) {
3323 switch (interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
)) {
3324 #define DEFINE_OP(curOpcode, length) \
3326 if (curOpcode == opcodeID) \
3328 bytecodeOffset += length; \
3330 FOR_EACH_OPCODE_ID(DEFINE_OP
)
3333 RELEASE_ASSERT_NOT_REACHED();
3341 String
CodeBlock::nameForRegister(int registerNumber
)
3343 SymbolTable::iterator end
= symbolTable()->end();
3344 for (SymbolTable::iterator ptr
= symbolTable()->begin(); ptr
!= end
; ++ptr
) {
3345 if (ptr
->value
.getIndex() == registerNumber
)
3346 return String(ptr
->key
);
3348 if (needsActivation() && registerNumber
== activationRegister())
3349 return ASCIILiteral("activation");
3350 if (registerNumber
== thisRegister())
3351 return ASCIILiteral("this");
3352 if (usesArguments()) {
3353 if (registerNumber
== argumentsRegister())
3354 return ASCIILiteral("arguments");
3355 if (unmodifiedArgumentsRegister(argumentsRegister()) == registerNumber
)
3356 return ASCIILiteral("real arguments");
3358 if (registerNumber
< 0) {
3359 int argumentPosition
= -registerNumber
;
3360 argumentPosition
-= JSStack::CallFrameHeaderSize
+ 1;
3361 return String::format("arguments[%3d]", argumentPosition
- 1).impl();