]> git.saurik.com Git - apple/javascriptcore.git/blob - bytecode/CodeBlock.cpp
da60b48a1c793fd75339a79c1a3b7e675f9a9962
[apple/javascriptcore.git] / bytecode / CodeBlock.cpp
1 /*
2 * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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 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.
17 *
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.
28 */
29
30 #include "config.h"
31 #include "CodeBlock.h"
32
33 #include "BytecodeGenerator.h"
34 #include "BytecodeUseDef.h"
35 #include "CallLinkStatus.h"
36 #include "DFGCapabilities.h"
37 #include "DFGCommon.h"
38 #include "DFGDriver.h"
39 #include "DFGJITCode.h"
40 #include "DFGWorklist.h"
41 #include "Debugger.h"
42 #include "Interpreter.h"
43 #include "JIT.h"
44 #include "JITStubs.h"
45 #include "JSActivation.h"
46 #include "JSCJSValue.h"
47 #include "JSFunction.h"
48 #include "JSNameScope.h"
49 #include "LLIntEntrypoint.h"
50 #include "LowLevelInterpreter.h"
51 #include "JSCInlines.h"
52 #include "PolymorphicGetByIdList.h"
53 #include "PolymorphicPutByIdList.h"
54 #include "ProfilerDatabase.h"
55 #include "ReduceWhitespace.h"
56 #include "Repatch.h"
57 #include "RepatchBuffer.h"
58 #include "SlotVisitorInlines.h"
59 #include "UnlinkedInstructionStream.h"
60 #include <wtf/BagToHashMap.h>
61 #include <wtf/CommaPrinter.h>
62 #include <wtf/StringExtras.h>
63 #include <wtf/StringPrintStream.h>
64
65 #if ENABLE(DFG_JIT)
66 #include "DFGOperations.h"
67 #endif
68
69 #if ENABLE(FTL_JIT)
70 #include "FTLJITCode.h"
71 #endif
72
73 namespace JSC {
74
75 CString CodeBlock::inferredName() const
76 {
77 switch (codeType()) {
78 case GlobalCode:
79 return "<global>";
80 case EvalCode:
81 return "<eval>";
82 case FunctionCode:
83 return jsCast<FunctionExecutable*>(ownerExecutable())->inferredName().utf8();
84 default:
85 CRASH();
86 return CString("", 0);
87 }
88 }
89
90 bool CodeBlock::hasHash() const
91 {
92 return !!m_hash;
93 }
94
95 bool CodeBlock::isSafeToComputeHash() const
96 {
97 return !isCompilationThread();
98 }
99
100 CodeBlockHash CodeBlock::hash() const
101 {
102 if (!m_hash) {
103 RELEASE_ASSERT(isSafeToComputeHash());
104 m_hash = CodeBlockHash(ownerExecutable()->source(), specializationKind());
105 }
106 return m_hash;
107 }
108
109 CString CodeBlock::sourceCodeForTools() const
110 {
111 if (codeType() != FunctionCode)
112 return ownerExecutable()->source().toUTF8();
113
114 SourceProvider* provider = source();
115 FunctionExecutable* executable = jsCast<FunctionExecutable*>(ownerExecutable());
116 UnlinkedFunctionExecutable* unlinked = executable->unlinkedExecutable();
117 unsigned unlinkedStartOffset = unlinked->startOffset();
118 unsigned linkedStartOffset = executable->source().startOffset();
119 int delta = linkedStartOffset - unlinkedStartOffset;
120 unsigned rangeStart = delta + unlinked->unlinkedFunctionNameStart();
121 unsigned rangeEnd = delta + unlinked->startOffset() + unlinked->sourceLength();
122 return toCString(
123 "function ",
124 provider->source().impl()->utf8ForRange(rangeStart, rangeEnd - rangeStart));
125 }
126
127 CString CodeBlock::sourceCodeOnOneLine() const
128 {
129 return reduceWhitespace(sourceCodeForTools());
130 }
131
132 CString CodeBlock::hashAsStringIfPossible() const
133 {
134 if (hasHash() || isSafeToComputeHash())
135 return toCString(hash());
136 return "<no-hash>";
137 }
138
139 void CodeBlock::dumpAssumingJITType(PrintStream& out, JITCode::JITType jitType) const
140 {
141 out.print(inferredName(), "#", hashAsStringIfPossible());
142 out.print(":[", RawPointer(this), "->");
143 if (!!m_alternative)
144 out.print(RawPointer(m_alternative.get()), "->");
145 out.print(RawPointer(ownerExecutable()), ", ", jitType, codeType());
146
147 if (codeType() == FunctionCode)
148 out.print(specializationKind());
149 out.print(", ", instructionCount());
150 if (this->jitType() == JITCode::BaselineJIT && m_shouldAlwaysBeInlined)
151 out.print(" (SABI)");
152 if (ownerExecutable()->neverInline())
153 out.print(" (NeverInline)");
154 if (ownerExecutable()->isStrictMode())
155 out.print(" (StrictMode)");
156 if (this->jitType() == JITCode::BaselineJIT && m_didFailFTLCompilation)
157 out.print(" (FTLFail)");
158 if (this->jitType() == JITCode::BaselineJIT && m_hasBeenCompiledWithFTL)
159 out.print(" (HadFTLReplacement)");
160 out.print("]");
161 }
162
163 void CodeBlock::dump(PrintStream& out) const
164 {
165 dumpAssumingJITType(out, jitType());
166 }
167
168 static CString constantName(int k, JSValue value)
169 {
170 return toCString(value, "(@k", k - FirstConstantRegisterIndex, ")");
171 }
172
173 static CString idName(int id0, const Identifier& ident)
174 {
175 return toCString(ident.impl(), "(@id", id0, ")");
176 }
177
178 CString CodeBlock::registerName(int r) const
179 {
180 if (r == missingThisObjectMarker())
181 return "<null>";
182
183 if (isConstantRegisterIndex(r))
184 return constantName(r, getConstant(r));
185
186 if (operandIsArgument(r)) {
187 if (!VirtualRegister(r).toArgument())
188 return "this";
189 return toCString("arg", VirtualRegister(r).toArgument());
190 }
191
192 return toCString("loc", VirtualRegister(r).toLocal());
193 }
194
195 static CString regexpToSourceString(RegExp* regExp)
196 {
197 char postfix[5] = { '/', 0, 0, 0, 0 };
198 int index = 1;
199 if (regExp->global())
200 postfix[index++] = 'g';
201 if (regExp->ignoreCase())
202 postfix[index++] = 'i';
203 if (regExp->multiline())
204 postfix[index] = 'm';
205
206 return toCString("/", regExp->pattern().impl(), postfix);
207 }
208
209 static CString regexpName(int re, RegExp* regexp)
210 {
211 return toCString(regexpToSourceString(regexp), "(@re", re, ")");
212 }
213
214 NEVER_INLINE static const char* debugHookName(int debugHookID)
215 {
216 switch (static_cast<DebugHookID>(debugHookID)) {
217 case DidEnterCallFrame:
218 return "didEnterCallFrame";
219 case WillLeaveCallFrame:
220 return "willLeaveCallFrame";
221 case WillExecuteStatement:
222 return "willExecuteStatement";
223 case WillExecuteProgram:
224 return "willExecuteProgram";
225 case DidExecuteProgram:
226 return "didExecuteProgram";
227 case DidReachBreakpoint:
228 return "didReachBreakpoint";
229 }
230
231 RELEASE_ASSERT_NOT_REACHED();
232 return "";
233 }
234
235 void CodeBlock::printUnaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
236 {
237 int r0 = (++it)->u.operand;
238 int r1 = (++it)->u.operand;
239
240 printLocationAndOp(out, exec, location, it, op);
241 out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
242 }
243
244 void CodeBlock::printBinaryOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
245 {
246 int r0 = (++it)->u.operand;
247 int r1 = (++it)->u.operand;
248 int r2 = (++it)->u.operand;
249 printLocationAndOp(out, exec, location, it, op);
250 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
251 }
252
253 void CodeBlock::printConditionalJump(PrintStream& out, ExecState* exec, const Instruction*, const Instruction*& it, int location, const char* op)
254 {
255 int r0 = (++it)->u.operand;
256 int offset = (++it)->u.operand;
257 printLocationAndOp(out, exec, location, it, op);
258 out.printf("%s, %d(->%d)", registerName(r0).data(), offset, location + offset);
259 }
260
261 void CodeBlock::printGetByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it)
262 {
263 const char* op;
264 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
265 case op_get_by_id:
266 op = "get_by_id";
267 break;
268 case op_get_by_id_out_of_line:
269 op = "get_by_id_out_of_line";
270 break;
271 case op_get_array_length:
272 op = "array_length";
273 break;
274 default:
275 RELEASE_ASSERT_NOT_REACHED();
276 op = 0;
277 }
278 int r0 = (++it)->u.operand;
279 int r1 = (++it)->u.operand;
280 int id0 = (++it)->u.operand;
281 printLocationAndOp(out, exec, location, it, op);
282 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
283 it += 4; // Increment up to the value profiler.
284 }
285
286 static void dumpStructure(PrintStream& out, const char* name, ExecState* exec, Structure* structure, const Identifier& ident)
287 {
288 if (!structure)
289 return;
290
291 out.printf("%s = %p", name, structure);
292
293 PropertyOffset offset = structure->getConcurrently(exec->vm(), ident.impl());
294 if (offset != invalidOffset)
295 out.printf(" (offset = %d)", offset);
296 }
297
298 #if ENABLE(JIT) // unused when not ENABLE(JIT), leading to silly warnings
299 static void dumpChain(PrintStream& out, ExecState* exec, StructureChain* chain, const Identifier& ident)
300 {
301 out.printf("chain = %p: [", chain);
302 bool first = true;
303 for (WriteBarrier<Structure>* currentStructure = chain->head();
304 *currentStructure;
305 ++currentStructure) {
306 if (first)
307 first = false;
308 else
309 out.printf(", ");
310 dumpStructure(out, "struct", exec, currentStructure->get(), ident);
311 }
312 out.printf("]");
313 }
314 #endif
315
316 void CodeBlock::printGetByIdCacheStatus(PrintStream& out, ExecState* exec, int location, const StubInfoMap& map)
317 {
318 Instruction* instruction = instructions().begin() + location;
319
320 const Identifier& ident = identifier(instruction[3].u.operand);
321
322 UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations.
323
324 if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
325 out.printf(" llint(array_length)");
326 else if (Structure* structure = instruction[4].u.structure.get()) {
327 out.printf(" llint(");
328 dumpStructure(out, "struct", exec, structure, ident);
329 out.printf(")");
330 }
331
332 #if ENABLE(JIT)
333 if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) {
334 StructureStubInfo& stubInfo = *stubPtr;
335 if (stubInfo.resetByGC)
336 out.print(" (Reset By GC)");
337
338 if (stubInfo.seen) {
339 out.printf(" jit(");
340
341 Structure* baseStructure = 0;
342 Structure* prototypeStructure = 0;
343 StructureChain* chain = 0;
344 PolymorphicGetByIdList* list = 0;
345
346 switch (stubInfo.accessType) {
347 case access_get_by_id_self:
348 out.printf("self");
349 baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
350 break;
351 case access_get_by_id_chain:
352 out.printf("chain");
353 baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get();
354 chain = stubInfo.u.getByIdChain.chain.get();
355 break;
356 case access_get_by_id_list:
357 out.printf("list");
358 list = stubInfo.u.getByIdList.list;
359 break;
360 case access_unset:
361 out.printf("unset");
362 break;
363 default:
364 RELEASE_ASSERT_NOT_REACHED();
365 break;
366 }
367
368 if (baseStructure) {
369 out.printf(", ");
370 dumpStructure(out, "struct", exec, baseStructure, ident);
371 }
372
373 if (prototypeStructure) {
374 out.printf(", ");
375 dumpStructure(out, "prototypeStruct", exec, baseStructure, ident);
376 }
377
378 if (chain) {
379 out.printf(", ");
380 dumpChain(out, exec, chain, ident);
381 }
382
383 if (list) {
384 out.printf(", list = %p: [", list);
385 for (unsigned i = 0; i < list->size(); ++i) {
386 if (i)
387 out.printf(", ");
388 out.printf("(");
389 dumpStructure(out, "base", exec, list->at(i).structure(), ident);
390 if (list->at(i).chain()) {
391 out.printf(", ");
392 dumpChain(out, exec, list->at(i).chain(), ident);
393 }
394 out.printf(")");
395 }
396 out.printf("]");
397 }
398 out.printf(")");
399 }
400 }
401 #else
402 UNUSED_PARAM(map);
403 #endif
404 }
405
406 void CodeBlock::printCallOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map)
407 {
408 int dst = (++it)->u.operand;
409 int func = (++it)->u.operand;
410 int argCount = (++it)->u.operand;
411 int registerOffset = (++it)->u.operand;
412 printLocationAndOp(out, exec, location, it, op);
413 out.printf("%s, %s, %d, %d", registerName(dst).data(), registerName(func).data(), argCount, registerOffset);
414 if (cacheDumpMode == DumpCaches) {
415 LLIntCallLinkInfo* callLinkInfo = it[1].u.callLinkInfo;
416 if (callLinkInfo->lastSeenCallee) {
417 out.printf(
418 " llint(%p, exec %p)",
419 callLinkInfo->lastSeenCallee.get(),
420 callLinkInfo->lastSeenCallee->executable());
421 }
422 #if ENABLE(JIT)
423 if (CallLinkInfo* info = map.get(CodeOrigin(location))) {
424 JSFunction* target = info->lastSeenCallee.get();
425 if (target)
426 out.printf(" jit(%p, exec %p)", target, target->executable());
427 }
428 out.print(" status(", CallLinkStatus::computeFor(this, location, map), ")");
429 #else
430 UNUSED_PARAM(map);
431 #endif
432 }
433 ++it;
434 ++it;
435 dumpArrayProfiling(out, it, hasPrintedProfiling);
436 dumpValueProfiling(out, it, hasPrintedProfiling);
437 }
438
439 void CodeBlock::printPutByIdOp(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op)
440 {
441 int r0 = (++it)->u.operand;
442 int id0 = (++it)->u.operand;
443 int r1 = (++it)->u.operand;
444 printLocationAndOp(out, exec, location, it, op);
445 out.printf("%s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data());
446 it += 5;
447 }
448
449 void CodeBlock::dumpBytecode(PrintStream& out)
450 {
451 // We only use the ExecState* for things that don't actually lead to JS execution,
452 // like converting a JSString to a String. Hence the globalExec is appropriate.
453 ExecState* exec = m_globalObject->globalExec();
454
455 size_t instructionCount = 0;
456
457 for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
458 ++instructionCount;
459
460 out.print(*this);
461 out.printf(
462 ": %lu m_instructions; %lu bytes; %d parameter(s); %d callee register(s); %d variable(s)",
463 static_cast<unsigned long>(instructions().size()),
464 static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
465 m_numParameters, m_numCalleeRegisters, m_numVars);
466 if (symbolTable() && symbolTable()->captureCount()) {
467 out.printf(
468 "; %d captured var(s) (from r%d to r%d, inclusive)",
469 symbolTable()->captureCount(), symbolTable()->captureStart(), symbolTable()->captureEnd() + 1);
470 }
471 if (usesArguments()) {
472 out.printf(
473 "; uses arguments, in r%d, r%d",
474 argumentsRegister().offset(),
475 unmodifiedArgumentsRegister(argumentsRegister()).offset());
476 }
477 if (needsActivation() && codeType() == FunctionCode)
478 out.printf("; activation in r%d", activationRegister().offset());
479 out.printf("\n");
480
481 StubInfoMap stubInfos;
482 CallLinkInfoMap callLinkInfos;
483 getStubInfoMap(stubInfos);
484 getCallLinkInfoMap(callLinkInfos);
485
486 const Instruction* begin = instructions().begin();
487 const Instruction* end = instructions().end();
488 for (const Instruction* it = begin; it != end; ++it)
489 dumpBytecode(out, exec, begin, it, stubInfos, callLinkInfos);
490
491 if (numberOfIdentifiers()) {
492 out.printf("\nIdentifiers:\n");
493 size_t i = 0;
494 do {
495 out.printf(" id%u = %s\n", static_cast<unsigned>(i), identifier(i).string().utf8().data());
496 ++i;
497 } while (i != numberOfIdentifiers());
498 }
499
500 if (!m_constantRegisters.isEmpty()) {
501 out.printf("\nConstants:\n");
502 size_t i = 0;
503 do {
504 out.printf(" k%u = %s\n", static_cast<unsigned>(i), toCString(m_constantRegisters[i].get()).data());
505 ++i;
506 } while (i < m_constantRegisters.size());
507 }
508
509 if (size_t count = m_unlinkedCode->numberOfRegExps()) {
510 out.printf("\nm_regexps:\n");
511 size_t i = 0;
512 do {
513 out.printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).data());
514 ++i;
515 } while (i < count);
516 }
517
518 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
519 out.printf("\nException Handlers:\n");
520 unsigned i = 0;
521 do {
522 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);
523 ++i;
524 } while (i < m_rareData->m_exceptionHandlers.size());
525 }
526
527 if (m_rareData && !m_rareData->m_switchJumpTables.isEmpty()) {
528 out.printf("Switch Jump Tables:\n");
529 unsigned i = 0;
530 do {
531 out.printf(" %1d = {\n", i);
532 int entry = 0;
533 Vector<int32_t>::const_iterator end = m_rareData->m_switchJumpTables[i].branchOffsets.end();
534 for (Vector<int32_t>::const_iterator iter = m_rareData->m_switchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
535 if (!*iter)
536 continue;
537 out.printf("\t\t%4d => %04d\n", entry + m_rareData->m_switchJumpTables[i].min, *iter);
538 }
539 out.printf(" }\n");
540 ++i;
541 } while (i < m_rareData->m_switchJumpTables.size());
542 }
543
544 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
545 out.printf("\nString Switch Jump Tables:\n");
546 unsigned i = 0;
547 do {
548 out.printf(" %1d = {\n", i);
549 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
550 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
551 out.printf("\t\t\"%s\" => %04d\n", iter->key->utf8().data(), iter->value.branchOffset);
552 out.printf(" }\n");
553 ++i;
554 } while (i < m_rareData->m_stringSwitchJumpTables.size());
555 }
556
557 out.printf("\n");
558 }
559
560 void CodeBlock::beginDumpProfiling(PrintStream& out, bool& hasPrintedProfiling)
561 {
562 if (hasPrintedProfiling) {
563 out.print("; ");
564 return;
565 }
566
567 out.print(" ");
568 hasPrintedProfiling = true;
569 }
570
571 void CodeBlock::dumpValueProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
572 {
573 ConcurrentJITLocker locker(m_lock);
574
575 ++it;
576 CString description = it->u.profile->briefDescription(locker);
577 if (!description.length())
578 return;
579 beginDumpProfiling(out, hasPrintedProfiling);
580 out.print(description);
581 }
582
583 void CodeBlock::dumpArrayProfiling(PrintStream& out, const Instruction*& it, bool& hasPrintedProfiling)
584 {
585 ConcurrentJITLocker locker(m_lock);
586
587 ++it;
588 if (!it->u.arrayProfile)
589 return;
590 CString description = it->u.arrayProfile->briefDescription(locker, this);
591 if (!description.length())
592 return;
593 beginDumpProfiling(out, hasPrintedProfiling);
594 out.print(description);
595 }
596
597 void CodeBlock::dumpRareCaseProfile(PrintStream& out, const char* name, RareCaseProfile* profile, bool& hasPrintedProfiling)
598 {
599 if (!profile || !profile->m_counter)
600 return;
601
602 beginDumpProfiling(out, hasPrintedProfiling);
603 out.print(name, profile->m_counter);
604 }
605
606 void CodeBlock::printLocationAndOp(PrintStream& out, ExecState*, int location, const Instruction*&, const char* op)
607 {
608 out.printf("[%4d] %-17s ", location, op);
609 }
610
611 void CodeBlock::printLocationOpAndRegisterOperand(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, int operand)
612 {
613 printLocationAndOp(out, exec, location, it, op);
614 out.printf("%s", registerName(operand).data());
615 }
616
617 void CodeBlock::dumpBytecode(
618 PrintStream& out, ExecState* exec, const Instruction* begin, const Instruction*& it,
619 const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
620 {
621 int location = it - begin;
622 bool hasPrintedProfiling = false;
623 OpcodeID opcode = exec->interpreter()->getOpcodeID(it->u.opcode);
624 switch (opcode) {
625 case op_enter: {
626 printLocationAndOp(out, exec, location, it, "enter");
627 break;
628 }
629 case op_touch_entry: {
630 printLocationAndOp(out, exec, location, it, "touch_entry");
631 break;
632 }
633 case op_create_activation: {
634 int r0 = (++it)->u.operand;
635 printLocationOpAndRegisterOperand(out, exec, location, it, "create_activation", r0);
636 break;
637 }
638 case op_create_arguments: {
639 int r0 = (++it)->u.operand;
640 printLocationOpAndRegisterOperand(out, exec, location, it, "create_arguments", r0);
641 break;
642 }
643 case op_init_lazy_reg: {
644 int r0 = (++it)->u.operand;
645 printLocationOpAndRegisterOperand(out, exec, location, it, "init_lazy_reg", r0);
646 break;
647 }
648 case op_get_callee: {
649 int r0 = (++it)->u.operand;
650 printLocationOpAndRegisterOperand(out, exec, location, it, "get_callee", r0);
651 ++it;
652 break;
653 }
654 case op_create_this: {
655 int r0 = (++it)->u.operand;
656 int r1 = (++it)->u.operand;
657 unsigned inferredInlineCapacity = (++it)->u.operand;
658 printLocationAndOp(out, exec, location, it, "create_this");
659 out.printf("%s, %s, %u", registerName(r0).data(), registerName(r1).data(), inferredInlineCapacity);
660 break;
661 }
662 case op_to_this: {
663 int r0 = (++it)->u.operand;
664 printLocationOpAndRegisterOperand(out, exec, location, it, "to_this", r0);
665 Structure* structure = (++it)->u.structure.get();
666 if (structure)
667 out.print(" cache(struct = ", RawPointer(structure), ")");
668 break;
669 }
670 case op_new_object: {
671 int r0 = (++it)->u.operand;
672 unsigned inferredInlineCapacity = (++it)->u.operand;
673 printLocationAndOp(out, exec, location, it, "new_object");
674 out.printf("%s, %u", registerName(r0).data(), inferredInlineCapacity);
675 ++it; // Skip object allocation profile.
676 break;
677 }
678 case op_new_array: {
679 int dst = (++it)->u.operand;
680 int argv = (++it)->u.operand;
681 int argc = (++it)->u.operand;
682 printLocationAndOp(out, exec, location, it, "new_array");
683 out.printf("%s, %s, %d", registerName(dst).data(), registerName(argv).data(), argc);
684 ++it; // Skip array allocation profile.
685 break;
686 }
687 case op_new_array_with_size: {
688 int dst = (++it)->u.operand;
689 int length = (++it)->u.operand;
690 printLocationAndOp(out, exec, location, it, "new_array_with_size");
691 out.printf("%s, %s", registerName(dst).data(), registerName(length).data());
692 ++it; // Skip array allocation profile.
693 break;
694 }
695 case op_new_array_buffer: {
696 int dst = (++it)->u.operand;
697 int argv = (++it)->u.operand;
698 int argc = (++it)->u.operand;
699 printLocationAndOp(out, exec, location, it, "new_array_buffer");
700 out.printf("%s, %d, %d", registerName(dst).data(), argv, argc);
701 ++it; // Skip array allocation profile.
702 break;
703 }
704 case op_new_regexp: {
705 int r0 = (++it)->u.operand;
706 int re0 = (++it)->u.operand;
707 printLocationAndOp(out, exec, location, it, "new_regexp");
708 out.printf("%s, ", registerName(r0).data());
709 if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps())
710 out.printf("%s", regexpName(re0, regexp(re0)).data());
711 else
712 out.printf("bad_regexp(%d)", re0);
713 break;
714 }
715 case op_mov: {
716 int r0 = (++it)->u.operand;
717 int r1 = (++it)->u.operand;
718 printLocationAndOp(out, exec, location, it, "mov");
719 out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
720 break;
721 }
722 case op_captured_mov: {
723 int r0 = (++it)->u.operand;
724 int r1 = (++it)->u.operand;
725 printLocationAndOp(out, exec, location, it, "captured_mov");
726 out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
727 ++it;
728 break;
729 }
730 case op_not: {
731 printUnaryOp(out, exec, location, it, "not");
732 break;
733 }
734 case op_eq: {
735 printBinaryOp(out, exec, location, it, "eq");
736 break;
737 }
738 case op_eq_null: {
739 printUnaryOp(out, exec, location, it, "eq_null");
740 break;
741 }
742 case op_neq: {
743 printBinaryOp(out, exec, location, it, "neq");
744 break;
745 }
746 case op_neq_null: {
747 printUnaryOp(out, exec, location, it, "neq_null");
748 break;
749 }
750 case op_stricteq: {
751 printBinaryOp(out, exec, location, it, "stricteq");
752 break;
753 }
754 case op_nstricteq: {
755 printBinaryOp(out, exec, location, it, "nstricteq");
756 break;
757 }
758 case op_less: {
759 printBinaryOp(out, exec, location, it, "less");
760 break;
761 }
762 case op_lesseq: {
763 printBinaryOp(out, exec, location, it, "lesseq");
764 break;
765 }
766 case op_greater: {
767 printBinaryOp(out, exec, location, it, "greater");
768 break;
769 }
770 case op_greatereq: {
771 printBinaryOp(out, exec, location, it, "greatereq");
772 break;
773 }
774 case op_inc: {
775 int r0 = (++it)->u.operand;
776 printLocationOpAndRegisterOperand(out, exec, location, it, "inc", r0);
777 break;
778 }
779 case op_dec: {
780 int r0 = (++it)->u.operand;
781 printLocationOpAndRegisterOperand(out, exec, location, it, "dec", r0);
782 break;
783 }
784 case op_to_number: {
785 printUnaryOp(out, exec, location, it, "to_number");
786 break;
787 }
788 case op_negate: {
789 printUnaryOp(out, exec, location, it, "negate");
790 break;
791 }
792 case op_add: {
793 printBinaryOp(out, exec, location, it, "add");
794 ++it;
795 break;
796 }
797 case op_mul: {
798 printBinaryOp(out, exec, location, it, "mul");
799 ++it;
800 break;
801 }
802 case op_div: {
803 printBinaryOp(out, exec, location, it, "div");
804 ++it;
805 break;
806 }
807 case op_mod: {
808 printBinaryOp(out, exec, location, it, "mod");
809 break;
810 }
811 case op_sub: {
812 printBinaryOp(out, exec, location, it, "sub");
813 ++it;
814 break;
815 }
816 case op_lshift: {
817 printBinaryOp(out, exec, location, it, "lshift");
818 break;
819 }
820 case op_rshift: {
821 printBinaryOp(out, exec, location, it, "rshift");
822 break;
823 }
824 case op_urshift: {
825 printBinaryOp(out, exec, location, it, "urshift");
826 break;
827 }
828 case op_bitand: {
829 printBinaryOp(out, exec, location, it, "bitand");
830 ++it;
831 break;
832 }
833 case op_bitxor: {
834 printBinaryOp(out, exec, location, it, "bitxor");
835 ++it;
836 break;
837 }
838 case op_bitor: {
839 printBinaryOp(out, exec, location, it, "bitor");
840 ++it;
841 break;
842 }
843 case op_check_has_instance: {
844 int r0 = (++it)->u.operand;
845 int r1 = (++it)->u.operand;
846 int r2 = (++it)->u.operand;
847 int offset = (++it)->u.operand;
848 printLocationAndOp(out, exec, location, it, "check_has_instance");
849 out.printf("%s, %s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), offset, location + offset);
850 break;
851 }
852 case op_instanceof: {
853 int r0 = (++it)->u.operand;
854 int r1 = (++it)->u.operand;
855 int r2 = (++it)->u.operand;
856 printLocationAndOp(out, exec, location, it, "instanceof");
857 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
858 break;
859 }
860 case op_unsigned: {
861 printUnaryOp(out, exec, location, it, "unsigned");
862 break;
863 }
864 case op_typeof: {
865 printUnaryOp(out, exec, location, it, "typeof");
866 break;
867 }
868 case op_is_undefined: {
869 printUnaryOp(out, exec, location, it, "is_undefined");
870 break;
871 }
872 case op_is_boolean: {
873 printUnaryOp(out, exec, location, it, "is_boolean");
874 break;
875 }
876 case op_is_number: {
877 printUnaryOp(out, exec, location, it, "is_number");
878 break;
879 }
880 case op_is_string: {
881 printUnaryOp(out, exec, location, it, "is_string");
882 break;
883 }
884 case op_is_object: {
885 printUnaryOp(out, exec, location, it, "is_object");
886 break;
887 }
888 case op_is_function: {
889 printUnaryOp(out, exec, location, it, "is_function");
890 break;
891 }
892 case op_in: {
893 printBinaryOp(out, exec, location, it, "in");
894 break;
895 }
896 case op_init_global_const_nop: {
897 printLocationAndOp(out, exec, location, it, "init_global_const_nop");
898 it++;
899 it++;
900 it++;
901 it++;
902 break;
903 }
904 case op_init_global_const: {
905 WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer;
906 int r0 = (++it)->u.operand;
907 printLocationAndOp(out, exec, location, it, "init_global_const");
908 out.printf("g%d(%p), %s", m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(r0).data());
909 it++;
910 it++;
911 break;
912 }
913 case op_get_by_id:
914 case op_get_by_id_out_of_line:
915 case op_get_array_length: {
916 printGetByIdOp(out, exec, location, it);
917 printGetByIdCacheStatus(out, exec, location, stubInfos);
918 dumpValueProfiling(out, it, hasPrintedProfiling);
919 break;
920 }
921 case op_get_arguments_length: {
922 printUnaryOp(out, exec, location, it, "get_arguments_length");
923 it++;
924 break;
925 }
926 case op_put_by_id: {
927 printPutByIdOp(out, exec, location, it, "put_by_id");
928 break;
929 }
930 case op_put_by_id_out_of_line: {
931 printPutByIdOp(out, exec, location, it, "put_by_id_out_of_line");
932 break;
933 }
934 case op_put_by_id_transition_direct: {
935 printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct");
936 break;
937 }
938 case op_put_by_id_transition_direct_out_of_line: {
939 printPutByIdOp(out, exec, location, it, "put_by_id_transition_direct_out_of_line");
940 break;
941 }
942 case op_put_by_id_transition_normal: {
943 printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal");
944 break;
945 }
946 case op_put_by_id_transition_normal_out_of_line: {
947 printPutByIdOp(out, exec, location, it, "put_by_id_transition_normal_out_of_line");
948 break;
949 }
950 case op_put_getter_setter: {
951 int r0 = (++it)->u.operand;
952 int id0 = (++it)->u.operand;
953 int r1 = (++it)->u.operand;
954 int r2 = (++it)->u.operand;
955 printLocationAndOp(out, exec, location, it, "put_getter_setter");
956 out.printf("%s, %s, %s, %s", registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(), registerName(r2).data());
957 break;
958 }
959 case op_del_by_id: {
960 int r0 = (++it)->u.operand;
961 int r1 = (++it)->u.operand;
962 int id0 = (++it)->u.operand;
963 printLocationAndOp(out, exec, location, it, "del_by_id");
964 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data());
965 break;
966 }
967 case op_get_by_val: {
968 int r0 = (++it)->u.operand;
969 int r1 = (++it)->u.operand;
970 int r2 = (++it)->u.operand;
971 printLocationAndOp(out, exec, location, it, "get_by_val");
972 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
973 dumpArrayProfiling(out, it, hasPrintedProfiling);
974 dumpValueProfiling(out, it, hasPrintedProfiling);
975 break;
976 }
977 case op_get_argument_by_val: {
978 int r0 = (++it)->u.operand;
979 int r1 = (++it)->u.operand;
980 int r2 = (++it)->u.operand;
981 printLocationAndOp(out, exec, location, it, "get_argument_by_val");
982 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
983 ++it;
984 dumpValueProfiling(out, it, hasPrintedProfiling);
985 break;
986 }
987 case op_get_by_pname: {
988 int r0 = (++it)->u.operand;
989 int r1 = (++it)->u.operand;
990 int r2 = (++it)->u.operand;
991 int r3 = (++it)->u.operand;
992 int r4 = (++it)->u.operand;
993 int r5 = (++it)->u.operand;
994 printLocationAndOp(out, exec, location, it, "get_by_pname");
995 out.printf("%s, %s, %s, %s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), registerName(r4).data(), registerName(r5).data());
996 break;
997 }
998 case op_put_by_val: {
999 int r0 = (++it)->u.operand;
1000 int r1 = (++it)->u.operand;
1001 int r2 = (++it)->u.operand;
1002 printLocationAndOp(out, exec, location, it, "put_by_val");
1003 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
1004 dumpArrayProfiling(out, it, hasPrintedProfiling);
1005 break;
1006 }
1007 case op_put_by_val_direct: {
1008 int r0 = (++it)->u.operand;
1009 int r1 = (++it)->u.operand;
1010 int r2 = (++it)->u.operand;
1011 printLocationAndOp(out, exec, location, it, "put_by_val_direct");
1012 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
1013 dumpArrayProfiling(out, it, hasPrintedProfiling);
1014 break;
1015 }
1016 case op_del_by_val: {
1017 int r0 = (++it)->u.operand;
1018 int r1 = (++it)->u.operand;
1019 int r2 = (++it)->u.operand;
1020 printLocationAndOp(out, exec, location, it, "del_by_val");
1021 out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), registerName(r2).data());
1022 break;
1023 }
1024 case op_put_by_index: {
1025 int r0 = (++it)->u.operand;
1026 unsigned n0 = (++it)->u.operand;
1027 int r1 = (++it)->u.operand;
1028 printLocationAndOp(out, exec, location, it, "put_by_index");
1029 out.printf("%s, %u, %s", registerName(r0).data(), n0, registerName(r1).data());
1030 break;
1031 }
1032 case op_jmp: {
1033 int offset = (++it)->u.operand;
1034 printLocationAndOp(out, exec, location, it, "jmp");
1035 out.printf("%d(->%d)", offset, location + offset);
1036 break;
1037 }
1038 case op_jtrue: {
1039 printConditionalJump(out, exec, begin, it, location, "jtrue");
1040 break;
1041 }
1042 case op_jfalse: {
1043 printConditionalJump(out, exec, begin, it, location, "jfalse");
1044 break;
1045 }
1046 case op_jeq_null: {
1047 printConditionalJump(out, exec, begin, it, location, "jeq_null");
1048 break;
1049 }
1050 case op_jneq_null: {
1051 printConditionalJump(out, exec, begin, it, location, "jneq_null");
1052 break;
1053 }
1054 case op_jneq_ptr: {
1055 int r0 = (++it)->u.operand;
1056 Special::Pointer pointer = (++it)->u.specialPointer;
1057 int offset = (++it)->u.operand;
1058 printLocationAndOp(out, exec, location, it, "jneq_ptr");
1059 out.printf("%s, %d (%p), %d(->%d)", registerName(r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset);
1060 break;
1061 }
1062 case op_jless: {
1063 int r0 = (++it)->u.operand;
1064 int r1 = (++it)->u.operand;
1065 int offset = (++it)->u.operand;
1066 printLocationAndOp(out, exec, location, it, "jless");
1067 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1068 break;
1069 }
1070 case op_jlesseq: {
1071 int r0 = (++it)->u.operand;
1072 int r1 = (++it)->u.operand;
1073 int offset = (++it)->u.operand;
1074 printLocationAndOp(out, exec, location, it, "jlesseq");
1075 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1076 break;
1077 }
1078 case op_jgreater: {
1079 int r0 = (++it)->u.operand;
1080 int r1 = (++it)->u.operand;
1081 int offset = (++it)->u.operand;
1082 printLocationAndOp(out, exec, location, it, "jgreater");
1083 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1084 break;
1085 }
1086 case op_jgreatereq: {
1087 int r0 = (++it)->u.operand;
1088 int r1 = (++it)->u.operand;
1089 int offset = (++it)->u.operand;
1090 printLocationAndOp(out, exec, location, it, "jgreatereq");
1091 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1092 break;
1093 }
1094 case op_jnless: {
1095 int r0 = (++it)->u.operand;
1096 int r1 = (++it)->u.operand;
1097 int offset = (++it)->u.operand;
1098 printLocationAndOp(out, exec, location, it, "jnless");
1099 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1100 break;
1101 }
1102 case op_jnlesseq: {
1103 int r0 = (++it)->u.operand;
1104 int r1 = (++it)->u.operand;
1105 int offset = (++it)->u.operand;
1106 printLocationAndOp(out, exec, location, it, "jnlesseq");
1107 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1108 break;
1109 }
1110 case op_jngreater: {
1111 int r0 = (++it)->u.operand;
1112 int r1 = (++it)->u.operand;
1113 int offset = (++it)->u.operand;
1114 printLocationAndOp(out, exec, location, it, "jngreater");
1115 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1116 break;
1117 }
1118 case op_jngreatereq: {
1119 int r0 = (++it)->u.operand;
1120 int r1 = (++it)->u.operand;
1121 int offset = (++it)->u.operand;
1122 printLocationAndOp(out, exec, location, it, "jngreatereq");
1123 out.printf("%s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), offset, location + offset);
1124 break;
1125 }
1126 case op_loop_hint: {
1127 printLocationAndOp(out, exec, location, it, "loop_hint");
1128 break;
1129 }
1130 case op_switch_imm: {
1131 int tableIndex = (++it)->u.operand;
1132 int defaultTarget = (++it)->u.operand;
1133 int scrutineeRegister = (++it)->u.operand;
1134 printLocationAndOp(out, exec, location, it, "switch_imm");
1135 out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
1136 break;
1137 }
1138 case op_switch_char: {
1139 int tableIndex = (++it)->u.operand;
1140 int defaultTarget = (++it)->u.operand;
1141 int scrutineeRegister = (++it)->u.operand;
1142 printLocationAndOp(out, exec, location, it, "switch_char");
1143 out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
1144 break;
1145 }
1146 case op_switch_string: {
1147 int tableIndex = (++it)->u.operand;
1148 int defaultTarget = (++it)->u.operand;
1149 int scrutineeRegister = (++it)->u.operand;
1150 printLocationAndOp(out, exec, location, it, "switch_string");
1151 out.printf("%d, %d(->%d), %s", tableIndex, defaultTarget, location + defaultTarget, registerName(scrutineeRegister).data());
1152 break;
1153 }
1154 case op_new_func: {
1155 int r0 = (++it)->u.operand;
1156 int f0 = (++it)->u.operand;
1157 int shouldCheck = (++it)->u.operand;
1158 printLocationAndOp(out, exec, location, it, "new_func");
1159 out.printf("%s, f%d, %s", registerName(r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
1160 break;
1161 }
1162 case op_new_captured_func: {
1163 int r0 = (++it)->u.operand;
1164 int f0 = (++it)->u.operand;
1165 printLocationAndOp(out, exec, location, it, "new_captured_func");
1166 out.printf("%s, f%d", registerName(r0).data(), f0);
1167 ++it;
1168 break;
1169 }
1170 case op_new_func_exp: {
1171 int r0 = (++it)->u.operand;
1172 int f0 = (++it)->u.operand;
1173 printLocationAndOp(out, exec, location, it, "new_func_exp");
1174 out.printf("%s, f%d", registerName(r0).data(), f0);
1175 break;
1176 }
1177 case op_call: {
1178 printCallOp(out, exec, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos);
1179 break;
1180 }
1181 case op_call_eval: {
1182 printCallOp(out, exec, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling, callLinkInfos);
1183 break;
1184 }
1185
1186 case op_construct_varargs:
1187 case op_call_varargs: {
1188 int result = (++it)->u.operand;
1189 int callee = (++it)->u.operand;
1190 int thisValue = (++it)->u.operand;
1191 int arguments = (++it)->u.operand;
1192 int firstFreeRegister = (++it)->u.operand;
1193 int varArgOffset = (++it)->u.operand;
1194 ++it;
1195 printLocationAndOp(out, exec, location, it, opcode == op_call_varargs ? "call_varargs" : "construct_varargs");
1196 out.printf("%s, %s, %s, %s, %d, %d", registerName(result).data(), registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister, varArgOffset);
1197 dumpValueProfiling(out, it, hasPrintedProfiling);
1198 break;
1199 }
1200
1201 case op_tear_off_activation: {
1202 int r0 = (++it)->u.operand;
1203 printLocationOpAndRegisterOperand(out, exec, location, it, "tear_off_activation", r0);
1204 break;
1205 }
1206 case op_tear_off_arguments: {
1207 int r0 = (++it)->u.operand;
1208 int r1 = (++it)->u.operand;
1209 printLocationAndOp(out, exec, location, it, "tear_off_arguments");
1210 out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
1211 break;
1212 }
1213 case op_ret: {
1214 int r0 = (++it)->u.operand;
1215 printLocationOpAndRegisterOperand(out, exec, location, it, "ret", r0);
1216 break;
1217 }
1218 case op_ret_object_or_this: {
1219 int r0 = (++it)->u.operand;
1220 int r1 = (++it)->u.operand;
1221 printLocationAndOp(out, exec, location, it, "constructor_ret");
1222 out.printf("%s %s", registerName(r0).data(), registerName(r1).data());
1223 break;
1224 }
1225 case op_construct: {
1226 printCallOp(out, exec, location, it, "construct", DumpCaches, hasPrintedProfiling, callLinkInfos);
1227 break;
1228 }
1229 case op_strcat: {
1230 int r0 = (++it)->u.operand;
1231 int r1 = (++it)->u.operand;
1232 int count = (++it)->u.operand;
1233 printLocationAndOp(out, exec, location, it, "strcat");
1234 out.printf("%s, %s, %d", registerName(r0).data(), registerName(r1).data(), count);
1235 break;
1236 }
1237 case op_to_primitive: {
1238 int r0 = (++it)->u.operand;
1239 int r1 = (++it)->u.operand;
1240 printLocationAndOp(out, exec, location, it, "to_primitive");
1241 out.printf("%s, %s", registerName(r0).data(), registerName(r1).data());
1242 break;
1243 }
1244 case op_get_pnames: {
1245 int r0 = it[1].u.operand;
1246 int r1 = it[2].u.operand;
1247 int r2 = it[3].u.operand;
1248 int r3 = it[4].u.operand;
1249 int offset = it[5].u.operand;
1250 printLocationAndOp(out, exec, location, it, "get_pnames");
1251 out.printf("%s, %s, %s, %s, %d(->%d)", registerName(r0).data(), registerName(r1).data(), registerName(r2).data(), registerName(r3).data(), offset, location + offset);
1252 it += OPCODE_LENGTH(op_get_pnames) - 1;
1253 break;
1254 }
1255 case op_next_pname: {
1256 int dest = it[1].u.operand;
1257 int base = it[2].u.operand;
1258 int i = it[3].u.operand;
1259 int size = it[4].u.operand;
1260 int iter = it[5].u.operand;
1261 int offset = it[6].u.operand;
1262 printLocationAndOp(out, exec, location, it, "next_pname");
1263 out.printf("%s, %s, %s, %s, %s, %d(->%d)", registerName(dest).data(), registerName(base).data(), registerName(i).data(), registerName(size).data(), registerName(iter).data(), offset, location + offset);
1264 it += OPCODE_LENGTH(op_next_pname) - 1;
1265 break;
1266 }
1267 case op_push_with_scope: {
1268 int r0 = (++it)->u.operand;
1269 printLocationOpAndRegisterOperand(out, exec, location, it, "push_with_scope", r0);
1270 break;
1271 }
1272 case op_pop_scope: {
1273 printLocationAndOp(out, exec, location, it, "pop_scope");
1274 break;
1275 }
1276 case op_push_name_scope: {
1277 int id0 = (++it)->u.operand;
1278 int r1 = (++it)->u.operand;
1279 unsigned attributes = (++it)->u.operand;
1280 printLocationAndOp(out, exec, location, it, "push_name_scope");
1281 out.printf("%s, %s, %u", idName(id0, identifier(id0)).data(), registerName(r1).data(), attributes);
1282 break;
1283 }
1284 case op_catch: {
1285 int r0 = (++it)->u.operand;
1286 printLocationOpAndRegisterOperand(out, exec, location, it, "catch", r0);
1287 break;
1288 }
1289 case op_throw: {
1290 int r0 = (++it)->u.operand;
1291 printLocationOpAndRegisterOperand(out, exec, location, it, "throw", r0);
1292 break;
1293 }
1294 case op_throw_static_error: {
1295 int k0 = (++it)->u.operand;
1296 int k1 = (++it)->u.operand;
1297 printLocationAndOp(out, exec, location, it, "throw_static_error");
1298 out.printf("%s, %s", constantName(k0, getConstant(k0)).data(), k1 ? "true" : "false");
1299 break;
1300 }
1301 case op_debug: {
1302 int debugHookID = (++it)->u.operand;
1303 int hasBreakpointFlag = (++it)->u.operand;
1304 printLocationAndOp(out, exec, location, it, "debug");
1305 out.printf("%s %d", debugHookName(debugHookID), hasBreakpointFlag);
1306 break;
1307 }
1308 case op_profile_will_call: {
1309 int function = (++it)->u.operand;
1310 printLocationOpAndRegisterOperand(out, exec, location, it, "profile_will_call", function);
1311 break;
1312 }
1313 case op_profile_did_call: {
1314 int function = (++it)->u.operand;
1315 printLocationOpAndRegisterOperand(out, exec, location, it, "profile_did_call", function);
1316 break;
1317 }
1318 case op_end: {
1319 int r0 = (++it)->u.operand;
1320 printLocationOpAndRegisterOperand(out, exec, location, it, "end", r0);
1321 break;
1322 }
1323 case op_resolve_scope: {
1324 int r0 = (++it)->u.operand;
1325 int id0 = (++it)->u.operand;
1326 ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
1327 int depth = (++it)->u.operand;
1328 printLocationAndOp(out, exec, location, it, "resolve_scope");
1329 out.printf("%s, %s, %u<%s|%s>, %d", registerName(r0).data(), idName(id0, identifier(id0)).data(),
1330 modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
1331 depth);
1332 ++it;
1333 break;
1334 }
1335 case op_get_from_scope: {
1336 int r0 = (++it)->u.operand;
1337 int r1 = (++it)->u.operand;
1338 int id0 = (++it)->u.operand;
1339 ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
1340 ++it; // Structure
1341 int operand = (++it)->u.operand; // Operand
1342 ++it; // Skip value profile.
1343 printLocationAndOp(out, exec, location, it, "get_from_scope");
1344 out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
1345 registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data(),
1346 modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
1347 operand);
1348 break;
1349 }
1350 case op_put_to_scope: {
1351 int r0 = (++it)->u.operand;
1352 int id0 = (++it)->u.operand;
1353 int r1 = (++it)->u.operand;
1354 ResolveModeAndType modeAndType = ResolveModeAndType((++it)->u.operand);
1355 ++it; // Structure
1356 int operand = (++it)->u.operand; // Operand
1357 printLocationAndOp(out, exec, location, it, "put_to_scope");
1358 out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
1359 registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(),
1360 modeAndType.operand(), resolveModeName(modeAndType.mode()), resolveTypeName(modeAndType.type()),
1361 operand);
1362 break;
1363 }
1364 default:
1365 RELEASE_ASSERT_NOT_REACHED();
1366 }
1367
1368 dumpRareCaseProfile(out, "rare case: ", rareCaseProfileForBytecodeOffset(location), hasPrintedProfiling);
1369 dumpRareCaseProfile(out, "special fast case: ", specialFastCaseProfileForBytecodeOffset(location), hasPrintedProfiling);
1370
1371 #if ENABLE(DFG_JIT)
1372 Vector<DFG::FrequentExitSite> exitSites = exitProfile().exitSitesFor(location);
1373 if (!exitSites.isEmpty()) {
1374 out.print(" !! frequent exits: ");
1375 CommaPrinter comma;
1376 for (unsigned i = 0; i < exitSites.size(); ++i)
1377 out.print(comma, exitSites[i].kind(), " ", exitSites[i].jitType());
1378 }
1379 #else // ENABLE(DFG_JIT)
1380 UNUSED_PARAM(location);
1381 #endif // ENABLE(DFG_JIT)
1382 out.print("\n");
1383 }
1384
1385 void CodeBlock::dumpBytecode(
1386 PrintStream& out, unsigned bytecodeOffset,
1387 const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos)
1388 {
1389 ExecState* exec = m_globalObject->globalExec();
1390 const Instruction* it = instructions().begin() + bytecodeOffset;
1391 dumpBytecode(out, exec, instructions().begin(), it, stubInfos, callLinkInfos);
1392 }
1393
1394 #define FOR_EACH_MEMBER_VECTOR(macro) \
1395 macro(instructions) \
1396 macro(callLinkInfos) \
1397 macro(linkedCallerList) \
1398 macro(identifiers) \
1399 macro(functionExpressions) \
1400 macro(constantRegisters)
1401
1402 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1403 macro(regexps) \
1404 macro(functions) \
1405 macro(exceptionHandlers) \
1406 macro(switchJumpTables) \
1407 macro(stringSwitchJumpTables) \
1408 macro(evalCodeCache) \
1409 macro(expressionInfo) \
1410 macro(lineInfo) \
1411 macro(callReturnIndexVector)
1412
1413 template<typename T>
1414 static size_t sizeInBytes(const Vector<T>& vector)
1415 {
1416 return vector.capacity() * sizeof(T);
1417 }
1418
1419 CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
1420 : m_globalObject(other.m_globalObject)
1421 , m_heap(other.m_heap)
1422 , m_numCalleeRegisters(other.m_numCalleeRegisters)
1423 , m_numVars(other.m_numVars)
1424 , m_isConstructor(other.m_isConstructor)
1425 , m_shouldAlwaysBeInlined(true)
1426 , m_didFailFTLCompilation(false)
1427 , m_hasBeenCompiledWithFTL(false)
1428 , m_unlinkedCode(*other.m_vm, other.m_ownerExecutable.get(), other.m_unlinkedCode.get())
1429 , m_hasDebuggerStatement(false)
1430 , m_steppingMode(SteppingModeDisabled)
1431 , m_numBreakpoints(0)
1432 , m_ownerExecutable(*other.m_vm, other.m_ownerExecutable.get(), other.m_ownerExecutable.get())
1433 , m_vm(other.m_vm)
1434 , m_instructions(other.m_instructions)
1435 , m_thisRegister(other.m_thisRegister)
1436 , m_argumentsRegister(other.m_argumentsRegister)
1437 , m_activationRegister(other.m_activationRegister)
1438 , m_isStrictMode(other.m_isStrictMode)
1439 , m_needsActivation(other.m_needsActivation)
1440 , m_mayBeExecuting(false)
1441 , m_visitAggregateHasBeenCalled(false)
1442 , m_source(other.m_source)
1443 , m_sourceOffset(other.m_sourceOffset)
1444 , m_firstLineColumnOffset(other.m_firstLineColumnOffset)
1445 , m_codeType(other.m_codeType)
1446 , m_constantRegisters(other.m_constantRegisters)
1447 , m_functionDecls(other.m_functionDecls)
1448 , m_functionExprs(other.m_functionExprs)
1449 , m_osrExitCounter(0)
1450 , m_optimizationDelayCounter(0)
1451 , m_reoptimizationRetryCounter(0)
1452 , m_hash(other.m_hash)
1453 #if ENABLE(JIT)
1454 , m_capabilityLevelState(DFG::CapabilityLevelNotSet)
1455 #endif
1456 {
1457 ASSERT(m_heap->isDeferred());
1458
1459 if (SymbolTable* symbolTable = other.symbolTable())
1460 m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable);
1461
1462 setNumParameters(other.numParameters());
1463 optimizeAfterWarmUp();
1464 jitAfterWarmUp();
1465
1466 if (other.m_rareData) {
1467 createRareDataIfNecessary();
1468
1469 m_rareData->m_exceptionHandlers = other.m_rareData->m_exceptionHandlers;
1470 m_rareData->m_constantBuffers = other.m_rareData->m_constantBuffers;
1471 m_rareData->m_switchJumpTables = other.m_rareData->m_switchJumpTables;
1472 m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
1473 }
1474
1475 m_heap->m_codeBlocks.add(this);
1476 m_heap->reportExtraMemoryCost(sizeof(CodeBlock));
1477 }
1478
1479 CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset)
1480 : m_globalObject(scope->globalObject()->vm(), ownerExecutable, scope->globalObject())
1481 , m_heap(&m_globalObject->vm().heap)
1482 , m_numCalleeRegisters(unlinkedCodeBlock->m_numCalleeRegisters)
1483 , m_numVars(unlinkedCodeBlock->m_numVars)
1484 , m_isConstructor(unlinkedCodeBlock->isConstructor())
1485 , m_shouldAlwaysBeInlined(true)
1486 , m_didFailFTLCompilation(false)
1487 , m_hasBeenCompiledWithFTL(false)
1488 , m_unlinkedCode(m_globalObject->vm(), ownerExecutable, unlinkedCodeBlock)
1489 , m_hasDebuggerStatement(false)
1490 , m_steppingMode(SteppingModeDisabled)
1491 , m_numBreakpoints(0)
1492 , m_ownerExecutable(m_globalObject->vm(), ownerExecutable, ownerExecutable)
1493 , m_vm(unlinkedCodeBlock->vm())
1494 , m_thisRegister(unlinkedCodeBlock->thisRegister())
1495 , m_argumentsRegister(unlinkedCodeBlock->argumentsRegister())
1496 , m_activationRegister(unlinkedCodeBlock->activationRegister())
1497 , m_isStrictMode(unlinkedCodeBlock->isStrictMode())
1498 , m_needsActivation(unlinkedCodeBlock->hasActivationRegister() && unlinkedCodeBlock->codeType() == FunctionCode)
1499 , m_mayBeExecuting(false)
1500 , m_visitAggregateHasBeenCalled(false)
1501 , m_source(sourceProvider)
1502 , m_sourceOffset(sourceOffset)
1503 , m_firstLineColumnOffset(firstLineColumnOffset)
1504 , m_codeType(unlinkedCodeBlock->codeType())
1505 , m_osrExitCounter(0)
1506 , m_optimizationDelayCounter(0)
1507 , m_reoptimizationRetryCounter(0)
1508 #if ENABLE(JIT)
1509 , m_capabilityLevelState(DFG::CapabilityLevelNotSet)
1510 #endif
1511 {
1512 ASSERT(m_heap->isDeferred());
1513
1514 bool didCloneSymbolTable = false;
1515
1516 if (SymbolTable* symbolTable = unlinkedCodeBlock->symbolTable()) {
1517 if (codeType() == FunctionCode && symbolTable->captureCount()) {
1518 m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable->cloneCapturedNames(*m_vm));
1519 didCloneSymbolTable = true;
1520 } else
1521 m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable);
1522 }
1523
1524 ASSERT(m_source);
1525 setNumParameters(unlinkedCodeBlock->numParameters());
1526
1527 setConstantRegisters(unlinkedCodeBlock->constantRegisters());
1528 if (unlinkedCodeBlock->usesGlobalObject())
1529 m_constantRegisters[unlinkedCodeBlock->globalObjectRegister().toConstantIndex()].set(*m_vm, ownerExecutable, m_globalObject.get());
1530 m_functionDecls.resizeToFit(unlinkedCodeBlock->numberOfFunctionDecls());
1531 for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) {
1532 UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i);
1533 unsigned lineCount = unlinkedExecutable->lineCount();
1534 unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset();
1535 bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset();
1536 unsigned startColumn = unlinkedExecutable->unlinkedBodyStartColumn() + (startColumnIsOnOwnerStartLine ? ownerExecutable->startColumn() : 1);
1537 bool endColumnIsOnStartLine = !lineCount;
1538 unsigned endColumn = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? startColumn : 1);
1539 unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset();
1540 unsigned sourceLength = unlinkedExecutable->sourceLength();
1541 SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine, startColumn);
1542 FunctionExecutable* executable = FunctionExecutable::create(*m_vm, code, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumn);
1543 m_functionDecls[i].set(*m_vm, ownerExecutable, executable);
1544 }
1545
1546 m_functionExprs.resizeToFit(unlinkedCodeBlock->numberOfFunctionExprs());
1547 for (size_t count = unlinkedCodeBlock->numberOfFunctionExprs(), i = 0; i < count; ++i) {
1548 UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionExpr(i);
1549 unsigned lineCount = unlinkedExecutable->lineCount();
1550 unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset();
1551 bool startColumnIsOnOwnerStartLine = !unlinkedExecutable->firstLineOffset();
1552 unsigned startColumn = unlinkedExecutable->unlinkedBodyStartColumn() + (startColumnIsOnOwnerStartLine ? ownerExecutable->startColumn() : 1);
1553 bool endColumnIsOnStartLine = !lineCount;
1554 unsigned endColumn = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? startColumn : 1);
1555 unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset();
1556 unsigned sourceLength = unlinkedExecutable->sourceLength();
1557 SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine, startColumn);
1558 FunctionExecutable* executable = FunctionExecutable::create(*m_vm, code, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumn);
1559 m_functionExprs[i].set(*m_vm, ownerExecutable, executable);
1560 }
1561
1562 if (unlinkedCodeBlock->hasRareData()) {
1563 createRareDataIfNecessary();
1564 if (size_t count = unlinkedCodeBlock->constantBufferCount()) {
1565 m_rareData->m_constantBuffers.grow(count);
1566 for (size_t i = 0; i < count; i++) {
1567 const UnlinkedCodeBlock::ConstantBuffer& buffer = unlinkedCodeBlock->constantBuffer(i);
1568 m_rareData->m_constantBuffers[i] = buffer;
1569 }
1570 }
1571 if (size_t count = unlinkedCodeBlock->numberOfExceptionHandlers()) {
1572 m_rareData->m_exceptionHandlers.resizeToFit(count);
1573 size_t nonLocalScopeDepth = scope->depth();
1574 for (size_t i = 0; i < count; i++) {
1575 const UnlinkedHandlerInfo& handler = unlinkedCodeBlock->exceptionHandler(i);
1576 m_rareData->m_exceptionHandlers[i].start = handler.start;
1577 m_rareData->m_exceptionHandlers[i].end = handler.end;
1578 m_rareData->m_exceptionHandlers[i].target = handler.target;
1579 m_rareData->m_exceptionHandlers[i].scopeDepth = nonLocalScopeDepth + handler.scopeDepth;
1580 #if ENABLE(JIT)
1581 m_rareData->m_exceptionHandlers[i].nativeCode = CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(op_catch)));
1582 #endif
1583 }
1584 }
1585
1586 if (size_t count = unlinkedCodeBlock->numberOfStringSwitchJumpTables()) {
1587 m_rareData->m_stringSwitchJumpTables.grow(count);
1588 for (size_t i = 0; i < count; i++) {
1589 UnlinkedStringJumpTable::StringOffsetTable::iterator ptr = unlinkedCodeBlock->stringSwitchJumpTable(i).offsetTable.begin();
1590 UnlinkedStringJumpTable::StringOffsetTable::iterator end = unlinkedCodeBlock->stringSwitchJumpTable(i).offsetTable.end();
1591 for (; ptr != end; ++ptr) {
1592 OffsetLocation offset;
1593 offset.branchOffset = ptr->value;
1594 m_rareData->m_stringSwitchJumpTables[i].offsetTable.add(ptr->key, offset);
1595 }
1596 }
1597 }
1598
1599 if (size_t count = unlinkedCodeBlock->numberOfSwitchJumpTables()) {
1600 m_rareData->m_switchJumpTables.grow(count);
1601 for (size_t i = 0; i < count; i++) {
1602 UnlinkedSimpleJumpTable& sourceTable = unlinkedCodeBlock->switchJumpTable(i);
1603 SimpleJumpTable& destTable = m_rareData->m_switchJumpTables[i];
1604 destTable.branchOffsets = sourceTable.branchOffsets;
1605 destTable.min = sourceTable.min;
1606 }
1607 }
1608 }
1609
1610 // Allocate metadata buffers for the bytecode
1611 if (size_t size = unlinkedCodeBlock->numberOfLLintCallLinkInfos())
1612 m_llintCallLinkInfos.resizeToFit(size);
1613 if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles())
1614 m_arrayProfiles.grow(size);
1615 if (size_t size = unlinkedCodeBlock->numberOfArrayAllocationProfiles())
1616 m_arrayAllocationProfiles.resizeToFit(size);
1617 if (size_t size = unlinkedCodeBlock->numberOfValueProfiles())
1618 m_valueProfiles.resizeToFit(size);
1619 if (size_t size = unlinkedCodeBlock->numberOfObjectAllocationProfiles())
1620 m_objectAllocationProfiles.resizeToFit(size);
1621
1622 // Copy and translate the UnlinkedInstructions
1623 unsigned instructionCount = unlinkedCodeBlock->instructions().count();
1624 UnlinkedInstructionStream::Reader instructionReader(unlinkedCodeBlock->instructions());
1625
1626 Vector<Instruction, 0, UnsafeVectorOverflow> instructions(instructionCount);
1627 for (unsigned i = 0; !instructionReader.atEnd(); ) {
1628 const UnlinkedInstruction* pc = instructionReader.next();
1629
1630 unsigned opLength = opcodeLength(pc[0].u.opcode);
1631
1632 instructions[i] = vm()->interpreter->getOpcode(pc[0].u.opcode);
1633 for (size_t j = 1; j < opLength; ++j) {
1634 if (sizeof(int32_t) != sizeof(intptr_t))
1635 instructions[i + j].u.pointer = 0;
1636 instructions[i + j].u.operand = pc[j].u.operand;
1637 }
1638 switch (pc[0].u.opcode) {
1639 case op_call_varargs:
1640 case op_construct_varargs:
1641 case op_get_by_val:
1642 case op_get_argument_by_val: {
1643 int arrayProfileIndex = pc[opLength - 2].u.operand;
1644 m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
1645
1646 instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex];
1647 FALLTHROUGH;
1648 }
1649 case op_get_by_id: {
1650 ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
1651 ASSERT(profile->m_bytecodeOffset == -1);
1652 profile->m_bytecodeOffset = i;
1653 instructions[i + opLength - 1] = profile;
1654 break;
1655 }
1656 case op_put_by_val: {
1657 int arrayProfileIndex = pc[opLength - 1].u.operand;
1658 m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
1659 instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
1660 break;
1661 }
1662 case op_put_by_val_direct: {
1663 int arrayProfileIndex = pc[opLength - 1].u.operand;
1664 m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
1665 instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex];
1666 break;
1667 }
1668
1669 case op_new_array:
1670 case op_new_array_buffer:
1671 case op_new_array_with_size: {
1672 int arrayAllocationProfileIndex = pc[opLength - 1].u.operand;
1673 instructions[i + opLength - 1] = &m_arrayAllocationProfiles[arrayAllocationProfileIndex];
1674 break;
1675 }
1676 case op_new_object: {
1677 int objectAllocationProfileIndex = pc[opLength - 1].u.operand;
1678 ObjectAllocationProfile* objectAllocationProfile = &m_objectAllocationProfiles[objectAllocationProfileIndex];
1679 int inferredInlineCapacity = pc[opLength - 2].u.operand;
1680
1681 instructions[i + opLength - 1] = objectAllocationProfile;
1682 objectAllocationProfile->initialize(*vm(),
1683 m_ownerExecutable.get(), m_globalObject->objectPrototype(), inferredInlineCapacity);
1684 break;
1685 }
1686
1687 case op_call:
1688 case op_call_eval: {
1689 ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
1690 ASSERT(profile->m_bytecodeOffset == -1);
1691 profile->m_bytecodeOffset = i;
1692 instructions[i + opLength - 1] = profile;
1693 int arrayProfileIndex = pc[opLength - 2].u.operand;
1694 m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i);
1695 instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex];
1696 instructions[i + 5] = &m_llintCallLinkInfos[pc[5].u.operand];
1697 break;
1698 }
1699 case op_construct: {
1700 instructions[i + 5] = &m_llintCallLinkInfos[pc[5].u.operand];
1701 ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
1702 ASSERT(profile->m_bytecodeOffset == -1);
1703 profile->m_bytecodeOffset = i;
1704 instructions[i + opLength - 1] = profile;
1705 break;
1706 }
1707 case op_get_by_id_out_of_line:
1708 case op_get_array_length:
1709 CRASH();
1710
1711 case op_init_global_const_nop: {
1712 ASSERT(codeType() == GlobalCode);
1713 Identifier ident = identifier(pc[4].u.operand);
1714 SymbolTableEntry entry = m_globalObject->symbolTable()->get(ident.impl());
1715 if (entry.isNull())
1716 break;
1717
1718 instructions[i + 0] = vm()->interpreter->getOpcode(op_init_global_const);
1719 instructions[i + 1] = &m_globalObject->registerAt(entry.getIndex());
1720 break;
1721 }
1722
1723 case op_resolve_scope: {
1724 const Identifier& ident = identifier(pc[2].u.operand);
1725 ResolveType type = static_cast<ResolveType>(pc[3].u.operand);
1726
1727 ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, type);
1728 instructions[i + 3].u.operand = op.type;
1729 instructions[i + 4].u.operand = op.depth;
1730 if (op.activation)
1731 instructions[i + 5].u.activation.set(*vm(), ownerExecutable, op.activation);
1732 break;
1733 }
1734
1735 case op_get_from_scope: {
1736 ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
1737 ASSERT(profile->m_bytecodeOffset == -1);
1738 profile->m_bytecodeOffset = i;
1739 instructions[i + opLength - 1] = profile;
1740
1741 // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
1742 const Identifier& ident = identifier(pc[3].u.operand);
1743 ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
1744 ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Get, modeAndType.type());
1745
1746 instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
1747 if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
1748 instructions[i + 5].u.watchpointSet = op.watchpointSet;
1749 else if (op.structure)
1750 instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
1751 instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
1752 break;
1753 }
1754
1755 case op_put_to_scope: {
1756 // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
1757 const Identifier& ident = identifier(pc[2].u.operand);
1758 ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
1759 ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, Put, modeAndType.type());
1760
1761 instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
1762 if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
1763 instructions[i + 5].u.watchpointSet = op.watchpointSet;
1764 else if (op.type == ClosureVar || op.type == ClosureVarWithVarInjectionChecks) {
1765 if (op.watchpointSet)
1766 op.watchpointSet->invalidate();
1767 } else if (op.structure)
1768 instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
1769 instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
1770 break;
1771 }
1772
1773 case op_captured_mov:
1774 case op_new_captured_func: {
1775 if (pc[3].u.index == UINT_MAX) {
1776 instructions[i + 3].u.watchpointSet = 0;
1777 break;
1778 }
1779 StringImpl* uid = identifier(pc[3].u.index).impl();
1780 RELEASE_ASSERT(didCloneSymbolTable);
1781 ConcurrentJITLocker locker(m_symbolTable->m_lock);
1782 SymbolTable::Map::iterator iter = m_symbolTable->find(locker, uid);
1783 ASSERT(iter != m_symbolTable->end(locker));
1784 iter->value.prepareToWatch(symbolTable());
1785 instructions[i + 3].u.watchpointSet = iter->value.watchpointSet();
1786 break;
1787 }
1788
1789 case op_debug: {
1790 if (pc[1].u.index == DidReachBreakpoint)
1791 m_hasDebuggerStatement = true;
1792 break;
1793 }
1794
1795 default:
1796 break;
1797 }
1798 i += opLength;
1799 }
1800 m_instructions = WTF::RefCountedArray<Instruction>(instructions);
1801
1802 // Set optimization thresholds only after m_instructions is initialized, since these
1803 // rely on the instruction count (and are in theory permitted to also inspect the
1804 // instruction stream to more accurate assess the cost of tier-up).
1805 optimizeAfterWarmUp();
1806 jitAfterWarmUp();
1807
1808 // If the concurrent thread will want the code block's hash, then compute it here
1809 // synchronously.
1810 if (Options::alwaysComputeHash())
1811 hash();
1812
1813 if (Options::dumpGeneratedBytecodes())
1814 dumpBytecode();
1815
1816 m_heap->m_codeBlocks.add(this);
1817 m_heap->reportExtraMemoryCost(sizeof(CodeBlock) + m_instructions.size() * sizeof(Instruction));
1818 }
1819
1820 CodeBlock::~CodeBlock()
1821 {
1822 if (m_vm->m_perBytecodeProfiler)
1823 m_vm->m_perBytecodeProfiler->notifyDestruction(this);
1824
1825 #if ENABLE(VERBOSE_VALUE_PROFILE)
1826 dumpValueProfiles();
1827 #endif
1828 while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end())
1829 m_incomingLLIntCalls.begin()->remove();
1830 #if ENABLE(JIT)
1831 // We may be destroyed before any CodeBlocks that refer to us are destroyed.
1832 // Consider that two CodeBlocks become unreachable at the same time. There
1833 // is no guarantee about the order in which the CodeBlocks are destroyed.
1834 // So, if we don't remove incoming calls, and get destroyed before the
1835 // CodeBlock(s) that have calls into us, then the CallLinkInfo vector's
1836 // destructor will try to remove nodes from our (no longer valid) linked list.
1837 while (m_incomingCalls.begin() != m_incomingCalls.end())
1838 m_incomingCalls.begin()->remove();
1839
1840 // Note that our outgoing calls will be removed from other CodeBlocks'
1841 // m_incomingCalls linked lists through the execution of the ~CallLinkInfo
1842 // destructors.
1843
1844 for (Bag<StructureStubInfo>::iterator iter = m_stubInfos.begin(); !!iter; ++iter)
1845 (*iter)->deref();
1846 #endif // ENABLE(JIT)
1847 }
1848
1849 void CodeBlock::setNumParameters(int newValue)
1850 {
1851 m_numParameters = newValue;
1852
1853 m_argumentValueProfiles.resizeToFit(newValue);
1854 }
1855
1856 void EvalCodeCache::visitAggregate(SlotVisitor& visitor)
1857 {
1858 EvalCacheMap::iterator end = m_cacheMap.end();
1859 for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr)
1860 visitor.append(&ptr->value);
1861 }
1862
1863 CodeBlock* CodeBlock::specialOSREntryBlockOrNull()
1864 {
1865 #if ENABLE(FTL_JIT)
1866 if (jitType() != JITCode::DFGJIT)
1867 return 0;
1868 DFG::JITCode* jitCode = m_jitCode->dfg();
1869 return jitCode->osrEntryBlock.get();
1870 #else // ENABLE(FTL_JIT)
1871 return 0;
1872 #endif // ENABLE(FTL_JIT)
1873 }
1874
1875 void CodeBlock::visitAggregate(SlotVisitor& visitor)
1876 {
1877 #if ENABLE(PARALLEL_GC)
1878 // I may be asked to scan myself more than once, and it may even happen concurrently.
1879 // To this end, use a CAS loop to check if I've been called already. Only one thread
1880 // may proceed past this point - whichever one wins the CAS race.
1881 unsigned oldValue;
1882 do {
1883 oldValue = m_visitAggregateHasBeenCalled;
1884 if (oldValue) {
1885 // Looks like someone else won! Return immediately to ensure that we don't
1886 // trace the same CodeBlock concurrently. Doing so is hazardous since we will
1887 // be mutating the state of ValueProfiles, which contain JSValues, which can
1888 // have word-tearing on 32-bit, leading to awesome timing-dependent crashes
1889 // that are nearly impossible to track down.
1890
1891 // Also note that it must be safe to return early as soon as we see the
1892 // value true (well, (unsigned)1), since once a GC thread is in this method
1893 // and has won the CAS race (i.e. was responsible for setting the value true)
1894 // it will definitely complete the rest of this method before declaring
1895 // termination.
1896 return;
1897 }
1898 } while (!WTF::weakCompareAndSwap(&m_visitAggregateHasBeenCalled, 0, 1));
1899 #endif // ENABLE(PARALLEL_GC)
1900
1901 if (!!m_alternative)
1902 m_alternative->visitAggregate(visitor);
1903
1904 if (CodeBlock* otherBlock = specialOSREntryBlockOrNull())
1905 otherBlock->visitAggregate(visitor);
1906
1907 visitor.reportExtraMemoryUsage(ownerExecutable(), sizeof(CodeBlock));
1908 if (m_jitCode)
1909 visitor.reportExtraMemoryUsage(ownerExecutable(), m_jitCode->size());
1910 if (m_instructions.size()) {
1911 // Divide by refCount() because m_instructions points to something that is shared
1912 // by multiple CodeBlocks, and we only want to count it towards the heap size once.
1913 // Having each CodeBlock report only its proportional share of the size is one way
1914 // of accomplishing this.
1915 visitor.reportExtraMemoryUsage(ownerExecutable(), m_instructions.size() * sizeof(Instruction) / m_instructions.refCount());
1916 }
1917
1918 visitor.append(&m_unlinkedCode);
1919
1920 // There are three things that may use unconditional finalizers: lazy bytecode freeing,
1921 // inline cache clearing, and jettisoning. The probability of us wanting to do at
1922 // least one of those things is probably quite close to 1. So we add one no matter what
1923 // and when it runs, it figures out whether it has any work to do.
1924 visitor.addUnconditionalFinalizer(this);
1925
1926 m_allTransitionsHaveBeenMarked = false;
1927
1928 if (shouldImmediatelyAssumeLivenessDuringScan()) {
1929 // This code block is live, so scan all references strongly and return.
1930 stronglyVisitStrongReferences(visitor);
1931 stronglyVisitWeakReferences(visitor);
1932 propagateTransitions(visitor);
1933 return;
1934 }
1935
1936 // There are two things that we use weak reference harvesters for: DFG fixpoint for
1937 // jettisoning, and trying to find structures that would be live based on some
1938 // inline cache. So it makes sense to register them regardless.
1939 visitor.addWeakReferenceHarvester(this);
1940
1941 #if ENABLE(DFG_JIT)
1942 // We get here if we're live in the sense that our owner executable is live,
1943 // but we're not yet live for sure in another sense: we may yet decide that this
1944 // code block should be jettisoned based on its outgoing weak references being
1945 // stale. Set a flag to indicate that we're still assuming that we're dead, and
1946 // perform one round of determining if we're live. The GC may determine, based on
1947 // either us marking additional objects, or by other objects being marked for
1948 // other reasons, that this iteration should run again; it will notify us of this
1949 // decision by calling harvestWeakReferences().
1950
1951 m_jitCode->dfgCommon()->livenessHasBeenProved = false;
1952
1953 propagateTransitions(visitor);
1954 determineLiveness(visitor);
1955 #else // ENABLE(DFG_JIT)
1956 RELEASE_ASSERT_NOT_REACHED();
1957 #endif // ENABLE(DFG_JIT)
1958 }
1959
1960 bool CodeBlock::shouldImmediatelyAssumeLivenessDuringScan()
1961 {
1962 #if ENABLE(DFG_JIT)
1963 // Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when
1964 // their weak references go stale. So if a basline JIT CodeBlock gets
1965 // scanned, we can assume that this means that it's live.
1966 if (!JITCode::isOptimizingJIT(jitType()))
1967 return true;
1968
1969 // For simplicity, we don't attempt to jettison code blocks during GC if
1970 // they are executing. Instead we strongly mark their weak references to
1971 // allow them to continue to execute soundly.
1972 if (m_mayBeExecuting)
1973 return true;
1974
1975 if (Options::forceDFGCodeBlockLiveness())
1976 return true;
1977
1978 return false;
1979 #else
1980 return true;
1981 #endif
1982 }
1983
1984 bool CodeBlock::isKnownToBeLiveDuringGC()
1985 {
1986 #if ENABLE(DFG_JIT)
1987 // This should return true for:
1988 // - Code blocks that behave like normal objects - i.e. if they are referenced then they
1989 // are live.
1990 // - Code blocks that were running on the stack.
1991 // - Code blocks that survived the last GC if the current GC is an Eden GC. This is
1992 // because either livenessHasBeenProved would have survived as true or m_mayBeExecuting
1993 // would survive as true.
1994 // - Code blocks that don't have any dead weak references.
1995
1996 return shouldImmediatelyAssumeLivenessDuringScan()
1997 || m_jitCode->dfgCommon()->livenessHasBeenProved;
1998 #else
1999 return true;
2000 #endif
2001 }
2002
2003 void CodeBlock::propagateTransitions(SlotVisitor& visitor)
2004 {
2005 UNUSED_PARAM(visitor);
2006
2007 if (m_allTransitionsHaveBeenMarked)
2008 return;
2009
2010 bool allAreMarkedSoFar = true;
2011
2012 Interpreter* interpreter = m_vm->interpreter;
2013 if (jitType() == JITCode::InterpreterThunk) {
2014 const Vector<unsigned>& propertyAccessInstructions = m_unlinkedCode->propertyAccessInstructions();
2015 for (size_t i = 0; i < propertyAccessInstructions.size(); ++i) {
2016 Instruction* instruction = &instructions()[propertyAccessInstructions[i]];
2017 switch (interpreter->getOpcodeID(instruction[0].u.opcode)) {
2018 case op_put_by_id_transition_direct:
2019 case op_put_by_id_transition_normal:
2020 case op_put_by_id_transition_direct_out_of_line:
2021 case op_put_by_id_transition_normal_out_of_line: {
2022 if (Heap::isMarked(instruction[4].u.structure.get()))
2023 visitor.append(&instruction[6].u.structure);
2024 else
2025 allAreMarkedSoFar = false;
2026 break;
2027 }
2028 default:
2029 break;
2030 }
2031 }
2032 }
2033
2034 #if ENABLE(JIT)
2035 if (JITCode::isJIT(jitType())) {
2036 for (Bag<StructureStubInfo>::iterator iter = m_stubInfos.begin(); !!iter; ++iter) {
2037 StructureStubInfo& stubInfo = **iter;
2038 switch (stubInfo.accessType) {
2039 case access_put_by_id_transition_normal:
2040 case access_put_by_id_transition_direct: {
2041 JSCell* origin = stubInfo.codeOrigin.codeOriginOwner();
2042 if ((!origin || Heap::isMarked(origin))
2043 && Heap::isMarked(stubInfo.u.putByIdTransition.previousStructure.get()))
2044 visitor.append(&stubInfo.u.putByIdTransition.structure);
2045 else
2046 allAreMarkedSoFar = false;
2047 break;
2048 }
2049
2050 case access_put_by_id_list: {
2051 PolymorphicPutByIdList* list = stubInfo.u.putByIdList.list;
2052 JSCell* origin = stubInfo.codeOrigin.codeOriginOwner();
2053 if (origin && !Heap::isMarked(origin)) {
2054 allAreMarkedSoFar = false;
2055 break;
2056 }
2057 for (unsigned j = list->size(); j--;) {
2058 PutByIdAccess& access = list->m_list[j];
2059 if (!access.isTransition())
2060 continue;
2061 if (Heap::isMarked(access.oldStructure()))
2062 visitor.append(&access.m_newStructure);
2063 else
2064 allAreMarkedSoFar = false;
2065 }
2066 break;
2067 }
2068
2069 default:
2070 break;
2071 }
2072 }
2073 }
2074 #endif // ENABLE(JIT)
2075
2076 #if ENABLE(DFG_JIT)
2077 if (JITCode::isOptimizingJIT(jitType())) {
2078 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
2079 for (unsigned i = 0; i < dfgCommon->transitions.size(); ++i) {
2080 if ((!dfgCommon->transitions[i].m_codeOrigin
2081 || Heap::isMarked(dfgCommon->transitions[i].m_codeOrigin.get()))
2082 && Heap::isMarked(dfgCommon->transitions[i].m_from.get())) {
2083 // If the following three things are live, then the target of the
2084 // transition is also live:
2085 // - This code block. We know it's live already because otherwise
2086 // we wouldn't be scanning ourselves.
2087 // - The code origin of the transition. Transitions may arise from
2088 // code that was inlined. They are not relevant if the user's
2089 // object that is required for the inlinee to run is no longer
2090 // live.
2091 // - The source of the transition. The transition checks if some
2092 // heap location holds the source, and if so, stores the target.
2093 // Hence the source must be live for the transition to be live.
2094 visitor.append(&dfgCommon->transitions[i].m_to);
2095 } else
2096 allAreMarkedSoFar = false;
2097 }
2098 }
2099 #endif // ENABLE(DFG_JIT)
2100
2101 if (allAreMarkedSoFar)
2102 m_allTransitionsHaveBeenMarked = true;
2103 }
2104
2105 void CodeBlock::determineLiveness(SlotVisitor& visitor)
2106 {
2107 UNUSED_PARAM(visitor);
2108
2109 if (shouldImmediatelyAssumeLivenessDuringScan())
2110 return;
2111
2112 #if ENABLE(DFG_JIT)
2113 // Check if we have any remaining work to do.
2114 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
2115 if (dfgCommon->livenessHasBeenProved)
2116 return;
2117
2118 // Now check all of our weak references. If all of them are live, then we
2119 // have proved liveness and so we scan our strong references. If at end of
2120 // GC we still have not proved liveness, then this code block is toast.
2121 bool allAreLiveSoFar = true;
2122 for (unsigned i = 0; i < dfgCommon->weakReferences.size(); ++i) {
2123 if (!Heap::isMarked(dfgCommon->weakReferences[i].get())) {
2124 allAreLiveSoFar = false;
2125 break;
2126 }
2127 }
2128
2129 // If some weak references are dead, then this fixpoint iteration was
2130 // unsuccessful.
2131 if (!allAreLiveSoFar)
2132 return;
2133
2134 // All weak references are live. Record this information so we don't
2135 // come back here again, and scan the strong references.
2136 dfgCommon->livenessHasBeenProved = true;
2137 stronglyVisitStrongReferences(visitor);
2138 #endif // ENABLE(DFG_JIT)
2139 }
2140
2141 void CodeBlock::visitWeakReferences(SlotVisitor& visitor)
2142 {
2143 propagateTransitions(visitor);
2144 determineLiveness(visitor);
2145 }
2146
2147 void CodeBlock::finalizeUnconditionally()
2148 {
2149 Interpreter* interpreter = m_vm->interpreter;
2150 if (JITCode::couldBeInterpreted(jitType())) {
2151 const Vector<unsigned>& propertyAccessInstructions = m_unlinkedCode->propertyAccessInstructions();
2152 for (size_t size = propertyAccessInstructions.size(), i = 0; i < size; ++i) {
2153 Instruction* curInstruction = &instructions()[propertyAccessInstructions[i]];
2154 switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
2155 case op_get_by_id:
2156 case op_get_by_id_out_of_line:
2157 case op_put_by_id:
2158 case op_put_by_id_out_of_line:
2159 if (!curInstruction[4].u.structure || Heap::isMarked(curInstruction[4].u.structure.get()))
2160 break;
2161 if (Options::verboseOSR())
2162 dataLogF("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get());
2163 curInstruction[4].u.structure.clear();
2164 curInstruction[5].u.operand = 0;
2165 break;
2166 case op_put_by_id_transition_direct:
2167 case op_put_by_id_transition_normal:
2168 case op_put_by_id_transition_direct_out_of_line:
2169 case op_put_by_id_transition_normal_out_of_line:
2170 if (Heap::isMarked(curInstruction[4].u.structure.get())
2171 && Heap::isMarked(curInstruction[6].u.structure.get())
2172 && Heap::isMarked(curInstruction[7].u.structureChain.get()))
2173 break;
2174 if (Options::verboseOSR()) {
2175 dataLogF("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
2176 curInstruction[4].u.structure.get(),
2177 curInstruction[6].u.structure.get(),
2178 curInstruction[7].u.structureChain.get());
2179 }
2180 curInstruction[4].u.structure.clear();
2181 curInstruction[6].u.structure.clear();
2182 curInstruction[7].u.structureChain.clear();
2183 curInstruction[0].u.opcode = interpreter->getOpcode(op_put_by_id);
2184 break;
2185 case op_get_array_length:
2186 break;
2187 case op_to_this:
2188 if (!curInstruction[2].u.structure || Heap::isMarked(curInstruction[2].u.structure.get()))
2189 break;
2190 if (Options::verboseOSR())
2191 dataLogF("Clearing LLInt to_this with structure %p.\n", curInstruction[2].u.structure.get());
2192 curInstruction[2].u.structure.clear();
2193 break;
2194 case op_get_callee:
2195 if (!curInstruction[2].u.jsCell || Heap::isMarked(curInstruction[2].u.jsCell.get()))
2196 break;
2197 if (Options::verboseOSR())
2198 dataLogF("Clearing LLInt get callee with function %p.\n", curInstruction[2].u.jsCell.get());
2199 curInstruction[2].u.jsCell.clear();
2200 break;
2201 case op_resolve_scope: {
2202 WriteBarrierBase<JSActivation>& activation = curInstruction[5].u.activation;
2203 if (!activation || Heap::isMarked(activation.get()))
2204 break;
2205 if (Options::verboseOSR())
2206 dataLogF("Clearing dead activation %p.\n", activation.get());
2207 activation.clear();
2208 break;
2209 }
2210 case op_get_from_scope:
2211 case op_put_to_scope: {
2212 ResolveModeAndType modeAndType =
2213 ResolveModeAndType(curInstruction[4].u.operand);
2214 if (modeAndType.type() == GlobalVar || modeAndType.type() == GlobalVarWithVarInjectionChecks)
2215 continue;
2216 WriteBarrierBase<Structure>& structure = curInstruction[5].u.structure;
2217 if (!structure || Heap::isMarked(structure.get()))
2218 break;
2219 if (Options::verboseOSR())
2220 dataLogF("Clearing scope access with structure %p.\n", structure.get());
2221 structure.clear();
2222 break;
2223 }
2224 default:
2225 RELEASE_ASSERT_NOT_REACHED();
2226 }
2227 }
2228
2229 for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) {
2230 if (m_llintCallLinkInfos[i].isLinked() && !Heap::isMarked(m_llintCallLinkInfos[i].callee.get())) {
2231 if (Options::verboseOSR())
2232 dataLog("Clearing LLInt call from ", *this, "\n");
2233 m_llintCallLinkInfos[i].unlink();
2234 }
2235 if (!!m_llintCallLinkInfos[i].lastSeenCallee && !Heap::isMarked(m_llintCallLinkInfos[i].lastSeenCallee.get()))
2236 m_llintCallLinkInfos[i].lastSeenCallee.clear();
2237 }
2238 }
2239
2240 #if ENABLE(DFG_JIT)
2241 // Check if we're not live. If we are, then jettison.
2242 if (!isKnownToBeLiveDuringGC()) {
2243 if (Options::verboseOSR())
2244 dataLog(*this, " has dead weak references, jettisoning during GC.\n");
2245
2246 if (DFG::shouldShowDisassembly()) {
2247 dataLog(*this, " will be jettisoned because of the following dead references:\n");
2248 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
2249 for (unsigned i = 0; i < dfgCommon->transitions.size(); ++i) {
2250 DFG::WeakReferenceTransition& transition = dfgCommon->transitions[i];
2251 JSCell* origin = transition.m_codeOrigin.get();
2252 JSCell* from = transition.m_from.get();
2253 JSCell* to = transition.m_to.get();
2254 if ((!origin || Heap::isMarked(origin)) && Heap::isMarked(from))
2255 continue;
2256 dataLog(" Transition under ", RawPointer(origin), ", ", RawPointer(from), " -> ", RawPointer(to), ".\n");
2257 }
2258 for (unsigned i = 0; i < dfgCommon->weakReferences.size(); ++i) {
2259 JSCell* weak = dfgCommon->weakReferences[i].get();
2260 if (Heap::isMarked(weak))
2261 continue;
2262 dataLog(" Weak reference ", RawPointer(weak), ".\n");
2263 }
2264 }
2265
2266 jettison(Profiler::JettisonDueToWeakReference);
2267 return;
2268 }
2269 #endif // ENABLE(DFG_JIT)
2270
2271 #if ENABLE(JIT)
2272 // Handle inline caches.
2273 if (!!jitCode()) {
2274 RepatchBuffer repatchBuffer(this);
2275
2276 for (auto iter = callLinkInfosBegin(); !!iter; ++iter)
2277 (*iter)->visitWeak(repatchBuffer);
2278
2279 for (Bag<StructureStubInfo>::iterator iter = m_stubInfos.begin(); !!iter; ++iter) {
2280 StructureStubInfo& stubInfo = **iter;
2281
2282 if (stubInfo.visitWeakReferences(repatchBuffer))
2283 continue;
2284
2285 resetStubDuringGCInternal(repatchBuffer, stubInfo);
2286 }
2287 }
2288 #endif
2289 }
2290
2291 void CodeBlock::getStubInfoMap(const ConcurrentJITLocker&, StubInfoMap& result)
2292 {
2293 #if ENABLE(JIT)
2294 toHashMap(m_stubInfos, getStructureStubInfoCodeOrigin, result);
2295 #else
2296 UNUSED_PARAM(result);
2297 #endif
2298 }
2299
2300 void CodeBlock::getStubInfoMap(StubInfoMap& result)
2301 {
2302 ConcurrentJITLocker locker(m_lock);
2303 getStubInfoMap(locker, result);
2304 }
2305
2306 void CodeBlock::getCallLinkInfoMap(const ConcurrentJITLocker&, CallLinkInfoMap& result)
2307 {
2308 #if ENABLE(JIT)
2309 toHashMap(m_callLinkInfos, getCallLinkInfoCodeOrigin, result);
2310 #else
2311 UNUSED_PARAM(result);
2312 #endif
2313 }
2314
2315 void CodeBlock::getCallLinkInfoMap(CallLinkInfoMap& result)
2316 {
2317 ConcurrentJITLocker locker(m_lock);
2318 getCallLinkInfoMap(locker, result);
2319 }
2320
2321 #if ENABLE(JIT)
2322 StructureStubInfo* CodeBlock::addStubInfo()
2323 {
2324 ConcurrentJITLocker locker(m_lock);
2325 return m_stubInfos.add();
2326 }
2327
2328 CallLinkInfo* CodeBlock::addCallLinkInfo()
2329 {
2330 ConcurrentJITLocker locker(m_lock);
2331 return m_callLinkInfos.add();
2332 }
2333
2334 void CodeBlock::resetStub(StructureStubInfo& stubInfo)
2335 {
2336 if (stubInfo.accessType == access_unset)
2337 return;
2338
2339 ConcurrentJITLocker locker(m_lock);
2340
2341 RepatchBuffer repatchBuffer(this);
2342 resetStubInternal(repatchBuffer, stubInfo);
2343 }
2344
2345 void CodeBlock::resetStubInternal(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
2346 {
2347 AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
2348
2349 if (Options::verboseOSR()) {
2350 // This can be called from GC destructor calls, so we don't try to do a full dump
2351 // of the CodeBlock.
2352 dataLog("Clearing structure cache (kind ", static_cast<int>(stubInfo.accessType), ") in ", RawPointer(this), ".\n");
2353 }
2354
2355 RELEASE_ASSERT(JITCode::isJIT(jitType()));
2356
2357 if (isGetByIdAccess(accessType))
2358 resetGetByID(repatchBuffer, stubInfo);
2359 else if (isPutByIdAccess(accessType))
2360 resetPutByID(repatchBuffer, stubInfo);
2361 else {
2362 RELEASE_ASSERT(isInAccess(accessType));
2363 resetIn(repatchBuffer, stubInfo);
2364 }
2365
2366 stubInfo.reset();
2367 }
2368
2369 void CodeBlock::resetStubDuringGCInternal(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
2370 {
2371 resetStubInternal(repatchBuffer, stubInfo);
2372 stubInfo.resetByGC = true;
2373 }
2374
2375 CallLinkInfo* CodeBlock::getCallLinkInfoForBytecodeIndex(unsigned index)
2376 {
2377 for (auto iter = m_callLinkInfos.begin(); !!iter; ++iter) {
2378 if ((*iter)->codeOrigin == CodeOrigin(index))
2379 return *iter;
2380 }
2381 return nullptr;
2382 }
2383 #endif
2384
2385 void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
2386 {
2387 visitor.append(&m_globalObject);
2388 visitor.append(&m_ownerExecutable);
2389 visitor.append(&m_symbolTable);
2390 visitor.append(&m_unlinkedCode);
2391 if (m_rareData)
2392 m_rareData->m_evalCodeCache.visitAggregate(visitor);
2393 visitor.appendValues(m_constantRegisters.data(), m_constantRegisters.size());
2394 for (size_t i = 0; i < m_functionExprs.size(); ++i)
2395 visitor.append(&m_functionExprs[i]);
2396 for (size_t i = 0; i < m_functionDecls.size(); ++i)
2397 visitor.append(&m_functionDecls[i]);
2398 for (unsigned i = 0; i < m_objectAllocationProfiles.size(); ++i)
2399 m_objectAllocationProfiles[i].visitAggregate(visitor);
2400
2401 #if ENABLE(DFG_JIT)
2402 if (JITCode::isOptimizingJIT(jitType())) {
2403 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
2404 if (dfgCommon->inlineCallFrames.get())
2405 dfgCommon->inlineCallFrames->visitAggregate(visitor);
2406 }
2407 #endif
2408
2409 updateAllPredictions();
2410 }
2411
2412 void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor)
2413 {
2414 UNUSED_PARAM(visitor);
2415
2416 #if ENABLE(DFG_JIT)
2417 if (!JITCode::isOptimizingJIT(jitType()))
2418 return;
2419
2420 DFG::CommonData* dfgCommon = m_jitCode->dfgCommon();
2421
2422 for (unsigned i = 0; i < dfgCommon->transitions.size(); ++i) {
2423 if (!!dfgCommon->transitions[i].m_codeOrigin)
2424 visitor.append(&dfgCommon->transitions[i].m_codeOrigin); // Almost certainly not necessary, since the code origin should also be a weak reference. Better to be safe, though.
2425 visitor.append(&dfgCommon->transitions[i].m_from);
2426 visitor.append(&dfgCommon->transitions[i].m_to);
2427 }
2428
2429 for (unsigned i = 0; i < dfgCommon->weakReferences.size(); ++i)
2430 visitor.append(&dfgCommon->weakReferences[i]);
2431 #endif
2432 }
2433
2434 CodeBlock* CodeBlock::baselineAlternative()
2435 {
2436 #if ENABLE(JIT)
2437 CodeBlock* result = this;
2438 while (result->alternative())
2439 result = result->alternative();
2440 RELEASE_ASSERT(result);
2441 RELEASE_ASSERT(JITCode::isBaselineCode(result->jitType()) || result->jitType() == JITCode::None);
2442 return result;
2443 #else
2444 return this;
2445 #endif
2446 }
2447
2448 CodeBlock* CodeBlock::baselineVersion()
2449 {
2450 #if ENABLE(JIT)
2451 if (JITCode::isBaselineCode(jitType()))
2452 return this;
2453 CodeBlock* result = replacement();
2454 if (!result) {
2455 // This can happen if we're creating the original CodeBlock for an executable.
2456 // Assume that we're the baseline CodeBlock.
2457 RELEASE_ASSERT(jitType() == JITCode::None);
2458 return this;
2459 }
2460 result = result->baselineAlternative();
2461 return result;
2462 #else
2463 return this;
2464 #endif
2465 }
2466
2467 #if ENABLE(JIT)
2468 bool CodeBlock::hasOptimizedReplacement(JITCode::JITType typeToReplace)
2469 {
2470 return JITCode::isHigherTier(replacement()->jitType(), typeToReplace);
2471 }
2472
2473 bool CodeBlock::hasOptimizedReplacement()
2474 {
2475 return hasOptimizedReplacement(jitType());
2476 }
2477 #endif
2478
2479 bool CodeBlock::isCaptured(VirtualRegister operand, InlineCallFrame* inlineCallFrame) const
2480 {
2481 if (operand.isArgument())
2482 return operand.toArgument() && usesArguments();
2483
2484 if (inlineCallFrame)
2485 return inlineCallFrame->capturedVars.get(operand.toLocal());
2486
2487 // The activation object isn't in the captured region, but it's "captured"
2488 // in the sense that stores to its location can be observed indirectly.
2489 if (needsActivation() && operand == activationRegister())
2490 return true;
2491
2492 // Ditto for the arguments object.
2493 if (usesArguments() && operand == argumentsRegister())
2494 return true;
2495 if (usesArguments() && operand == unmodifiedArgumentsRegister(argumentsRegister()))
2496 return true;
2497
2498 // We're in global code so there are no locals to capture
2499 if (!symbolTable())
2500 return false;
2501
2502 return symbolTable()->isCaptured(operand.offset());
2503 }
2504
2505 int CodeBlock::framePointerOffsetToGetActivationRegisters(int machineCaptureStart)
2506 {
2507 // We'll be adding this to the stack pointer to get a registers pointer that looks
2508 // like it would have looked in the baseline engine. For example, if bytecode would
2509 // have put the first captured variable at offset -5 but we put it at offset -1, then
2510 // we'll have an offset of 4.
2511 int32_t offset = 0;
2512
2513 // Compute where we put the captured variables. This offset will point the registers
2514 // pointer directly at the first captured var.
2515 offset += machineCaptureStart;
2516
2517 // Now compute the offset needed to make the runtime see the captured variables at the
2518 // same offset that the bytecode would have used.
2519 offset -= symbolTable()->captureStart();
2520
2521 return offset;
2522 }
2523
2524 int CodeBlock::framePointerOffsetToGetActivationRegisters()
2525 {
2526 if (!JITCode::isOptimizingJIT(jitType()))
2527 return 0;
2528 #if ENABLE(DFG_JIT)
2529 return framePointerOffsetToGetActivationRegisters(jitCode()->dfgCommon()->machineCaptureStart);
2530 #else
2531 RELEASE_ASSERT_NOT_REACHED();
2532 return 0;
2533 #endif
2534 }
2535
2536 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
2537 {
2538 RELEASE_ASSERT(bytecodeOffset < instructions().size());
2539
2540 if (!m_rareData)
2541 return 0;
2542
2543 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
2544 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
2545 // Handlers are ordered innermost first, so the first handler we encounter
2546 // that contains the source address is the correct handler to use.
2547 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end > bytecodeOffset)
2548 return &exceptionHandlers[i];
2549 }
2550
2551 return 0;
2552 }
2553
2554 unsigned CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
2555 {
2556 RELEASE_ASSERT(bytecodeOffset < instructions().size());
2557 return m_ownerExecutable->lineNo() + m_unlinkedCode->lineNumberForBytecodeOffset(bytecodeOffset);
2558 }
2559
2560 unsigned CodeBlock::columnNumberForBytecodeOffset(unsigned bytecodeOffset)
2561 {
2562 int divot;
2563 int startOffset;
2564 int endOffset;
2565 unsigned line;
2566 unsigned column;
2567 expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
2568 return column;
2569 }
2570
2571 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
2572 {
2573 m_unlinkedCode->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset, line, column);
2574 divot += m_sourceOffset;
2575 column += line ? 1 : firstLineColumnOffset();
2576 line += m_ownerExecutable->lineNo();
2577 }
2578
2579 bool CodeBlock::hasOpDebugForLineAndColumn(unsigned line, unsigned column)
2580 {
2581 Interpreter* interpreter = vm()->interpreter;
2582 const Instruction* begin = instructions().begin();
2583 const Instruction* end = instructions().end();
2584 for (const Instruction* it = begin; it != end;) {
2585 OpcodeID opcodeID = interpreter->getOpcodeID(it->u.opcode);
2586 if (opcodeID == op_debug) {
2587 unsigned bytecodeOffset = it - begin;
2588 int unused;
2589 unsigned opDebugLine;
2590 unsigned opDebugColumn;
2591 expressionRangeForBytecodeOffset(bytecodeOffset, unused, unused, unused, opDebugLine, opDebugColumn);
2592 if (line == opDebugLine && (column == Breakpoint::unspecifiedColumn || column == opDebugColumn))
2593 return true;
2594 }
2595 it += opcodeLengths[opcodeID];
2596 }
2597 return false;
2598 }
2599
2600 void CodeBlock::shrinkToFit(ShrinkMode shrinkMode)
2601 {
2602 m_rareCaseProfiles.shrinkToFit();
2603 m_specialFastCaseProfiles.shrinkToFit();
2604
2605 if (shrinkMode == EarlyShrink) {
2606 m_constantRegisters.shrinkToFit();
2607
2608 if (m_rareData) {
2609 m_rareData->m_switchJumpTables.shrinkToFit();
2610 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
2611 }
2612 } // else don't shrink these, because we would have already pointed pointers into these tables.
2613 }
2614
2615 unsigned CodeBlock::addOrFindConstant(JSValue v)
2616 {
2617 unsigned result;
2618 if (findConstant(v, result))
2619 return result;
2620 return addConstant(v);
2621 }
2622
2623 bool CodeBlock::findConstant(JSValue v, unsigned& index)
2624 {
2625 unsigned numberOfConstants = numberOfConstantRegisters();
2626 for (unsigned i = 0; i < numberOfConstants; ++i) {
2627 if (getConstant(FirstConstantRegisterIndex + i) == v) {
2628 index = i;
2629 return true;
2630 }
2631 }
2632 index = numberOfConstants;
2633 return false;
2634 }
2635
2636 #if ENABLE(JIT)
2637 void CodeBlock::unlinkCalls()
2638 {
2639 if (!!m_alternative)
2640 m_alternative->unlinkCalls();
2641 for (size_t i = 0; i < m_llintCallLinkInfos.size(); ++i) {
2642 if (m_llintCallLinkInfos[i].isLinked())
2643 m_llintCallLinkInfos[i].unlink();
2644 }
2645 if (m_callLinkInfos.isEmpty())
2646 return;
2647 if (!m_vm->canUseJIT())
2648 return;
2649 RepatchBuffer repatchBuffer(this);
2650 for (auto iter = m_callLinkInfos.begin(); !!iter; ++iter) {
2651 CallLinkInfo& info = **iter;
2652 if (!info.isLinked())
2653 continue;
2654 info.unlink(repatchBuffer);
2655 }
2656 }
2657
2658 void CodeBlock::linkIncomingCall(ExecState* callerFrame, CallLinkInfo* incoming)
2659 {
2660 noticeIncomingCall(callerFrame);
2661 m_incomingCalls.push(incoming);
2662 }
2663 #endif // ENABLE(JIT)
2664
2665 void CodeBlock::unlinkIncomingCalls()
2666 {
2667 while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end())
2668 m_incomingLLIntCalls.begin()->unlink();
2669 #if ENABLE(JIT)
2670 if (m_incomingCalls.isEmpty())
2671 return;
2672 RepatchBuffer repatchBuffer(this);
2673 while (m_incomingCalls.begin() != m_incomingCalls.end())
2674 m_incomingCalls.begin()->unlink(repatchBuffer);
2675 #endif // ENABLE(JIT)
2676 }
2677
2678 void CodeBlock::linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo* incoming)
2679 {
2680 noticeIncomingCall(callerFrame);
2681 m_incomingLLIntCalls.push(incoming);
2682 }
2683
2684 void CodeBlock::clearEvalCache()
2685 {
2686 if (!!m_alternative)
2687 m_alternative->clearEvalCache();
2688 if (CodeBlock* otherBlock = specialOSREntryBlockOrNull())
2689 otherBlock->clearEvalCache();
2690 if (!m_rareData)
2691 return;
2692 m_rareData->m_evalCodeCache.clear();
2693 }
2694
2695 void CodeBlock::install()
2696 {
2697 ownerExecutable()->installCode(this);
2698 }
2699
2700 PassRefPtr<CodeBlock> CodeBlock::newReplacement()
2701 {
2702 return ownerExecutable()->newReplacementCodeBlockFor(specializationKind());
2703 }
2704
2705 const SlowArgument* CodeBlock::machineSlowArguments()
2706 {
2707 if (!JITCode::isOptimizingJIT(jitType()))
2708 return symbolTable()->slowArguments();
2709
2710 #if ENABLE(DFG_JIT)
2711 return jitCode()->dfgCommon()->slowArguments.get();
2712 #else // ENABLE(DFG_JIT)
2713 return 0;
2714 #endif // ENABLE(DFG_JIT)
2715 }
2716
2717 #if ENABLE(JIT)
2718 CodeBlock* ProgramCodeBlock::replacement()
2719 {
2720 return jsCast<ProgramExecutable*>(ownerExecutable())->codeBlock();
2721 }
2722
2723 CodeBlock* EvalCodeBlock::replacement()
2724 {
2725 return jsCast<EvalExecutable*>(ownerExecutable())->codeBlock();
2726 }
2727
2728 CodeBlock* FunctionCodeBlock::replacement()
2729 {
2730 return jsCast<FunctionExecutable*>(ownerExecutable())->codeBlockFor(m_isConstructor ? CodeForConstruct : CodeForCall);
2731 }
2732
2733 DFG::CapabilityLevel ProgramCodeBlock::capabilityLevelInternal()
2734 {
2735 return DFG::programCapabilityLevel(this);
2736 }
2737
2738 DFG::CapabilityLevel EvalCodeBlock::capabilityLevelInternal()
2739 {
2740 return DFG::evalCapabilityLevel(this);
2741 }
2742
2743 DFG::CapabilityLevel FunctionCodeBlock::capabilityLevelInternal()
2744 {
2745 if (m_isConstructor)
2746 return DFG::functionForConstructCapabilityLevel(this);
2747 return DFG::functionForCallCapabilityLevel(this);
2748 }
2749 #endif
2750
2751 void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mode)
2752 {
2753 RELEASE_ASSERT(reason != Profiler::NotJettisoned);
2754
2755 #if ENABLE(DFG_JIT)
2756 if (DFG::shouldShowDisassembly()) {
2757 dataLog("Jettisoning ", *this);
2758 if (mode == CountReoptimization)
2759 dataLog(" and counting reoptimization");
2760 dataLog(" due to ", reason, ".\n");
2761 }
2762
2763 DeferGCForAWhile deferGC(*m_heap);
2764 RELEASE_ASSERT(JITCode::isOptimizingJIT(jitType()));
2765
2766 if (Profiler::Compilation* compilation = jitCode()->dfgCommon()->compilation.get())
2767 compilation->setJettisonReason(reason);
2768
2769 // We want to accomplish two things here:
2770 // 1) Make sure that if this CodeBlock is on the stack right now, then if we return to it
2771 // we should OSR exit at the top of the next bytecode instruction after the return.
2772 // 2) Make sure that if we call the owner executable, then we shouldn't call this CodeBlock.
2773
2774 // This accomplishes the OSR-exit-on-return part, and does its own book-keeping about
2775 // whether the invalidation has already happened.
2776 if (!jitCode()->dfgCommon()->invalidate()) {
2777 // Nothing to do since we've already been invalidated. That means that we cannot be
2778 // the optimized replacement.
2779 RELEASE_ASSERT(this != replacement());
2780 return;
2781 }
2782
2783 if (DFG::shouldShowDisassembly())
2784 dataLog(" Did invalidate ", *this, "\n");
2785
2786 // Count the reoptimization if that's what the user wanted.
2787 if (mode == CountReoptimization) {
2788 // FIXME: Maybe this should call alternative().
2789 // https://bugs.webkit.org/show_bug.cgi?id=123677
2790 baselineAlternative()->countReoptimization();
2791 if (DFG::shouldShowDisassembly())
2792 dataLog(" Did count reoptimization for ", *this, "\n");
2793 }
2794
2795 // Now take care of the entrypoint.
2796 if (this != replacement()) {
2797 // This means that we were never the entrypoint. This can happen for OSR entry code
2798 // blocks.
2799 return;
2800 }
2801 alternative()->optimizeAfterWarmUp();
2802 tallyFrequentExitSites();
2803 alternative()->install();
2804 if (DFG::shouldShowDisassembly())
2805 dataLog(" Did install baseline version of ", *this, "\n");
2806 #else // ENABLE(DFG_JIT)
2807 UNUSED_PARAM(mode);
2808 UNREACHABLE_FOR_PLATFORM();
2809 #endif // ENABLE(DFG_JIT)
2810 }
2811
2812 JSGlobalObject* CodeBlock::globalObjectFor(CodeOrigin codeOrigin)
2813 {
2814 if (!codeOrigin.inlineCallFrame)
2815 return globalObject();
2816 return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->eitherCodeBlock()->globalObject();
2817 }
2818
2819 void CodeBlock::noticeIncomingCall(ExecState* callerFrame)
2820 {
2821 CodeBlock* callerCodeBlock = callerFrame->codeBlock();
2822
2823 if (Options::verboseCallLink())
2824 dataLog("Noticing call link from ", *callerCodeBlock, " to ", *this, "\n");
2825
2826 if (!m_shouldAlwaysBeInlined)
2827 return;
2828
2829 #if ENABLE(DFG_JIT)
2830 if (!hasBaselineJITProfiling())
2831 return;
2832
2833 if (!DFG::mightInlineFunction(this))
2834 return;
2835
2836 if (!canInline(m_capabilityLevelState))
2837 return;
2838
2839 if (!DFG::isSmallEnoughToInlineCodeInto(callerCodeBlock)) {
2840 m_shouldAlwaysBeInlined = false;
2841 if (Options::verboseCallLink())
2842 dataLog(" Clearing SABI because caller is too large.\n");
2843 return;
2844 }
2845
2846 if (callerCodeBlock->jitType() == JITCode::InterpreterThunk) {
2847 // If the caller is still in the interpreter, then we can't expect inlining to
2848 // happen anytime soon. Assume it's profitable to optimize it separately. This
2849 // ensures that a function is SABI only if it is called no more frequently than
2850 // any of its callers.
2851 m_shouldAlwaysBeInlined = false;
2852 if (Options::verboseCallLink())
2853 dataLog(" Clearing SABI because caller is in LLInt.\n");
2854 return;
2855 }
2856
2857 if (callerCodeBlock->codeType() != FunctionCode) {
2858 // If the caller is either eval or global code, assume that that won't be
2859 // optimized anytime soon. For eval code this is particularly true since we
2860 // delay eval optimization by a *lot*.
2861 m_shouldAlwaysBeInlined = false;
2862 if (Options::verboseCallLink())
2863 dataLog(" Clearing SABI because caller is not a function.\n");
2864 return;
2865 }
2866
2867 ExecState* frame = callerFrame;
2868 for (unsigned i = Options::maximumInliningDepth(); i--; frame = frame->callerFrame()) {
2869 if (frame->isVMEntrySentinel())
2870 break;
2871 if (frame->codeBlock() == this) {
2872 // Recursive calls won't be inlined.
2873 if (Options::verboseCallLink())
2874 dataLog(" Clearing SABI because recursion was detected.\n");
2875 m_shouldAlwaysBeInlined = false;
2876 return;
2877 }
2878 }
2879
2880 RELEASE_ASSERT(callerCodeBlock->m_capabilityLevelState != DFG::CapabilityLevelNotSet);
2881
2882 if (canCompile(callerCodeBlock->m_capabilityLevelState))
2883 return;
2884
2885 if (Options::verboseCallLink())
2886 dataLog(" Clearing SABI because the caller is not a DFG candidate.\n");
2887
2888 m_shouldAlwaysBeInlined = false;
2889 #endif
2890 }
2891
2892 unsigned CodeBlock::reoptimizationRetryCounter() const
2893 {
2894 #if ENABLE(JIT)
2895 ASSERT(m_reoptimizationRetryCounter <= Options::reoptimizationRetryCounterMax());
2896 return m_reoptimizationRetryCounter;
2897 #else
2898 return 0;
2899 #endif // ENABLE(JIT)
2900 }
2901
2902 #if ENABLE(JIT)
2903 void CodeBlock::countReoptimization()
2904 {
2905 m_reoptimizationRetryCounter++;
2906 if (m_reoptimizationRetryCounter > Options::reoptimizationRetryCounterMax())
2907 m_reoptimizationRetryCounter = Options::reoptimizationRetryCounterMax();
2908 }
2909
2910 unsigned CodeBlock::numberOfDFGCompiles()
2911 {
2912 ASSERT(JITCode::isBaselineCode(jitType()));
2913 if (Options::testTheFTL()) {
2914 if (m_didFailFTLCompilation)
2915 return 1000000;
2916 return (m_hasBeenCompiledWithFTL ? 1 : 0) + m_reoptimizationRetryCounter;
2917 }
2918 return (JITCode::isOptimizingJIT(replacement()->jitType()) ? 1 : 0) + m_reoptimizationRetryCounter;
2919 }
2920
2921 int32_t CodeBlock::codeTypeThresholdMultiplier() const
2922 {
2923 if (codeType() == EvalCode)
2924 return Options::evalThresholdMultiplier();
2925
2926 return 1;
2927 }
2928
2929 double CodeBlock::optimizationThresholdScalingFactor()
2930 {
2931 // This expression arises from doing a least-squares fit of
2932 //
2933 // F[x_] =: a * Sqrt[x + b] + Abs[c * x] + d
2934 //
2935 // against the data points:
2936 //
2937 // x F[x_]
2938 // 10 0.9 (smallest reasonable code block)
2939 // 200 1.0 (typical small-ish code block)
2940 // 320 1.2 (something I saw in 3d-cube that I wanted to optimize)
2941 // 1268 5.0 (something I saw in 3d-cube that I didn't want to optimize)
2942 // 4000 5.5 (random large size, used to cause the function to converge to a shallow curve of some sort)
2943 // 10000 6.0 (similar to above)
2944 //
2945 // I achieve the minimization using the following Mathematica code:
2946 //
2947 // MyFunctionTemplate[x_, a_, b_, c_, d_] := a*Sqrt[x + b] + Abs[c*x] + d
2948 //
2949 // samples = {{10, 0.9}, {200, 1}, {320, 1.2}, {1268, 5}, {4000, 5.5}, {10000, 6}}
2950 //
2951 // solution =
2952 // Minimize[Plus @@ ((MyFunctionTemplate[#[[1]], a, b, c, d] - #[[2]])^2 & /@ samples),
2953 // {a, b, c, d}][[2]]
2954 //
2955 // And the code below (to initialize a, b, c, d) is generated by:
2956 //
2957 // Print["const double " <> ToString[#[[1]]] <> " = " <>
2958 // If[#[[2]] < 0.00001, "0.0", ToString[#[[2]]]] <> ";"] & /@ solution
2959 //
2960 // We've long known the following to be true:
2961 // - Small code blocks are cheap to optimize and so we should do it sooner rather
2962 // than later.
2963 // - Large code blocks are expensive to optimize and so we should postpone doing so,
2964 // and sometimes have a large enough threshold that we never optimize them.
2965 // - The difference in cost is not totally linear because (a) just invoking the
2966 // DFG incurs some base cost and (b) for large code blocks there is enough slop
2967 // in the correlation between instruction count and the actual compilation cost
2968 // that for those large blocks, the instruction count should not have a strong
2969 // influence on our threshold.
2970 //
2971 // I knew the goals but I didn't know how to achieve them; so I picked an interesting
2972 // example where the heuristics were right (code block in 3d-cube with instruction
2973 // count 320, which got compiled early as it should have been) and one where they were
2974 // totally wrong (code block in 3d-cube with instruction count 1268, which was expensive
2975 // to compile and didn't run often enough to warrant compilation in my opinion), and
2976 // then threw in additional data points that represented my own guess of what our
2977 // heuristics should do for some round-numbered examples.
2978 //
2979 // The expression to which I decided to fit the data arose because I started with an
2980 // affine function, and then did two things: put the linear part in an Abs to ensure
2981 // that the fit didn't end up choosing a negative value of c (which would result in
2982 // the function turning over and going negative for large x) and I threw in a Sqrt
2983 // term because Sqrt represents my intution that the function should be more sensitive
2984 // to small changes in small values of x, but less sensitive when x gets large.
2985
2986 // Note that the current fit essentially eliminates the linear portion of the
2987 // expression (c == 0.0).
2988 const double a = 0.061504;
2989 const double b = 1.02406;
2990 const double c = 0.0;
2991 const double d = 0.825914;
2992
2993 double instructionCount = this->instructionCount();
2994
2995 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.
2996
2997 double result = d + a * sqrt(instructionCount + b) + c * instructionCount;
2998
2999 result *= codeTypeThresholdMultiplier();
3000
3001 if (Options::verboseOSR()) {
3002 dataLog(
3003 *this, ": instruction count is ", instructionCount,
3004 ", scaling execution counter by ", result, " * ", codeTypeThresholdMultiplier(),
3005 "\n");
3006 }
3007 return result;
3008 }
3009
3010 static int32_t clipThreshold(double threshold)
3011 {
3012 if (threshold < 1.0)
3013 return 1;
3014
3015 if (threshold > static_cast<double>(std::numeric_limits<int32_t>::max()))
3016 return std::numeric_limits<int32_t>::max();
3017
3018 return static_cast<int32_t>(threshold);
3019 }
3020
3021 int32_t CodeBlock::adjustedCounterValue(int32_t desiredThreshold)
3022 {
3023 return clipThreshold(
3024 static_cast<double>(desiredThreshold) *
3025 optimizationThresholdScalingFactor() *
3026 (1 << reoptimizationRetryCounter()));
3027 }
3028
3029 bool CodeBlock::checkIfOptimizationThresholdReached()
3030 {
3031 #if ENABLE(DFG_JIT)
3032 if (DFG::Worklist* worklist = DFG::existingGlobalDFGWorklistOrNull()) {
3033 if (worklist->compilationState(DFG::CompilationKey(this, DFG::DFGMode))
3034 == DFG::Worklist::Compiled) {
3035 optimizeNextInvocation();
3036 return true;
3037 }
3038 }
3039 #endif
3040
3041 return m_jitExecuteCounter.checkIfThresholdCrossedAndSet(this);
3042 }
3043
3044 void CodeBlock::optimizeNextInvocation()
3045 {
3046 if (Options::verboseOSR())
3047 dataLog(*this, ": Optimizing next invocation.\n");
3048 m_jitExecuteCounter.setNewThreshold(0, this);
3049 }
3050
3051 void CodeBlock::dontOptimizeAnytimeSoon()
3052 {
3053 if (Options::verboseOSR())
3054 dataLog(*this, ": Not optimizing anytime soon.\n");
3055 m_jitExecuteCounter.deferIndefinitely();
3056 }
3057
3058 void CodeBlock::optimizeAfterWarmUp()
3059 {
3060 if (Options::verboseOSR())
3061 dataLog(*this, ": Optimizing after warm-up.\n");
3062 #if ENABLE(DFG_JIT)
3063 m_jitExecuteCounter.setNewThreshold(
3064 adjustedCounterValue(Options::thresholdForOptimizeAfterWarmUp()), this);
3065 #endif
3066 }
3067
3068 void CodeBlock::optimizeAfterLongWarmUp()
3069 {
3070 if (Options::verboseOSR())
3071 dataLog(*this, ": Optimizing after long warm-up.\n");
3072 #if ENABLE(DFG_JIT)
3073 m_jitExecuteCounter.setNewThreshold(
3074 adjustedCounterValue(Options::thresholdForOptimizeAfterLongWarmUp()), this);
3075 #endif
3076 }
3077
3078 void CodeBlock::optimizeSoon()
3079 {
3080 if (Options::verboseOSR())
3081 dataLog(*this, ": Optimizing soon.\n");
3082 #if ENABLE(DFG_JIT)
3083 m_jitExecuteCounter.setNewThreshold(
3084 adjustedCounterValue(Options::thresholdForOptimizeSoon()), this);
3085 #endif
3086 }
3087
3088 void CodeBlock::forceOptimizationSlowPathConcurrently()
3089 {
3090 if (Options::verboseOSR())
3091 dataLog(*this, ": Forcing slow path concurrently.\n");
3092 m_jitExecuteCounter.forceSlowPathConcurrently();
3093 }
3094
3095 #if ENABLE(DFG_JIT)
3096 void CodeBlock::setOptimizationThresholdBasedOnCompilationResult(CompilationResult result)
3097 {
3098 JITCode::JITType type = jitType();
3099 if (type != JITCode::BaselineJIT) {
3100 dataLog(*this, ": expected to have baseline code but have ", type, "\n");
3101 RELEASE_ASSERT_NOT_REACHED();
3102 }
3103
3104 CodeBlock* theReplacement = replacement();
3105 if ((result == CompilationSuccessful) != (theReplacement != this)) {
3106 dataLog(*this, ": we have result = ", result, " but ");
3107 if (theReplacement == this)
3108 dataLog("we are our own replacement.\n");
3109 else
3110 dataLog("our replacement is ", pointerDump(theReplacement), "\n");
3111 RELEASE_ASSERT_NOT_REACHED();
3112 }
3113
3114 switch (result) {
3115 case CompilationSuccessful:
3116 RELEASE_ASSERT(JITCode::isOptimizingJIT(replacement()->jitType()));
3117 optimizeNextInvocation();
3118 return;
3119 case CompilationFailed:
3120 dontOptimizeAnytimeSoon();
3121 return;
3122 case CompilationDeferred:
3123 // We'd like to do dontOptimizeAnytimeSoon() but we cannot because
3124 // forceOptimizationSlowPathConcurrently() is inherently racy. It won't
3125 // necessarily guarantee anything. So, we make sure that even if that
3126 // function ends up being a no-op, we still eventually retry and realize
3127 // that we have optimized code ready.
3128 optimizeAfterWarmUp();
3129 return;
3130 case CompilationInvalidated:
3131 // Retry with exponential backoff.
3132 countReoptimization();
3133 optimizeAfterWarmUp();
3134 return;
3135 }
3136
3137 dataLog("Unrecognized result: ", static_cast<int>(result), "\n");
3138 RELEASE_ASSERT_NOT_REACHED();
3139 }
3140
3141 #endif
3142
3143 uint32_t CodeBlock::adjustedExitCountThreshold(uint32_t desiredThreshold)
3144 {
3145 ASSERT(JITCode::isOptimizingJIT(jitType()));
3146 // Compute this the lame way so we don't saturate. This is called infrequently
3147 // enough that this loop won't hurt us.
3148 unsigned result = desiredThreshold;
3149 for (unsigned n = baselineVersion()->reoptimizationRetryCounter(); n--;) {
3150 unsigned newResult = result << 1;
3151 if (newResult < result)
3152 return std::numeric_limits<uint32_t>::max();
3153 result = newResult;
3154 }
3155 return result;
3156 }
3157
3158 uint32_t CodeBlock::exitCountThresholdForReoptimization()
3159 {
3160 return adjustedExitCountThreshold(Options::osrExitCountForReoptimization() * codeTypeThresholdMultiplier());
3161 }
3162
3163 uint32_t CodeBlock::exitCountThresholdForReoptimizationFromLoop()
3164 {
3165 return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop() * codeTypeThresholdMultiplier());
3166 }
3167
3168 bool CodeBlock::shouldReoptimizeNow()
3169 {
3170 return osrExitCounter() >= exitCountThresholdForReoptimization();
3171 }
3172
3173 bool CodeBlock::shouldReoptimizeFromLoopNow()
3174 {
3175 return osrExitCounter() >= exitCountThresholdForReoptimizationFromLoop();
3176 }
3177 #endif
3178
3179 ArrayProfile* CodeBlock::getArrayProfile(unsigned bytecodeOffset)
3180 {
3181 for (unsigned i = 0; i < m_arrayProfiles.size(); ++i) {
3182 if (m_arrayProfiles[i].bytecodeOffset() == bytecodeOffset)
3183 return &m_arrayProfiles[i];
3184 }
3185 return 0;
3186 }
3187
3188 ArrayProfile* CodeBlock::getOrAddArrayProfile(unsigned bytecodeOffset)
3189 {
3190 ArrayProfile* result = getArrayProfile(bytecodeOffset);
3191 if (result)
3192 return result;
3193 return addArrayProfile(bytecodeOffset);
3194 }
3195
3196 void CodeBlock::updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
3197 {
3198 ConcurrentJITLocker locker(m_lock);
3199
3200 numberOfLiveNonArgumentValueProfiles = 0;
3201 numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
3202 for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
3203 ValueProfile* profile = getFromAllValueProfiles(i);
3204 unsigned numSamples = profile->totalNumberOfSamples();
3205 if (numSamples > ValueProfile::numberOfBuckets)
3206 numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
3207 numberOfSamplesInProfiles += numSamples;
3208 if (profile->m_bytecodeOffset < 0) {
3209 profile->computeUpdatedPrediction(locker);
3210 continue;
3211 }
3212 if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
3213 numberOfLiveNonArgumentValueProfiles++;
3214 profile->computeUpdatedPrediction(locker);
3215 }
3216
3217 #if ENABLE(DFG_JIT)
3218 m_lazyOperandValueProfiles.computeUpdatedPredictions(locker);
3219 #endif
3220 }
3221
3222 void CodeBlock::updateAllValueProfilePredictions()
3223 {
3224 unsigned ignoredValue1, ignoredValue2;
3225 updateAllPredictionsAndCountLiveness(ignoredValue1, ignoredValue2);
3226 }
3227
3228 void CodeBlock::updateAllArrayPredictions()
3229 {
3230 ConcurrentJITLocker locker(m_lock);
3231
3232 for (unsigned i = m_arrayProfiles.size(); i--;)
3233 m_arrayProfiles[i].computeUpdatedPrediction(locker, this);
3234
3235 // Don't count these either, for similar reasons.
3236 for (unsigned i = m_arrayAllocationProfiles.size(); i--;)
3237 m_arrayAllocationProfiles[i].updateIndexingType();
3238 }
3239
3240 void CodeBlock::updateAllPredictions()
3241 {
3242 updateAllValueProfilePredictions();
3243 updateAllArrayPredictions();
3244 }
3245
3246 bool CodeBlock::shouldOptimizeNow()
3247 {
3248 if (Options::verboseOSR())
3249 dataLog("Considering optimizing ", *this, "...\n");
3250
3251 if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay())
3252 return true;
3253
3254 updateAllArrayPredictions();
3255
3256 unsigned numberOfLiveNonArgumentValueProfiles;
3257 unsigned numberOfSamplesInProfiles;
3258 updateAllPredictionsAndCountLiveness(numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
3259
3260 if (Options::verboseOSR()) {
3261 dataLogF(
3262 "Profile hotness: %lf (%u / %u), %lf (%u / %u)\n",
3263 (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(),
3264 numberOfLiveNonArgumentValueProfiles, numberOfValueProfiles(),
3265 (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles(),
3266 numberOfSamplesInProfiles, ValueProfile::numberOfBuckets * numberOfValueProfiles());
3267 }
3268
3269 if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate())
3270 && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate())
3271 && static_cast<unsigned>(m_optimizationDelayCounter) + 1 >= Options::minimumOptimizationDelay())
3272 return true;
3273
3274 ASSERT(m_optimizationDelayCounter < std::numeric_limits<uint8_t>::max());
3275 m_optimizationDelayCounter++;
3276 optimizeAfterWarmUp();
3277 return false;
3278 }
3279
3280 #if ENABLE(DFG_JIT)
3281 void CodeBlock::tallyFrequentExitSites()
3282 {
3283 ASSERT(JITCode::isOptimizingJIT(jitType()));
3284 ASSERT(alternative()->jitType() == JITCode::BaselineJIT);
3285
3286 CodeBlock* profiledBlock = alternative();
3287
3288 switch (jitType()) {
3289 case JITCode::DFGJIT: {
3290 DFG::JITCode* jitCode = m_jitCode->dfg();
3291 for (unsigned i = 0; i < jitCode->osrExit.size(); ++i) {
3292 DFG::OSRExit& exit = jitCode->osrExit[i];
3293
3294 if (!exit.considerAddingAsFrequentExitSite(profiledBlock))
3295 continue;
3296 }
3297 break;
3298 }
3299
3300 #if ENABLE(FTL_JIT)
3301 case JITCode::FTLJIT: {
3302 // There is no easy way to avoid duplicating this code since the FTL::JITCode::osrExit
3303 // vector contains a totally different type, that just so happens to behave like
3304 // DFG::JITCode::osrExit.
3305 FTL::JITCode* jitCode = m_jitCode->ftl();
3306 for (unsigned i = 0; i < jitCode->osrExit.size(); ++i) {
3307 FTL::OSRExit& exit = jitCode->osrExit[i];
3308
3309 if (!exit.considerAddingAsFrequentExitSite(profiledBlock))
3310 continue;
3311 }
3312 break;
3313 }
3314 #endif
3315
3316 default:
3317 RELEASE_ASSERT_NOT_REACHED();
3318 break;
3319 }
3320 }
3321 #endif // ENABLE(DFG_JIT)
3322
3323 #if ENABLE(VERBOSE_VALUE_PROFILE)
3324 void CodeBlock::dumpValueProfiles()
3325 {
3326 dataLog("ValueProfile for ", *this, ":\n");
3327 for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
3328 ValueProfile* profile = getFromAllValueProfiles(i);
3329 if (profile->m_bytecodeOffset < 0) {
3330 ASSERT(profile->m_bytecodeOffset == -1);
3331 dataLogF(" arg = %u: ", i);
3332 } else
3333 dataLogF(" bc = %d: ", profile->m_bytecodeOffset);
3334 if (!profile->numberOfSamples() && profile->m_prediction == SpecNone) {
3335 dataLogF("<empty>\n");
3336 continue;
3337 }
3338 profile->dump(WTF::dataFile());
3339 dataLogF("\n");
3340 }
3341 dataLog("RareCaseProfile for ", *this, ":\n");
3342 for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) {
3343 RareCaseProfile* profile = rareCaseProfile(i);
3344 dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
3345 }
3346 dataLog("SpecialFastCaseProfile for ", *this, ":\n");
3347 for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) {
3348 RareCaseProfile* profile = specialFastCaseProfile(i);
3349 dataLogF(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
3350 }
3351 }
3352 #endif // ENABLE(VERBOSE_VALUE_PROFILE)
3353
3354 unsigned CodeBlock::frameRegisterCount()
3355 {
3356 switch (jitType()) {
3357 case JITCode::InterpreterThunk:
3358 return LLInt::frameRegisterCountFor(this);
3359
3360 #if ENABLE(JIT)
3361 case JITCode::BaselineJIT:
3362 return JIT::frameRegisterCountFor(this);
3363 #endif // ENABLE(JIT)
3364
3365 #if ENABLE(DFG_JIT)
3366 case JITCode::DFGJIT:
3367 case JITCode::FTLJIT:
3368 return jitCode()->dfgCommon()->frameRegisterCount;
3369 #endif // ENABLE(DFG_JIT)
3370
3371 default:
3372 RELEASE_ASSERT_NOT_REACHED();
3373 return 0;
3374 }
3375 }
3376
3377 int CodeBlock::stackPointerOffset()
3378 {
3379 return virtualRegisterForLocal(frameRegisterCount() - 1).offset();
3380 }
3381
3382 size_t CodeBlock::predictedMachineCodeSize()
3383 {
3384 // This will be called from CodeBlock::CodeBlock before either m_vm or the
3385 // instructions have been initialized. It's OK to return 0 because what will really
3386 // matter is the recomputation of this value when the slow path is triggered.
3387 if (!m_vm)
3388 return 0;
3389
3390 if (!m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT)
3391 return 0; // It's as good of a prediction as we'll get.
3392
3393 // Be conservative: return a size that will be an overestimation 84% of the time.
3394 double multiplier = m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT.mean() +
3395 m_vm->machineCodeBytesPerBytecodeWordForBaselineJIT.standardDeviation();
3396
3397 // Be paranoid: silently reject bogus multipiers. Silently doing the "wrong" thing
3398 // here is OK, since this whole method is just a heuristic.
3399 if (multiplier < 0 || multiplier > 1000)
3400 return 0;
3401
3402 double doubleResult = multiplier * m_instructions.size();
3403
3404 // Be even more paranoid: silently reject values that won't fit into a size_t. If
3405 // the function is so huge that we can't even fit it into virtual memory then we
3406 // should probably have some other guards in place to prevent us from even getting
3407 // to this point.
3408 if (doubleResult > std::numeric_limits<size_t>::max())
3409 return 0;
3410
3411 return static_cast<size_t>(doubleResult);
3412 }
3413
3414 bool CodeBlock::usesOpcode(OpcodeID opcodeID)
3415 {
3416 Interpreter* interpreter = vm()->interpreter;
3417 Instruction* instructionsBegin = instructions().begin();
3418 unsigned instructionCount = instructions().size();
3419
3420 for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
3421 switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
3422 #define DEFINE_OP(curOpcode, length) \
3423 case curOpcode: \
3424 if (curOpcode == opcodeID) \
3425 return true; \
3426 bytecodeOffset += length; \
3427 break;
3428 FOR_EACH_OPCODE_ID(DEFINE_OP)
3429 #undef DEFINE_OP
3430 default:
3431 RELEASE_ASSERT_NOT_REACHED();
3432 break;
3433 }
3434 }
3435
3436 return false;
3437 }
3438
3439 String CodeBlock::nameForRegister(VirtualRegister virtualRegister)
3440 {
3441 ConcurrentJITLocker locker(symbolTable()->m_lock);
3442 SymbolTable::Map::iterator end = symbolTable()->end(locker);
3443 for (SymbolTable::Map::iterator ptr = symbolTable()->begin(locker); ptr != end; ++ptr) {
3444 if (ptr->value.getIndex() == virtualRegister.offset()) {
3445 // FIXME: This won't work from the compilation thread.
3446 // https://bugs.webkit.org/show_bug.cgi?id=115300
3447 return String(ptr->key);
3448 }
3449 }
3450 if (needsActivation() && virtualRegister == activationRegister())
3451 return ASCIILiteral("activation");
3452 if (virtualRegister == thisRegister())
3453 return ASCIILiteral("this");
3454 if (usesArguments()) {
3455 if (virtualRegister == argumentsRegister())
3456 return ASCIILiteral("arguments");
3457 if (unmodifiedArgumentsRegister(argumentsRegister()) == virtualRegister)
3458 return ASCIILiteral("real arguments");
3459 }
3460 if (virtualRegister.isArgument())
3461 return String::format("arguments[%3d]", virtualRegister.toArgument()).impl();
3462
3463 return "";
3464 }
3465
3466 namespace {
3467
3468 struct VerifyCapturedDef {
3469 void operator()(CodeBlock* codeBlock, Instruction* instruction, OpcodeID opcodeID, int operand)
3470 {
3471 unsigned bytecodeOffset = instruction - codeBlock->instructions().begin();
3472
3473 if (codeBlock->isConstantRegisterIndex(operand)) {
3474 codeBlock->beginValidationDidFail();
3475 dataLog(" At bc#", bytecodeOffset, " encountered a definition of a constant.\n");
3476 codeBlock->endValidationDidFail();
3477 return;
3478 }
3479
3480 switch (opcodeID) {
3481 case op_enter:
3482 case op_captured_mov:
3483 case op_init_lazy_reg:
3484 case op_create_arguments:
3485 case op_new_captured_func:
3486 return;
3487 default:
3488 break;
3489 }
3490
3491 VirtualRegister virtualReg(operand);
3492 if (!virtualReg.isLocal())
3493 return;
3494
3495 if (codeBlock->captureCount() && codeBlock->symbolTable()->isCaptured(operand)) {
3496 codeBlock->beginValidationDidFail();
3497 dataLog(" At bc#", bytecodeOffset, " encountered invalid assignment to captured variable loc", virtualReg.toLocal(), ".\n");
3498 codeBlock->endValidationDidFail();
3499 return;
3500 }
3501
3502 return;
3503 }
3504 };
3505
3506 } // anonymous namespace
3507
3508 void CodeBlock::validate()
3509 {
3510 BytecodeLivenessAnalysis liveness(this); // Compute directly from scratch so it doesn't effect CodeBlock footprint.
3511
3512 FastBitVector liveAtHead = liveness.getLivenessInfoAtBytecodeOffset(0);
3513
3514 if (liveAtHead.numBits() != static_cast<size_t>(m_numCalleeRegisters)) {
3515 beginValidationDidFail();
3516 dataLog(" Wrong number of bits in result!\n");
3517 dataLog(" Result: ", liveAtHead, "\n");
3518 dataLog(" Bit count: ", liveAtHead.numBits(), "\n");
3519 endValidationDidFail();
3520 }
3521
3522 for (unsigned i = m_numCalleeRegisters; i--;) {
3523 bool isCaptured = false;
3524 VirtualRegister reg = virtualRegisterForLocal(i);
3525
3526 if (captureCount())
3527 isCaptured = reg.offset() <= captureStart() && reg.offset() > captureEnd();
3528
3529 if (isCaptured) {
3530 if (!liveAtHead.get(i)) {
3531 beginValidationDidFail();
3532 dataLog(" Variable loc", i, " is expected to be live because it is captured, but it isn't live.\n");
3533 dataLog(" Result: ", liveAtHead, "\n");
3534 endValidationDidFail();
3535 }
3536 } else {
3537 if (liveAtHead.get(i)) {
3538 beginValidationDidFail();
3539 dataLog(" Variable loc", i, " is expected to be dead.\n");
3540 dataLog(" Result: ", liveAtHead, "\n");
3541 endValidationDidFail();
3542 }
3543 }
3544 }
3545
3546 for (unsigned bytecodeOffset = 0; bytecodeOffset < instructions().size();) {
3547 Instruction* currentInstruction = instructions().begin() + bytecodeOffset;
3548 OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
3549
3550 VerifyCapturedDef verifyCapturedDef;
3551 computeDefsForBytecodeOffset(this, bytecodeOffset, verifyCapturedDef);
3552
3553 bytecodeOffset += opcodeLength(opcodeID);
3554 }
3555 }
3556
3557 void CodeBlock::beginValidationDidFail()
3558 {
3559 dataLog("Validation failure in ", *this, ":\n");
3560 dataLog("\n");
3561 }
3562
3563 void CodeBlock::endValidationDidFail()
3564 {
3565 dataLog("\n");
3566 dumpBytecode();
3567 dataLog("\n");
3568 dataLog("Validation failure.\n");
3569 RELEASE_ASSERT_NOT_REACHED();
3570 }
3571
3572 void CodeBlock::addBreakpoint(unsigned numBreakpoints)
3573 {
3574 m_numBreakpoints += numBreakpoints;
3575 ASSERT(m_numBreakpoints);
3576 if (JITCode::isOptimizingJIT(jitType()))
3577 jettison(Profiler::JettisonDueToDebuggerBreakpoint);
3578 }
3579
3580 void CodeBlock::setSteppingMode(CodeBlock::SteppingMode mode)
3581 {
3582 m_steppingMode = mode;
3583 if (mode == SteppingModeEnabled && JITCode::isOptimizingJIT(jitType()))
3584 jettison(Profiler::JettisonDueToDebuggerStepping);
3585 }
3586
3587 RareCaseProfile* CodeBlock::rareCaseProfileForBytecodeOffset(int bytecodeOffset)
3588 {
3589 return tryBinarySearch<RareCaseProfile, int>(
3590 m_rareCaseProfiles, m_rareCaseProfiles.size(), bytecodeOffset,
3591 getRareCaseProfileBytecodeOffset);
3592 }
3593
3594 #if ENABLE(JIT)
3595 DFG::CapabilityLevel CodeBlock::capabilityLevel()
3596 {
3597 DFG::CapabilityLevel result = capabilityLevelInternal();
3598 m_capabilityLevelState = result;
3599 return result;
3600 }
3601 #endif
3602
3603 } // namespace JSC