]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - bytecode/CodeBlock.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / bytecode / CodeBlock.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2008, 2009, 2010 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 Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
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 "DFGCapabilities.h"
35#include "DFGNode.h"
36#include "DFGRepatch.h"
37#include "Debugger.h"
38#include "Interpreter.h"
39#include "JIT.h"
40#include "JITStubs.h"
41#include "JSActivation.h"
42#include "JSFunction.h"
43#include "JSStaticScopeObject.h"
44#include "JSValue.h"
45#include "LowLevelInterpreter.h"
46#include "RepatchBuffer.h"
47#include "UStringConcatenate.h"
48#include <stdio.h>
49#include <wtf/StringExtras.h>
50
51#if ENABLE(DFG_JIT)
52#include "DFGOperations.h"
53#endif
54
55#define DUMP_CODE_BLOCK_STATISTICS 0
56
57namespace JSC {
58
59#if ENABLE(DFG_JIT)
60using namespace DFG;
61#endif
62
63static UString escapeQuotes(const UString& str)
64{
65 UString result = str;
66 size_t pos = 0;
67 while ((pos = result.find('\"', pos)) != notFound) {
68 result = makeUString(result.substringSharingImpl(0, pos), "\"\\\"\"", result.substringSharingImpl(pos + 1));
69 pos += 4;
70 }
71 return result;
72}
73
74static UString valueToSourceString(ExecState* exec, JSValue val)
75{
76 if (!val)
77 return "0";
78
79 if (val.isString())
80 return makeUString("\"", escapeQuotes(val.toString(exec)->value(exec)), "\"");
81
82 return val.description();
83}
84
85static CString constantName(ExecState* exec, int k, JSValue value)
86{
87 return makeUString(valueToSourceString(exec, value), "(@k", UString::number(k - FirstConstantRegisterIndex), ")").utf8();
88}
89
90static CString idName(int id0, const Identifier& ident)
91{
92 return makeUString(ident.ustring(), "(@id", UString::number(id0), ")").utf8();
93}
94
95CString CodeBlock::registerName(ExecState* exec, int r) const
96{
97 if (r == missingThisObjectMarker())
98 return "<null>";
99
100 if (isConstantRegisterIndex(r))
101 return constantName(exec, r, getConstant(r));
102
103 return makeUString("r", UString::number(r)).utf8();
104}
105
106static UString regexpToSourceString(RegExp* regExp)
107{
108 char postfix[5] = { '/', 0, 0, 0, 0 };
109 int index = 1;
110 if (regExp->global())
111 postfix[index++] = 'g';
112 if (regExp->ignoreCase())
113 postfix[index++] = 'i';
114 if (regExp->multiline())
115 postfix[index] = 'm';
116
117 return makeUString("/", regExp->pattern(), postfix);
118}
119
120static CString regexpName(int re, RegExp* regexp)
121{
122 return makeUString(regexpToSourceString(regexp), "(@re", UString::number(re), ")").utf8();
123}
124
125static UString pointerToSourceString(void* p)
126{
127 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
128 snprintf(buffer, sizeof(buffer), "%p", p);
129 return buffer;
130}
131
132NEVER_INLINE static const char* debugHookName(int debugHookID)
133{
134 switch (static_cast<DebugHookID>(debugHookID)) {
135 case DidEnterCallFrame:
136 return "didEnterCallFrame";
137 case WillLeaveCallFrame:
138 return "willLeaveCallFrame";
139 case WillExecuteStatement:
140 return "willExecuteStatement";
141 case WillExecuteProgram:
142 return "willExecuteProgram";
143 case DidExecuteProgram:
144 return "didExecuteProgram";
145 case DidReachBreakpoint:
146 return "didReachBreakpoint";
147 }
148
149 ASSERT_NOT_REACHED();
150 return "";
151}
152
153void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
154{
155 int r0 = (++it)->u.operand;
156 int r1 = (++it)->u.operand;
157
158 dataLog("[%4d] %s\t\t %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data());
159}
160
161void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
162{
163 int r0 = (++it)->u.operand;
164 int r1 = (++it)->u.operand;
165 int r2 = (++it)->u.operand;
166 dataLog("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
167}
168
169void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) const
170{
171 int r0 = (++it)->u.operand;
172 int offset = (++it)->u.operand;
173 dataLog("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(exec, r0).data(), offset, location + offset);
174}
175
176void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
177{
178 int r0 = (++it)->u.operand;
179 int r1 = (++it)->u.operand;
180 int id0 = (++it)->u.operand;
181 dataLog("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
182 it += 5;
183}
184
185void CodeBlock::printCallOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
186{
187 int func = (++it)->u.operand;
188 int argCount = (++it)->u.operand;
189 int registerOffset = (++it)->u.operand;
190 dataLog("[%4d] %s\t %s, %d, %d\n", location, op, registerName(exec, func).data(), argCount, registerOffset);
191 it += 2;
192}
193
194void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
195{
196 int r0 = (++it)->u.operand;
197 int id0 = (++it)->u.operand;
198 int r1 = (++it)->u.operand;
199 dataLog("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
200 it += 5;
201}
202
203#if ENABLE(JIT)
204static bool isGlobalResolve(OpcodeID opcodeID)
205{
206 return opcodeID == op_resolve_global || opcodeID == op_resolve_global_dynamic;
207}
208
209static bool isPropertyAccess(OpcodeID opcodeID)
210{
211 switch (opcodeID) {
212 case op_get_by_id_self:
213 case op_get_by_id_proto:
214 case op_get_by_id_chain:
215 case op_put_by_id_transition:
216 case op_put_by_id_replace:
217 case op_get_by_id:
218 case op_put_by_id:
219 case op_get_by_id_generic:
220 case op_put_by_id_generic:
221 case op_get_array_length:
222 case op_get_string_length:
223 return true;
224 default:
225 return false;
226 }
227}
228
229static unsigned instructionOffsetForNth(ExecState* exec, const RefCountedArray<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
230{
231 size_t i = 0;
232 while (i < instructions.size()) {
233 OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode);
234 if (predicate(currentOpcode)) {
235 if (!--nth)
236 return i;
237 }
238 i += opcodeLengths[currentOpcode];
239 }
240
241 ASSERT_NOT_REACHED();
242 return 0;
243}
244
245static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
246{
247 dataLog(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data());
248}
249
250static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset)
251{
252 switch (stubInfo.accessType) {
253 case access_get_by_id_self:
254 dataLog(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data());
255 return;
256 case access_get_by_id_proto:
257 dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).utf8().data());
258 return;
259 case access_get_by_id_chain:
260 dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).utf8().data());
261 return;
262 case access_get_by_id_self_list:
263 dataLog(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).utf8().data(), stubInfo.u.getByIdSelfList.listSize);
264 return;
265 case access_get_by_id_proto_list:
266 dataLog(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).utf8().data(), stubInfo.u.getByIdProtoList.listSize);
267 return;
268 case access_put_by_id_transition_normal:
269 case access_put_by_id_transition_direct:
270 dataLog(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(stubInfo.u.putByIdTransition.previousStructure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).utf8().data(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).utf8().data());
271 return;
272 case access_put_by_id_replace:
273 dataLog(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data());
274 return;
275 case access_unset:
276 dataLog(" [%4d] %s\n", instructionOffset, "unset");
277 return;
278 case access_get_by_id_generic:
279 dataLog(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic");
280 return;
281 case access_put_by_id_generic:
282 dataLog(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic");
283 return;
284 case access_get_array_length:
285 dataLog(" [%4d] %s\n", instructionOffset, "op_get_array_length");
286 return;
287 case access_get_string_length:
288 dataLog(" [%4d] %s\n", instructionOffset, "op_get_string_length");
289 return;
290 default:
291 ASSERT_NOT_REACHED();
292 }
293}
294#endif
295
296void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
297{
298 unsigned instructionOffset = vPC - instructions().begin();
299 dataLog(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data());
300}
301
302void CodeBlock::printStructures(const Instruction* vPC) const
303{
304 Interpreter* interpreter = m_globalData->interpreter;
305 unsigned instructionOffset = vPC - instructions().begin();
306
307 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
308 printStructure("get_by_id", vPC, 4);
309 return;
310 }
311 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
312 printStructure("get_by_id_self", vPC, 4);
313 return;
314 }
315 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
316 dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data());
317 return;
318 }
319 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
320 dataLog(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data());
321 return;
322 }
323 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
324 dataLog(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data());
325 return;
326 }
327 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
328 printStructure("put_by_id", vPC, 4);
329 return;
330 }
331 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
332 printStructure("put_by_id_replace", vPC, 4);
333 return;
334 }
335 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
336 printStructure("resolve_global", vPC, 4);
337 return;
338 }
339 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
340 printStructure("resolve_global_dynamic", vPC, 4);
341 return;
342 }
343
344 // These m_instructions doesn't ref Structures.
345 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_call) || vPC[0].u.opcode == interpreter->getOpcode(op_call_eval) || vPC[0].u.opcode == interpreter->getOpcode(op_construct));
346}
347
348void CodeBlock::dump(ExecState* exec) const
349{
350 size_t instructionCount = 0;
351
352 for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
353 ++instructionCount;
354
355 dataLog("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s); %d variable(s)\n\n",
356 static_cast<unsigned long>(instructions().size()),
357 static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
358 this, m_numParameters, m_numCalleeRegisters, m_numVars);
359
360 Vector<Instruction>::const_iterator begin = instructions().begin();
361 Vector<Instruction>::const_iterator end = instructions().end();
362 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
363 dump(exec, begin, it);
364
365 if (!m_identifiers.isEmpty()) {
366 dataLog("\nIdentifiers:\n");
367 size_t i = 0;
368 do {
369 dataLog(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ustring().utf8().data());
370 ++i;
371 } while (i != m_identifiers.size());
372 }
373
374 if (!m_constantRegisters.isEmpty()) {
375 dataLog("\nConstants:\n");
376 size_t i = 0;
377 do {
378 dataLog(" k%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data());
379 ++i;
380 } while (i < m_constantRegisters.size());
381 }
382
383 if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
384 dataLog("\nm_regexps:\n");
385 size_t i = 0;
386 do {
387 dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data());
388 ++i;
389 } while (i < m_rareData->m_regexps.size());
390 }
391
392#if ENABLE(JIT)
393 if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
394 dataLog("\nStructures:\n");
395
396 if (!m_globalResolveInfos.isEmpty()) {
397 size_t i = 0;
398 do {
399 printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, instructions(), i + 1, isGlobalResolve));
400 ++i;
401 } while (i < m_globalResolveInfos.size());
402 }
403 if (!m_structureStubInfos.isEmpty()) {
404 size_t i = 0;
405 do {
406 printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, instructions(), i + 1, isPropertyAccess));
407 ++i;
408 } while (i < m_structureStubInfos.size());
409 }
410#endif
411#if ENABLE(CLASSIC_INTERPRETER)
412 if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
413 dataLog("\nStructures:\n");
414
415 if (!m_globalResolveInstructions.isEmpty()) {
416 size_t i = 0;
417 do {
418 printStructures(&instructions()[m_globalResolveInstructions[i]]);
419 ++i;
420 } while (i < m_globalResolveInstructions.size());
421 }
422 if (!m_propertyAccessInstructions.isEmpty()) {
423 size_t i = 0;
424 do {
425 printStructures(&instructions()[m_propertyAccessInstructions[i]]);
426 ++i;
427 } while (i < m_propertyAccessInstructions.size());
428 }
429#endif
430
431 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
432 dataLog("\nException Handlers:\n");
433 unsigned i = 0;
434 do {
435 dataLog("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
436 ++i;
437 } while (i < m_rareData->m_exceptionHandlers.size());
438 }
439
440 if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
441 dataLog("Immediate Switch Jump Tables:\n");
442 unsigned i = 0;
443 do {
444 dataLog(" %1d = {\n", i);
445 int entry = 0;
446 Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
447 for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
448 if (!*iter)
449 continue;
450 dataLog("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
451 }
452 dataLog(" }\n");
453 ++i;
454 } while (i < m_rareData->m_immediateSwitchJumpTables.size());
455 }
456
457 if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
458 dataLog("\nCharacter Switch Jump Tables:\n");
459 unsigned i = 0;
460 do {
461 dataLog(" %1d = {\n", i);
462 int entry = 0;
463 Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
464 for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
465 if (!*iter)
466 continue;
467 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
468 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
469 dataLog("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter);
470 }
471 dataLog(" }\n");
472 ++i;
473 } while (i < m_rareData->m_characterSwitchJumpTables.size());
474 }
475
476 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
477 dataLog("\nString Switch Jump Tables:\n");
478 unsigned i = 0;
479 do {
480 dataLog(" %1d = {\n", i);
481 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
482 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
483 dataLog("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset);
484 dataLog(" }\n");
485 ++i;
486 } while (i < m_rareData->m_stringSwitchJumpTables.size());
487 }
488
489 dataLog("\n");
490}
491
492void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
493{
494 int location = it - begin;
495 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
496 case op_enter: {
497 dataLog("[%4d] enter\n", location);
498 break;
499 }
500 case op_create_activation: {
501 int r0 = (++it)->u.operand;
502 dataLog("[%4d] create_activation %s\n", location, registerName(exec, r0).data());
503 break;
504 }
505 case op_create_arguments: {
506 int r0 = (++it)->u.operand;
507 dataLog("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data());
508 break;
509 }
510 case op_init_lazy_reg: {
511 int r0 = (++it)->u.operand;
512 dataLog("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data());
513 break;
514 }
515 case op_get_callee: {
516 int r0 = (++it)->u.operand;
517 dataLog("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data());
518 break;
519 }
520 case op_create_this: {
521 int r0 = (++it)->u.operand;
522 int r1 = (++it)->u.operand;
523 dataLog("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
524 break;
525 }
526 case op_convert_this: {
527 int r0 = (++it)->u.operand;
528 dataLog("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data());
529 break;
530 }
531 case op_new_object: {
532 int r0 = (++it)->u.operand;
533 dataLog("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
534 break;
535 }
536 case op_new_array: {
537 int dst = (++it)->u.operand;
538 int argv = (++it)->u.operand;
539 int argc = (++it)->u.operand;
540 dataLog("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
541 break;
542 }
543 case op_new_array_buffer: {
544 int dst = (++it)->u.operand;
545 int argv = (++it)->u.operand;
546 int argc = (++it)->u.operand;
547 dataLog("[%4d] new_array_buffer %s, %d, %d\n", location, registerName(exec, dst).data(), argv, argc);
548 break;
549 }
550 case op_new_regexp: {
551 int r0 = (++it)->u.operand;
552 int re0 = (++it)->u.operand;
553 dataLog("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data());
554 if (r0 >=0 && r0 < (int)numberOfRegExps())
555 dataLog("%s\n", regexpName(re0, regexp(re0)).data());
556 else
557 dataLog("bad_regexp(%d)\n", re0);
558 break;
559 }
560 case op_mov: {
561 int r0 = (++it)->u.operand;
562 int r1 = (++it)->u.operand;
563 dataLog("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
564 break;
565 }
566 case op_not: {
567 printUnaryOp(exec, location, it, "not");
568 break;
569 }
570 case op_eq: {
571 printBinaryOp(exec, location, it, "eq");
572 break;
573 }
574 case op_eq_null: {
575 printUnaryOp(exec, location, it, "eq_null");
576 break;
577 }
578 case op_neq: {
579 printBinaryOp(exec, location, it, "neq");
580 break;
581 }
582 case op_neq_null: {
583 printUnaryOp(exec, location, it, "neq_null");
584 break;
585 }
586 case op_stricteq: {
587 printBinaryOp(exec, location, it, "stricteq");
588 break;
589 }
590 case op_nstricteq: {
591 printBinaryOp(exec, location, it, "nstricteq");
592 break;
593 }
594 case op_less: {
595 printBinaryOp(exec, location, it, "less");
596 break;
597 }
598 case op_lesseq: {
599 printBinaryOp(exec, location, it, "lesseq");
600 break;
601 }
602 case op_greater: {
603 printBinaryOp(exec, location, it, "greater");
604 break;
605 }
606 case op_greatereq: {
607 printBinaryOp(exec, location, it, "greatereq");
608 break;
609 }
610 case op_pre_inc: {
611 int r0 = (++it)->u.operand;
612 dataLog("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).data());
613 break;
614 }
615 case op_pre_dec: {
616 int r0 = (++it)->u.operand;
617 dataLog("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).data());
618 break;
619 }
620 case op_post_inc: {
621 printUnaryOp(exec, location, it, "post_inc");
622 break;
623 }
624 case op_post_dec: {
625 printUnaryOp(exec, location, it, "post_dec");
626 break;
627 }
628 case op_to_jsnumber: {
629 printUnaryOp(exec, location, it, "to_jsnumber");
630 break;
631 }
632 case op_negate: {
633 printUnaryOp(exec, location, it, "negate");
634 break;
635 }
636 case op_add: {
637 printBinaryOp(exec, location, it, "add");
638 ++it;
639 break;
640 }
641 case op_mul: {
642 printBinaryOp(exec, location, it, "mul");
643 ++it;
644 break;
645 }
646 case op_div: {
647 printBinaryOp(exec, location, it, "div");
648 ++it;
649 break;
650 }
651 case op_mod: {
652 printBinaryOp(exec, location, it, "mod");
653 break;
654 }
655 case op_sub: {
656 printBinaryOp(exec, location, it, "sub");
657 ++it;
658 break;
659 }
660 case op_lshift: {
661 printBinaryOp(exec, location, it, "lshift");
662 break;
663 }
664 case op_rshift: {
665 printBinaryOp(exec, location, it, "rshift");
666 break;
667 }
668 case op_urshift: {
669 printBinaryOp(exec, location, it, "urshift");
670 break;
671 }
672 case op_bitand: {
673 printBinaryOp(exec, location, it, "bitand");
674 ++it;
675 break;
676 }
677 case op_bitxor: {
678 printBinaryOp(exec, location, it, "bitxor");
679 ++it;
680 break;
681 }
682 case op_bitor: {
683 printBinaryOp(exec, location, it, "bitor");
684 ++it;
685 break;
686 }
687 case op_check_has_instance: {
688 int base = (++it)->u.operand;
689 dataLog("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data());
690 break;
691 }
692 case op_instanceof: {
693 int r0 = (++it)->u.operand;
694 int r1 = (++it)->u.operand;
695 int r2 = (++it)->u.operand;
696 int r3 = (++it)->u.operand;
697 dataLog("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data());
698 break;
699 }
700 case op_typeof: {
701 printUnaryOp(exec, location, it, "typeof");
702 break;
703 }
704 case op_is_undefined: {
705 printUnaryOp(exec, location, it, "is_undefined");
706 break;
707 }
708 case op_is_boolean: {
709 printUnaryOp(exec, location, it, "is_boolean");
710 break;
711 }
712 case op_is_number: {
713 printUnaryOp(exec, location, it, "is_number");
714 break;
715 }
716 case op_is_string: {
717 printUnaryOp(exec, location, it, "is_string");
718 break;
719 }
720 case op_is_object: {
721 printUnaryOp(exec, location, it, "is_object");
722 break;
723 }
724 case op_is_function: {
725 printUnaryOp(exec, location, it, "is_function");
726 break;
727 }
728 case op_in: {
729 printBinaryOp(exec, location, it, "in");
730 break;
731 }
732 case op_resolve: {
733 int r0 = (++it)->u.operand;
734 int id0 = (++it)->u.operand;
735 dataLog("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
736 it++;
737 break;
738 }
739 case op_resolve_skip: {
740 int r0 = (++it)->u.operand;
741 int id0 = (++it)->u.operand;
742 int skipLevels = (++it)->u.operand;
743 dataLog("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels);
744 it++;
745 break;
746 }
747 case op_resolve_global: {
748 int r0 = (++it)->u.operand;
749 int id0 = (++it)->u.operand;
750 dataLog("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
751 it += 3;
752 break;
753 }
754 case op_resolve_global_dynamic: {
755 int r0 = (++it)->u.operand;
756 int id0 = (++it)->u.operand;
757 JSValue scope = JSValue((++it)->u.jsCell.get());
758 ++it;
759 int depth = (++it)->u.operand;
760 dataLog("[%4d] resolve_global_dynamic\t %s, %s, %s, %d\n", location, registerName(exec, r0).data(), valueToSourceString(exec, scope).utf8().data(), idName(id0, m_identifiers[id0]).data(), depth);
761 ++it;
762 break;
763 }
764 case op_get_scoped_var: {
765 int r0 = (++it)->u.operand;
766 int index = (++it)->u.operand;
767 int skipLevels = (++it)->u.operand;
768 dataLog("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels);
769 it++;
770 break;
771 }
772 case op_put_scoped_var: {
773 int index = (++it)->u.operand;
774 int skipLevels = (++it)->u.operand;
775 int r0 = (++it)->u.operand;
776 dataLog("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).data());
777 break;
778 }
779 case op_get_global_var: {
780 int r0 = (++it)->u.operand;
781 int index = (++it)->u.operand;
782 dataLog("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index);
783 it++;
784 break;
785 }
786 case op_put_global_var: {
787 int index = (++it)->u.operand;
788 int r0 = (++it)->u.operand;
789 dataLog("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data());
790 break;
791 }
792 case op_resolve_base: {
793 int r0 = (++it)->u.operand;
794 int id0 = (++it)->u.operand;
795 int isStrict = (++it)->u.operand;
796 dataLog("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
797 it++;
798 break;
799 }
800 case op_ensure_property_exists: {
801 int r0 = (++it)->u.operand;
802 int id0 = (++it)->u.operand;
803 dataLog("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
804 break;
805 }
806 case op_resolve_with_base: {
807 int r0 = (++it)->u.operand;
808 int r1 = (++it)->u.operand;
809 int id0 = (++it)->u.operand;
810 dataLog("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
811 it++;
812 break;
813 }
814 case op_resolve_with_this: {
815 int r0 = (++it)->u.operand;
816 int r1 = (++it)->u.operand;
817 int id0 = (++it)->u.operand;
818 dataLog("[%4d] resolve_with_this %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
819 it++;
820 break;
821 }
822 case op_get_by_id: {
823 printGetByIdOp(exec, location, it, "get_by_id");
824 break;
825 }
826 case op_get_by_id_self: {
827 printGetByIdOp(exec, location, it, "get_by_id_self");
828 break;
829 }
830 case op_get_by_id_proto: {
831 printGetByIdOp(exec, location, it, "get_by_id_proto");
832 break;
833 }
834 case op_get_by_id_chain: {
835 printGetByIdOp(exec, location, it, "get_by_id_chain");
836 break;
837 }
838 case op_get_by_id_getter_self: {
839 printGetByIdOp(exec, location, it, "get_by_id_getter_self");
840 break;
841 }
842 case op_get_by_id_getter_proto: {
843 printGetByIdOp(exec, location, it, "get_by_id_getter_proto");
844 break;
845 }
846 case op_get_by_id_getter_chain: {
847 printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
848 break;
849 }
850 case op_get_by_id_custom_self: {
851 printGetByIdOp(exec, location, it, "get_by_id_custom_self");
852 break;
853 }
854 case op_get_by_id_custom_proto: {
855 printGetByIdOp(exec, location, it, "get_by_id_custom_proto");
856 break;
857 }
858 case op_get_by_id_custom_chain: {
859 printGetByIdOp(exec, location, it, "get_by_id_custom_chain");
860 break;
861 }
862 case op_get_by_id_generic: {
863 printGetByIdOp(exec, location, it, "get_by_id_generic");
864 break;
865 }
866 case op_get_array_length: {
867 printGetByIdOp(exec, location, it, "get_array_length");
868 break;
869 }
870 case op_get_string_length: {
871 printGetByIdOp(exec, location, it, "get_string_length");
872 break;
873 }
874 case op_get_arguments_length: {
875 printUnaryOp(exec, location, it, "get_arguments_length");
876 it++;
877 break;
878 }
879 case op_put_by_id: {
880 printPutByIdOp(exec, location, it, "put_by_id");
881 break;
882 }
883 case op_put_by_id_replace: {
884 printPutByIdOp(exec, location, it, "put_by_id_replace");
885 break;
886 }
887 case op_put_by_id_transition: {
888 printPutByIdOp(exec, location, it, "put_by_id_transition");
889 break;
890 }
891 case op_put_by_id_transition_direct: {
892 printPutByIdOp(exec, location, it, "put_by_id_transition_direct");
893 break;
894 }
895 case op_put_by_id_transition_normal: {
896 printPutByIdOp(exec, location, it, "put_by_id_transition_normal");
897 break;
898 }
899 case op_put_by_id_generic: {
900 printPutByIdOp(exec, location, it, "put_by_id_generic");
901 break;
902 }
903 case op_put_getter_setter: {
904 int r0 = (++it)->u.operand;
905 int id0 = (++it)->u.operand;
906 int r1 = (++it)->u.operand;
907 int r2 = (++it)->u.operand;
908 dataLog("[%4d] put_getter_setter\t %s, %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
909 break;
910 }
911 case op_method_check: {
912 dataLog("[%4d] method_check\n", location);
913 break;
914 }
915 case op_del_by_id: {
916 int r0 = (++it)->u.operand;
917 int r1 = (++it)->u.operand;
918 int id0 = (++it)->u.operand;
919 dataLog("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
920 break;
921 }
922 case op_get_by_val: {
923 int r0 = (++it)->u.operand;
924 int r1 = (++it)->u.operand;
925 int r2 = (++it)->u.operand;
926 dataLog("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
927 it++;
928 break;
929 }
930 case op_get_argument_by_val: {
931 int r0 = (++it)->u.operand;
932 int r1 = (++it)->u.operand;
933 int r2 = (++it)->u.operand;
934 dataLog("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
935 ++it;
936 break;
937 }
938 case op_get_by_pname: {
939 int r0 = (++it)->u.operand;
940 int r1 = (++it)->u.operand;
941 int r2 = (++it)->u.operand;
942 int r3 = (++it)->u.operand;
943 int r4 = (++it)->u.operand;
944 int r5 = (++it)->u.operand;
945 dataLog("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), registerName(exec, r4).data(), registerName(exec, r5).data());
946 break;
947 }
948 case op_put_by_val: {
949 int r0 = (++it)->u.operand;
950 int r1 = (++it)->u.operand;
951 int r2 = (++it)->u.operand;
952 dataLog("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
953 break;
954 }
955 case op_del_by_val: {
956 int r0 = (++it)->u.operand;
957 int r1 = (++it)->u.operand;
958 int r2 = (++it)->u.operand;
959 dataLog("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
960 break;
961 }
962 case op_put_by_index: {
963 int r0 = (++it)->u.operand;
964 unsigned n0 = (++it)->u.operand;
965 int r1 = (++it)->u.operand;
966 dataLog("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data());
967 break;
968 }
969 case op_jmp: {
970 int offset = (++it)->u.operand;
971 dataLog("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset);
972 break;
973 }
974 case op_loop: {
975 int offset = (++it)->u.operand;
976 dataLog("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset);
977 break;
978 }
979 case op_jtrue: {
980 printConditionalJump(exec, begin, it, location, "jtrue");
981 break;
982 }
983 case op_loop_if_true: {
984 printConditionalJump(exec, begin, it, location, "loop_if_true");
985 break;
986 }
987 case op_loop_if_false: {
988 printConditionalJump(exec, begin, it, location, "loop_if_false");
989 break;
990 }
991 case op_jfalse: {
992 printConditionalJump(exec, begin, it, location, "jfalse");
993 break;
994 }
995 case op_jeq_null: {
996 printConditionalJump(exec, begin, it, location, "jeq_null");
997 break;
998 }
999 case op_jneq_null: {
1000 printConditionalJump(exec, begin, it, location, "jneq_null");
1001 break;
1002 }
1003 case op_jneq_ptr: {
1004 int r0 = (++it)->u.operand;
1005 int r1 = (++it)->u.operand;
1006 int offset = (++it)->u.operand;
1007 dataLog("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1008 break;
1009 }
1010 case op_jless: {
1011 int r0 = (++it)->u.operand;
1012 int r1 = (++it)->u.operand;
1013 int offset = (++it)->u.operand;
1014 dataLog("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1015 break;
1016 }
1017 case op_jlesseq: {
1018 int r0 = (++it)->u.operand;
1019 int r1 = (++it)->u.operand;
1020 int offset = (++it)->u.operand;
1021 dataLog("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1022 break;
1023 }
1024 case op_jgreater: {
1025 int r0 = (++it)->u.operand;
1026 int r1 = (++it)->u.operand;
1027 int offset = (++it)->u.operand;
1028 dataLog("[%4d] jgreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1029 break;
1030 }
1031 case op_jgreatereq: {
1032 int r0 = (++it)->u.operand;
1033 int r1 = (++it)->u.operand;
1034 int offset = (++it)->u.operand;
1035 dataLog("[%4d] jgreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1036 break;
1037 }
1038 case op_jnless: {
1039 int r0 = (++it)->u.operand;
1040 int r1 = (++it)->u.operand;
1041 int offset = (++it)->u.operand;
1042 dataLog("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1043 break;
1044 }
1045 case op_jnlesseq: {
1046 int r0 = (++it)->u.operand;
1047 int r1 = (++it)->u.operand;
1048 int offset = (++it)->u.operand;
1049 dataLog("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1050 break;
1051 }
1052 case op_jngreater: {
1053 int r0 = (++it)->u.operand;
1054 int r1 = (++it)->u.operand;
1055 int offset = (++it)->u.operand;
1056 dataLog("[%4d] jngreater\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1057 break;
1058 }
1059 case op_jngreatereq: {
1060 int r0 = (++it)->u.operand;
1061 int r1 = (++it)->u.operand;
1062 int offset = (++it)->u.operand;
1063 dataLog("[%4d] jngreatereq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1064 break;
1065 }
1066 case op_loop_if_less: {
1067 int r0 = (++it)->u.operand;
1068 int r1 = (++it)->u.operand;
1069 int offset = (++it)->u.operand;
1070 dataLog("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1071 break;
1072 }
1073 case op_loop_if_lesseq: {
1074 int r0 = (++it)->u.operand;
1075 int r1 = (++it)->u.operand;
1076 int offset = (++it)->u.operand;
1077 dataLog("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1078 break;
1079 }
1080 case op_loop_if_greater: {
1081 int r0 = (++it)->u.operand;
1082 int r1 = (++it)->u.operand;
1083 int offset = (++it)->u.operand;
1084 dataLog("[%4d] loop_if_greater\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1085 break;
1086 }
1087 case op_loop_if_greatereq: {
1088 int r0 = (++it)->u.operand;
1089 int r1 = (++it)->u.operand;
1090 int offset = (++it)->u.operand;
1091 dataLog("[%4d] loop_if_greatereq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1092 break;
1093 }
1094 case op_loop_hint: {
1095 dataLog("[%4d] loop_hint\n", location);
1096 break;
1097 }
1098 case op_switch_imm: {
1099 int tableIndex = (++it)->u.operand;
1100 int defaultTarget = (++it)->u.operand;
1101 int scrutineeRegister = (++it)->u.operand;
1102 dataLog("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1103 break;
1104 }
1105 case op_switch_char: {
1106 int tableIndex = (++it)->u.operand;
1107 int defaultTarget = (++it)->u.operand;
1108 int scrutineeRegister = (++it)->u.operand;
1109 dataLog("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1110 break;
1111 }
1112 case op_switch_string: {
1113 int tableIndex = (++it)->u.operand;
1114 int defaultTarget = (++it)->u.operand;
1115 int scrutineeRegister = (++it)->u.operand;
1116 dataLog("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1117 break;
1118 }
1119 case op_new_func: {
1120 int r0 = (++it)->u.operand;
1121 int f0 = (++it)->u.operand;
1122 int shouldCheck = (++it)->u.operand;
1123 dataLog("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
1124 break;
1125 }
1126 case op_new_func_exp: {
1127 int r0 = (++it)->u.operand;
1128 int f0 = (++it)->u.operand;
1129 dataLog("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).data(), f0);
1130 break;
1131 }
1132 case op_call: {
1133 printCallOp(exec, location, it, "call");
1134 break;
1135 }
1136 case op_call_eval: {
1137 printCallOp(exec, location, it, "call_eval");
1138 break;
1139 }
1140 case op_call_varargs: {
1141 int callee = (++it)->u.operand;
1142 int thisValue = (++it)->u.operand;
1143 int arguments = (++it)->u.operand;
1144 int firstFreeRegister = (++it)->u.operand;
1145 dataLog("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(exec, callee).data(), registerName(exec, thisValue).data(), registerName(exec, arguments).data(), firstFreeRegister);
1146 break;
1147 }
1148 case op_tear_off_activation: {
1149 int r0 = (++it)->u.operand;
1150 int r1 = (++it)->u.operand;
1151 dataLog("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1152 break;
1153 }
1154 case op_tear_off_arguments: {
1155 int r0 = (++it)->u.operand;
1156 dataLog("[%4d] tear_off_arguments %s\n", location, registerName(exec, r0).data());
1157 break;
1158 }
1159 case op_ret: {
1160 int r0 = (++it)->u.operand;
1161 dataLog("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data());
1162 break;
1163 }
1164 case op_call_put_result: {
1165 int r0 = (++it)->u.operand;
1166 dataLog("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
1167 it++;
1168 break;
1169 }
1170 case op_ret_object_or_this: {
1171 int r0 = (++it)->u.operand;
1172 int r1 = (++it)->u.operand;
1173 dataLog("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1174 break;
1175 }
1176 case op_construct: {
1177 printCallOp(exec, location, it, "construct");
1178 break;
1179 }
1180 case op_strcat: {
1181 int r0 = (++it)->u.operand;
1182 int r1 = (++it)->u.operand;
1183 int count = (++it)->u.operand;
1184 dataLog("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count);
1185 break;
1186 }
1187 case op_to_primitive: {
1188 int r0 = (++it)->u.operand;
1189 int r1 = (++it)->u.operand;
1190 dataLog("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1191 break;
1192 }
1193 case op_get_pnames: {
1194 int r0 = it[1].u.operand;
1195 int r1 = it[2].u.operand;
1196 int r2 = it[3].u.operand;
1197 int r3 = it[4].u.operand;
1198 int offset = it[5].u.operand;
1199 dataLog("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data(), registerName(exec, r3).data(), offset, location + offset);
1200 it += OPCODE_LENGTH(op_get_pnames) - 1;
1201 break;
1202 }
1203 case op_next_pname: {
1204 int dest = it[1].u.operand;
1205 int base = it[2].u.operand;
1206 int i = it[3].u.operand;
1207 int size = it[4].u.operand;
1208 int iter = it[5].u.operand;
1209 int offset = it[6].u.operand;
1210 dataLog("[%4d] next_pname\t %s, %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, dest).data(), registerName(exec, base).data(), registerName(exec, i).data(), registerName(exec, size).data(), registerName(exec, iter).data(), offset, location + offset);
1211 it += OPCODE_LENGTH(op_next_pname) - 1;
1212 break;
1213 }
1214 case op_push_scope: {
1215 int r0 = (++it)->u.operand;
1216 dataLog("[%4d] push_scope\t %s\n", location, registerName(exec, r0).data());
1217 break;
1218 }
1219 case op_pop_scope: {
1220 dataLog("[%4d] pop_scope\n", location);
1221 break;
1222 }
1223 case op_push_new_scope: {
1224 int r0 = (++it)->u.operand;
1225 int id0 = (++it)->u.operand;
1226 int r1 = (++it)->u.operand;
1227 dataLog("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
1228 break;
1229 }
1230 case op_jmp_scopes: {
1231 int scopeDelta = (++it)->u.operand;
1232 int offset = (++it)->u.operand;
1233 dataLog("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset);
1234 break;
1235 }
1236 case op_catch: {
1237 int r0 = (++it)->u.operand;
1238 dataLog("[%4d] catch\t\t %s\n", location, registerName(exec, r0).data());
1239 break;
1240 }
1241 case op_throw: {
1242 int r0 = (++it)->u.operand;
1243 dataLog("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data());
1244 break;
1245 }
1246 case op_throw_reference_error: {
1247 int k0 = (++it)->u.operand;
1248 dataLog("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data());
1249 break;
1250 }
1251 case op_debug: {
1252 int debugHookID = (++it)->u.operand;
1253 int firstLine = (++it)->u.operand;
1254 int lastLine = (++it)->u.operand;
1255 dataLog("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1256 break;
1257 }
1258 case op_profile_will_call: {
1259 int function = (++it)->u.operand;
1260 dataLog("[%4d] profile_will_call %s\n", location, registerName(exec, function).data());
1261 break;
1262 }
1263 case op_profile_did_call: {
1264 int function = (++it)->u.operand;
1265 dataLog("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).data());
1266 break;
1267 }
1268 case op_end: {
1269 int r0 = (++it)->u.operand;
1270 dataLog("[%4d] end\t\t %s\n", location, registerName(exec, r0).data());
1271 break;
1272 }
1273 }
1274}
1275
1276#if DUMP_CODE_BLOCK_STATISTICS
1277static HashSet<CodeBlock*> liveCodeBlockSet;
1278#endif
1279
1280#define FOR_EACH_MEMBER_VECTOR(macro) \
1281 macro(instructions) \
1282 macro(globalResolveInfos) \
1283 macro(structureStubInfos) \
1284 macro(callLinkInfos) \
1285 macro(linkedCallerList) \
1286 macro(identifiers) \
1287 macro(functionExpressions) \
1288 macro(constantRegisters)
1289
1290#define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1291 macro(regexps) \
1292 macro(functions) \
1293 macro(exceptionHandlers) \
1294 macro(immediateSwitchJumpTables) \
1295 macro(characterSwitchJumpTables) \
1296 macro(stringSwitchJumpTables) \
1297 macro(evalCodeCache) \
1298 macro(expressionInfo) \
1299 macro(lineInfo) \
1300 macro(callReturnIndexVector)
1301
1302template<typename T>
1303static size_t sizeInBytes(const Vector<T>& vector)
1304{
1305 return vector.capacity() * sizeof(T);
1306}
1307
1308void CodeBlock::dumpStatistics()
1309{
1310#if DUMP_CODE_BLOCK_STATISTICS
1311 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1312 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1313 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1314 #undef DEFINE_VARS
1315
1316 // Non-vector data members
1317 size_t evalCodeCacheIsNotEmpty = 0;
1318
1319 size_t symbolTableIsNotEmpty = 0;
1320 size_t symbolTableTotalSize = 0;
1321
1322 size_t hasRareData = 0;
1323
1324 size_t isFunctionCode = 0;
1325 size_t isGlobalCode = 0;
1326 size_t isEvalCode = 0;
1327
1328 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1329 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1330 CodeBlock* codeBlock = *it;
1331
1332 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1333 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1334 #undef GET_STATS
1335
1336 if (!codeBlock->m_symbolTable.isEmpty()) {
1337 symbolTableIsNotEmpty++;
1338 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1339 }
1340
1341 if (codeBlock->m_rareData) {
1342 hasRareData++;
1343 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1344 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1345 #undef GET_STATS
1346
1347 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1348 evalCodeCacheIsNotEmpty++;
1349 }
1350
1351 switch (codeBlock->codeType()) {
1352 case FunctionCode:
1353 ++isFunctionCode;
1354 break;
1355 case GlobalCode:
1356 ++isGlobalCode;
1357 break;
1358 case EvalCode:
1359 ++isEvalCode;
1360 break;
1361 }
1362 }
1363
1364 size_t totalSize = 0;
1365
1366 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1367 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1368 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1369 #undef GET_TOTAL_SIZE
1370
1371 totalSize += symbolTableTotalSize;
1372 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1373
1374 dataLog("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1375 dataLog("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1376 dataLog("Size of all CodeBlocks: %zu\n", totalSize);
1377 dataLog("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1378
1379 dataLog("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1380 dataLog("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1381 dataLog("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1382
1383 dataLog("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1384
1385 #define PRINT_STATS(name) dataLog("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); dataLog("Size of all " #name ": %zu\n", name##TotalSize);
1386 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1387 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1388 #undef PRINT_STATS
1389
1390 dataLog("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1391 dataLog("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1392
1393 dataLog("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1394
1395#else
1396 dataLog("Dumping CodeBlock statistics is not enabled.\n");
1397#endif
1398}
1399
1400CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
1401 : m_globalObject(other.m_globalObject)
1402 , m_heap(other.m_heap)
1403 , m_numCalleeRegisters(other.m_numCalleeRegisters)
1404 , m_numVars(other.m_numVars)
1405 , m_numCapturedVars(other.m_numCapturedVars)
1406 , m_isConstructor(other.m_isConstructor)
1407 , m_ownerExecutable(*other.m_globalData, other.m_ownerExecutable.get(), other.m_ownerExecutable.get())
1408 , m_globalData(other.m_globalData)
1409 , m_instructions(other.m_instructions)
1410 , m_thisRegister(other.m_thisRegister)
1411 , m_argumentsRegister(other.m_argumentsRegister)
1412 , m_activationRegister(other.m_activationRegister)
1413 , m_needsFullScopeChain(other.m_needsFullScopeChain)
1414 , m_usesEval(other.m_usesEval)
1415 , m_isNumericCompareFunction(other.m_isNumericCompareFunction)
1416 , m_isStrictMode(other.m_isStrictMode)
1417 , m_codeType(other.m_codeType)
1418 , m_source(other.m_source)
1419 , m_sourceOffset(other.m_sourceOffset)
1420#if ENABLE(JIT)
1421 , m_globalResolveInfos(other.m_globalResolveInfos)
1422#endif
1423#if ENABLE(VALUE_PROFILER)
1424 , m_executionEntryCount(0)
1425#endif
1426 , m_jumpTargets(other.m_jumpTargets)
1427 , m_loopTargets(other.m_loopTargets)
1428 , m_identifiers(other.m_identifiers)
1429 , m_constantRegisters(other.m_constantRegisters)
1430 , m_functionDecls(other.m_functionDecls)
1431 , m_functionExprs(other.m_functionExprs)
1432 , m_symbolTable(symTab)
1433 , m_speculativeSuccessCounter(0)
1434 , m_speculativeFailCounter(0)
1435 , m_forcedOSRExitCounter(0)
1436 , m_optimizationDelayCounter(0)
1437 , m_reoptimizationRetryCounter(0)
1438#if ENABLE(JIT)
1439 , m_canCompileWithDFGState(CompileWithDFGUnset)
1440#endif
1441{
1442 setNumParameters(other.numParameters());
1443 optimizeAfterWarmUp();
1444 jitAfterWarmUp();
1445
1446 if (other.m_rareData) {
1447 createRareDataIfNecessary();
1448
1449 m_rareData->m_exceptionHandlers = other.m_rareData->m_exceptionHandlers;
1450 m_rareData->m_regexps = other.m_rareData->m_regexps;
1451 m_rareData->m_constantBuffers = other.m_rareData->m_constantBuffers;
1452 m_rareData->m_immediateSwitchJumpTables = other.m_rareData->m_immediateSwitchJumpTables;
1453 m_rareData->m_characterSwitchJumpTables = other.m_rareData->m_characterSwitchJumpTables;
1454 m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables;
1455 m_rareData->m_expressionInfo = other.m_rareData->m_expressionInfo;
1456 m_rareData->m_lineInfo = other.m_rareData->m_lineInfo;
1457 }
1458}
1459
1460CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor, PassOwnPtr<CodeBlock> alternative)
1461 : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject)
1462 , m_heap(&m_globalObject->globalData().heap)
1463 , m_numCalleeRegisters(0)
1464 , m_numVars(0)
1465 , m_isConstructor(isConstructor)
1466 , m_numParameters(0)
1467 , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
1468 , m_globalData(0)
1469 , m_argumentsRegister(-1)
1470 , m_needsFullScopeChain(ownerExecutable->needsActivation())
1471 , m_usesEval(ownerExecutable->usesEval())
1472 , m_isNumericCompareFunction(false)
1473 , m_isStrictMode(ownerExecutable->isStrictMode())
1474 , m_codeType(codeType)
1475 , m_source(sourceProvider)
1476 , m_sourceOffset(sourceOffset)
1477#if ENABLE(VALUE_PROFILER)
1478 , m_executionEntryCount(0)
1479#endif
1480 , m_symbolTable(symTab)
1481 , m_alternative(alternative)
1482 , m_speculativeSuccessCounter(0)
1483 , m_speculativeFailCounter(0)
1484 , m_optimizationDelayCounter(0)
1485 , m_reoptimizationRetryCounter(0)
1486{
1487 ASSERT(m_source);
1488
1489 optimizeAfterWarmUp();
1490 jitAfterWarmUp();
1491
1492#if DUMP_CODE_BLOCK_STATISTICS
1493 liveCodeBlockSet.add(this);
1494#endif
1495}
1496
1497CodeBlock::~CodeBlock()
1498{
1499#if ENABLE(DFG_JIT)
1500 // Remove myself from the set of DFG code blocks. Note that I may not be in this set
1501 // (because I'm not a DFG code block), in which case this is a no-op anyway.
1502 m_globalData->heap.m_dfgCodeBlocks.m_set.remove(this);
1503#endif
1504
1505#if ENABLE(VERBOSE_VALUE_PROFILE)
1506 dumpValueProfiles();
1507#endif
1508
1509#if ENABLE(LLINT)
1510 while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end())
1511 m_incomingLLIntCalls.begin()->remove();
1512#endif // ENABLE(LLINT)
1513#if ENABLE(JIT)
1514 // We may be destroyed before any CodeBlocks that refer to us are destroyed.
1515 // Consider that two CodeBlocks become unreachable at the same time. There
1516 // is no guarantee about the order in which the CodeBlocks are destroyed.
1517 // So, if we don't remove incoming calls, and get destroyed before the
1518 // CodeBlock(s) that have calls into us, then the CallLinkInfo vector's
1519 // destructor will try to remove nodes from our (no longer valid) linked list.
1520 while (m_incomingCalls.begin() != m_incomingCalls.end())
1521 m_incomingCalls.begin()->remove();
1522
1523 // Note that our outgoing calls will be removed from other CodeBlocks'
1524 // m_incomingCalls linked lists through the execution of the ~CallLinkInfo
1525 // destructors.
1526
1527 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1528 m_structureStubInfos[i].deref();
1529#endif // ENABLE(JIT)
1530
1531#if DUMP_CODE_BLOCK_STATISTICS
1532 liveCodeBlockSet.remove(this);
1533#endif
1534}
1535
1536void CodeBlock::setNumParameters(int newValue)
1537{
1538 m_numParameters = newValue;
1539
1540#if ENABLE(VALUE_PROFILER)
1541 m_argumentValueProfiles.resize(newValue);
1542#endif
1543}
1544
1545void CodeBlock::addParameter()
1546{
1547 m_numParameters++;
1548
1549#if ENABLE(VALUE_PROFILER)
1550 m_argumentValueProfiles.append(ValueProfile());
1551#endif
1552}
1553
1554void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) const
1555{
1556 Interpreter* interpreter = m_globalData->interpreter;
1557
1558 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) && vPC[4].u.structure) {
1559 visitor.append(&vPC[4].u.structure);
1560 return;
1561 }
1562
1563 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
1564 visitor.append(&vPC[4].u.structure);
1565 return;
1566 }
1567 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto)) {
1568 visitor.append(&vPC[4].u.structure);
1569 visitor.append(&vPC[5].u.structure);
1570 return;
1571 }
1572 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_chain)) {
1573 visitor.append(&vPC[4].u.structure);
1574 if (vPC[5].u.structureChain)
1575 visitor.append(&vPC[5].u.structureChain);
1576 return;
1577 }
1578 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1579 visitor.append(&vPC[4].u.structure);
1580 visitor.append(&vPC[5].u.structure);
1581 if (vPC[6].u.structureChain)
1582 visitor.append(&vPC[6].u.structureChain);
1583 return;
1584 }
1585 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) && vPC[4].u.structure) {
1586 visitor.append(&vPC[4].u.structure);
1587 return;
1588 }
1589 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1590 visitor.append(&vPC[4].u.structure);
1591 return;
1592 }
1593 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global) || vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
1594 if (vPC[3].u.structure)
1595 visitor.append(&vPC[3].u.structure);
1596 return;
1597 }
1598
1599 // These instructions don't ref their Structures.
1600 ASSERT(vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == interpreter->getOpcode(op_get_array_length) || vPC[0].u.opcode == interpreter->getOpcode(op_get_string_length));
1601}
1602
1603void EvalCodeCache::visitAggregate(SlotVisitor& visitor)
1604{
1605 EvalCacheMap::iterator end = m_cacheMap.end();
1606 for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr)
1607 visitor.append(&ptr->second);
1608}
1609
1610void CodeBlock::visitAggregate(SlotVisitor& visitor)
1611{
1612#if ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
1613 if (!!m_dfgData) {
1614 // I may be asked to scan myself more than once, and it may even happen concurrently.
1615 // To this end, use a CAS loop to check if I've been called already. Only one thread
1616 // may proceed past this point - whichever one wins the CAS race.
1617 unsigned oldValue;
1618 do {
1619 oldValue = m_dfgData->visitAggregateHasBeenCalled;
1620 if (oldValue) {
1621 // Looks like someone else won! Return immediately to ensure that we don't
1622 // trace the same CodeBlock concurrently. Doing so is hazardous since we will
1623 // be mutating the state of ValueProfiles, which contain JSValues, which can
1624 // have word-tearing on 32-bit, leading to awesome timing-dependent crashes
1625 // that are nearly impossible to track down.
1626
1627 // Also note that it must be safe to return early as soon as we see the
1628 // value true (well, (unsigned)1), since once a GC thread is in this method
1629 // and has won the CAS race (i.e. was responsible for setting the value true)
1630 // it will definitely complete the rest of this method before declaring
1631 // termination.
1632 return;
1633 }
1634 } while (!WTF::weakCompareAndSwap(&m_dfgData->visitAggregateHasBeenCalled, 0, 1));
1635 }
1636#endif // ENABLE(PARALLEL_GC) && ENABLE(DFG_JIT)
1637
1638 if (!!m_alternative)
1639 m_alternative->visitAggregate(visitor);
1640
1641 // There are three things that may use unconditional finalizers: lazy bytecode freeing,
1642 // inline cache clearing, and jettisoning. The probability of us wanting to do at
1643 // least one of those things is probably quite close to 1. So we add one no matter what
1644 // and when it runs, it figures out whether it has any work to do.
1645 visitor.addUnconditionalFinalizer(this);
1646
1647 if (shouldImmediatelyAssumeLivenessDuringScan()) {
1648 // This code block is live, so scan all references strongly and return.
1649 stronglyVisitStrongReferences(visitor);
1650 stronglyVisitWeakReferences(visitor);
1651 return;
1652 }
1653
1654#if ENABLE(DFG_JIT)
1655 // We get here if we're live in the sense that our owner executable is live,
1656 // but we're not yet live for sure in another sense: we may yet decide that this
1657 // code block should be jettisoned based on its outgoing weak references being
1658 // stale. Set a flag to indicate that we're still assuming that we're dead, and
1659 // perform one round of determining if we're live. The GC may determine, based on
1660 // either us marking additional objects, or by other objects being marked for
1661 // other reasons, that this iteration should run again; it will notify us of this
1662 // decision by calling harvestWeakReferences().
1663
1664 m_dfgData->livenessHasBeenProved = false;
1665 m_dfgData->allTransitionsHaveBeenMarked = false;
1666
1667 performTracingFixpointIteration(visitor);
1668
1669 // GC doesn't have enough information yet for us to decide whether to keep our DFG
1670 // data, so we need to register a handler to run again at the end of GC, when more
1671 // information is available.
1672 if (!(m_dfgData->livenessHasBeenProved && m_dfgData->allTransitionsHaveBeenMarked))
1673 visitor.addWeakReferenceHarvester(this);
1674
1675#else // ENABLE(DFG_JIT)
1676 ASSERT_NOT_REACHED();
1677#endif // ENABLE(DFG_JIT)
1678}
1679
1680void CodeBlock::performTracingFixpointIteration(SlotVisitor& visitor)
1681{
1682 UNUSED_PARAM(visitor);
1683
1684#if ENABLE(DFG_JIT)
1685 // Evaluate our weak reference transitions, if there are still some to evaluate.
1686 if (!m_dfgData->allTransitionsHaveBeenMarked) {
1687 bool allAreMarkedSoFar = true;
1688 for (unsigned i = 0; i < m_dfgData->transitions.size(); ++i) {
1689 if ((!m_dfgData->transitions[i].m_codeOrigin
1690 || Heap::isMarked(m_dfgData->transitions[i].m_codeOrigin.get()))
1691 && Heap::isMarked(m_dfgData->transitions[i].m_from.get())) {
1692 // If the following three things are live, then the target of the
1693 // transition is also live:
1694 // - This code block. We know it's live already because otherwise
1695 // we wouldn't be scanning ourselves.
1696 // - The code origin of the transition. Transitions may arise from
1697 // code that was inlined. They are not relevant if the user's
1698 // object that is required for the inlinee to run is no longer
1699 // live.
1700 // - The source of the transition. The transition checks if some
1701 // heap location holds the source, and if so, stores the target.
1702 // Hence the source must be live for the transition to be live.
1703 visitor.append(&m_dfgData->transitions[i].m_to);
1704 } else
1705 allAreMarkedSoFar = false;
1706 }
1707
1708 if (allAreMarkedSoFar)
1709 m_dfgData->allTransitionsHaveBeenMarked = true;
1710 }
1711
1712 // Check if we have any remaining work to do.
1713 if (m_dfgData->livenessHasBeenProved)
1714 return;
1715
1716 // Now check all of our weak references. If all of them are live, then we
1717 // have proved liveness and so we scan our strong references. If at end of
1718 // GC we still have not proved liveness, then this code block is toast.
1719 bool allAreLiveSoFar = true;
1720 for (unsigned i = 0; i < m_dfgData->weakReferences.size(); ++i) {
1721 if (!Heap::isMarked(m_dfgData->weakReferences[i].get())) {
1722 allAreLiveSoFar = false;
1723 break;
1724 }
1725 }
1726
1727 // If some weak references are dead, then this fixpoint iteration was
1728 // unsuccessful.
1729 if (!allAreLiveSoFar)
1730 return;
1731
1732 // All weak references are live. Record this information so we don't
1733 // come back here again, and scan the strong references.
1734 m_dfgData->livenessHasBeenProved = true;
1735 stronglyVisitStrongReferences(visitor);
1736#endif // ENABLE(DFG_JIT)
1737}
1738
1739void CodeBlock::visitWeakReferences(SlotVisitor& visitor)
1740{
1741 performTracingFixpointIteration(visitor);
1742}
1743
1744void CodeBlock::finalizeUnconditionally()
1745{
1746#if ENABLE(JIT)
1747#if ENABLE(JIT_VERBOSE_OSR)
1748 static const bool verboseUnlinking = true;
1749#else
1750 static const bool verboseUnlinking = false;
1751#endif
1752#endif // ENABLE(JIT)
1753
1754#if ENABLE(LLINT)
1755 Interpreter* interpreter = m_globalData->interpreter;
1756 // interpreter->classicEnabled() returns true if the old C++ interpreter is enabled. If that's enabled
1757 // then we're not using LLInt.
1758 if (!interpreter->classicEnabled() && !!numberOfInstructions()) {
1759 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) {
1760 Instruction* curInstruction = &instructions()[m_propertyAccessInstructions[i]];
1761 switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) {
1762 case op_get_by_id:
1763 case op_put_by_id:
1764 if (!curInstruction[4].u.structure || Heap::isMarked(curInstruction[4].u.structure.get()))
1765 break;
1766 if (verboseUnlinking)
1767 dataLog("Clearing LLInt property access with structure %p.\n", curInstruction[4].u.structure.get());
1768 curInstruction[4].u.structure.clear();
1769 curInstruction[5].u.operand = 0;
1770 break;
1771 case op_put_by_id_transition_direct:
1772 case op_put_by_id_transition_normal:
1773 if (Heap::isMarked(curInstruction[4].u.structure.get())
1774 && Heap::isMarked(curInstruction[6].u.structure.get())
1775 && Heap::isMarked(curInstruction[7].u.structureChain.get()))
1776 break;
1777 if (verboseUnlinking) {
1778 dataLog("Clearing LLInt put transition with structures %p -> %p, chain %p.\n",
1779 curInstruction[4].u.structure.get(),
1780 curInstruction[6].u.structure.get(),
1781 curInstruction[7].u.structureChain.get());
1782 }
1783 curInstruction[4].u.structure.clear();
1784 curInstruction[6].u.structure.clear();
1785 curInstruction[7].u.structureChain.clear();
1786 curInstruction[0].u.opcode = interpreter->getOpcode(op_put_by_id);
1787 break;
1788 default:
1789 ASSERT_NOT_REACHED();
1790 }
1791 }
1792 for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i) {
1793 Instruction* curInstruction = &instructions()[m_globalResolveInstructions[i]];
1794 ASSERT(interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global
1795 || interpreter->getOpcodeID(curInstruction[0].u.opcode) == op_resolve_global_dynamic);
1796 if (!curInstruction[3].u.structure || Heap::isMarked(curInstruction[3].u.structure.get()))
1797 continue;
1798 if (verboseUnlinking)
1799 dataLog("Clearing LLInt global resolve cache with structure %p.\n", curInstruction[3].u.structure.get());
1800 curInstruction[3].u.structure.clear();
1801 curInstruction[4].u.operand = 0;
1802 }
1803 for (unsigned i = 0; i < m_llintCallLinkInfos.size(); ++i) {
1804 if (m_llintCallLinkInfos[i].isLinked() && !Heap::isMarked(m_llintCallLinkInfos[i].callee.get())) {
1805 if (verboseUnlinking)
1806 dataLog("Clearing LLInt call from %p.\n", this);
1807 m_llintCallLinkInfos[i].unlink();
1808 }
1809 if (!!m_llintCallLinkInfos[i].lastSeenCallee && !Heap::isMarked(m_llintCallLinkInfos[i].lastSeenCallee.get()))
1810 m_llintCallLinkInfos[i].lastSeenCallee.clear();
1811 }
1812 }
1813#endif // ENABLE(LLINT)
1814
1815#if ENABLE(DFG_JIT)
1816 // Check if we're not live. If we are, then jettison.
1817 if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData->livenessHasBeenProved)) {
1818 if (verboseUnlinking)
1819 dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this);
1820
1821 // Make sure that the baseline JIT knows that it should re-warm-up before
1822 // optimizing.
1823 alternative()->optimizeAfterWarmUp();
1824
1825 jettison();
1826 return;
1827 }
1828#endif // ENABLE(DFG_JIT)
1829
1830#if ENABLE(JIT)
1831 // Handle inline caches.
1832 if (!!getJITCode()) {
1833 RepatchBuffer repatchBuffer(this);
1834 for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i) {
1835 if (callLinkInfo(i).isLinked() && !Heap::isMarked(callLinkInfo(i).callee.get())) {
1836 if (verboseUnlinking)
1837 dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get());
1838 callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
1839 }
1840 if (!!callLinkInfo(i).lastSeenCallee
1841 && !Heap::isMarked(callLinkInfo(i).lastSeenCallee.get()))
1842 callLinkInfo(i).lastSeenCallee.clear();
1843 }
1844 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1845 if (m_globalResolveInfos[i].structure && !Heap::isMarked(m_globalResolveInfos[i].structure.get())) {
1846 if (verboseUnlinking)
1847 dataLog("Clearing resolve info in %p.\n", this);
1848 m_globalResolveInfos[i].structure.clear();
1849 }
1850 }
1851
1852 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i) {
1853 StructureStubInfo& stubInfo = m_structureStubInfos[i];
1854
1855 AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
1856
1857 if (stubInfo.visitWeakReferences())
1858 continue;
1859
1860 if (verboseUnlinking)
1861 dataLog("Clearing structure cache (kind %d) in %p.\n", stubInfo.accessType, this);
1862
1863 if (isGetByIdAccess(accessType)) {
1864 if (getJITCode().jitType() == JITCode::DFGJIT)
1865 DFG::dfgResetGetByID(repatchBuffer, stubInfo);
1866 else
1867 JIT::resetPatchGetById(repatchBuffer, &stubInfo);
1868 } else {
1869 ASSERT(isPutByIdAccess(accessType));
1870 if (getJITCode().jitType() == JITCode::DFGJIT)
1871 DFG::dfgResetPutByID(repatchBuffer, stubInfo);
1872 else
1873 JIT::resetPatchPutById(repatchBuffer, &stubInfo);
1874 }
1875
1876 stubInfo.reset();
1877 }
1878
1879 for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
1880 if (!m_methodCallLinkInfos[i].cachedStructure)
1881 continue;
1882
1883 ASSERT(m_methodCallLinkInfos[i].seenOnce());
1884 ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
1885
1886 if (!Heap::isMarked(m_methodCallLinkInfos[i].cachedStructure.get())
1887 || !Heap::isMarked(m_methodCallLinkInfos[i].cachedPrototypeStructure.get())
1888 || !Heap::isMarked(m_methodCallLinkInfos[i].cachedFunction.get())
1889 || !Heap::isMarked(m_methodCallLinkInfos[i].cachedPrototype.get())) {
1890 if (verboseUnlinking)
1891 dataLog("Clearing method call in %p.\n", this);
1892 m_methodCallLinkInfos[i].reset(repatchBuffer, getJITType());
1893
1894 StructureStubInfo& stubInfo = getStubInfo(m_methodCallLinkInfos[i].bytecodeIndex);
1895
1896 AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
1897
1898 if (accessType != access_unset) {
1899 ASSERT(isGetByIdAccess(accessType));
1900 if (getJITCode().jitType() == JITCode::DFGJIT)
1901 DFG::dfgResetGetByID(repatchBuffer, stubInfo);
1902 else
1903 JIT::resetPatchGetById(repatchBuffer, &stubInfo);
1904 stubInfo.reset();
1905 }
1906 }
1907 }
1908 }
1909#endif
1910}
1911
1912void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
1913{
1914 visitor.append(&m_globalObject);
1915 visitor.append(&m_ownerExecutable);
1916 if (m_rareData) {
1917 m_rareData->m_evalCodeCache.visitAggregate(visitor);
1918 size_t regExpCount = m_rareData->m_regexps.size();
1919 WriteBarrier<RegExp>* regexps = m_rareData->m_regexps.data();
1920 for (size_t i = 0; i < regExpCount; i++)
1921 visitor.append(regexps + i);
1922 }
1923 visitor.appendValues(m_constantRegisters.data(), m_constantRegisters.size());
1924 for (size_t i = 0; i < m_functionExprs.size(); ++i)
1925 visitor.append(&m_functionExprs[i]);
1926 for (size_t i = 0; i < m_functionDecls.size(); ++i)
1927 visitor.append(&m_functionDecls[i]);
1928#if ENABLE(CLASSIC_INTERPRETER)
1929 if (m_globalData->interpreter->classicEnabled() && !!numberOfInstructions()) {
1930 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1931 visitStructures(visitor, &instructions()[m_propertyAccessInstructions[i]]);
1932 for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
1933 visitStructures(visitor, &instructions()[m_globalResolveInstructions[i]]);
1934 }
1935#endif
1936
1937#if ENABLE(DFG_JIT)
1938 if (hasCodeOrigins()) {
1939 // Make sure that executables that we have inlined don't die.
1940 // FIXME: If they would have otherwise died, we should probably trigger recompilation.
1941 for (size_t i = 0; i < inlineCallFrames().size(); ++i) {
1942 InlineCallFrame& inlineCallFrame = inlineCallFrames()[i];
1943 visitor.append(&inlineCallFrame.executable);
1944 visitor.append(&inlineCallFrame.callee);
1945 }
1946 }
1947
1948 m_lazyOperandValueProfiles.computeUpdatedPredictions();
1949#endif
1950
1951#if ENABLE(VALUE_PROFILER)
1952 for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
1953 valueProfileForArgument(profileIndex)->computeUpdatedPrediction();
1954 for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
1955 valueProfile(profileIndex)->computeUpdatedPrediction();
1956#endif
1957}
1958
1959void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor)
1960{
1961 UNUSED_PARAM(visitor);
1962
1963#if ENABLE(DFG_JIT)
1964 if (!m_dfgData)
1965 return;
1966
1967 for (unsigned i = 0; i < m_dfgData->transitions.size(); ++i) {
1968 if (!!m_dfgData->transitions[i].m_codeOrigin)
1969 visitor.append(&m_dfgData->transitions[i].m_codeOrigin); // Almost certainly not necessary, since the code origin should also be a weak reference. Better to be safe, though.
1970 visitor.append(&m_dfgData->transitions[i].m_from);
1971 visitor.append(&m_dfgData->transitions[i].m_to);
1972 }
1973
1974 for (unsigned i = 0; i < m_dfgData->weakReferences.size(); ++i)
1975 visitor.append(&m_dfgData->weakReferences[i]);
1976#endif
1977}
1978
1979HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1980{
1981 ASSERT(bytecodeOffset < instructions().size());
1982
1983 if (!m_rareData)
1984 return 0;
1985
1986 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1987 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1988 // Handlers are ordered innermost first, so the first handler we encounter
1989 // that contains the source address is the correct handler to use.
1990 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1991 return &exceptionHandlers[i];
1992 }
1993
1994 return 0;
1995}
1996
1997int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
1998{
1999 ASSERT(bytecodeOffset < instructions().size());
2000
2001 if (!m_rareData)
2002 return m_ownerExecutable->source().firstLine();
2003
2004 Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
2005
2006 int low = 0;
2007 int high = lineInfo.size();
2008 while (low < high) {
2009 int mid = low + (high - low) / 2;
2010 if (lineInfo[mid].instructionOffset <= bytecodeOffset)
2011 low = mid + 1;
2012 else
2013 high = mid;
2014 }
2015
2016 if (!low)
2017 return m_ownerExecutable->source().firstLine();
2018 return lineInfo[low - 1].lineNumber;
2019}
2020
2021void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
2022{
2023 ASSERT(bytecodeOffset < instructions().size());
2024
2025 if (!m_rareData) {
2026 startOffset = 0;
2027 endOffset = 0;
2028 divot = 0;
2029 return;
2030 }
2031
2032 Vector<ExpressionRangeInfo>& expressionInfo = m_rareData->m_expressionInfo;
2033
2034 int low = 0;
2035 int high = expressionInfo.size();
2036 while (low < high) {
2037 int mid = low + (high - low) / 2;
2038 if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
2039 low = mid + 1;
2040 else
2041 high = mid;
2042 }
2043
2044 ASSERT(low);
2045 if (!low) {
2046 startOffset = 0;
2047 endOffset = 0;
2048 divot = 0;
2049 return;
2050 }
2051
2052 startOffset = expressionInfo[low - 1].startOffset;
2053 endOffset = expressionInfo[low - 1].endOffset;
2054 divot = expressionInfo[low - 1].divotPoint + m_sourceOffset;
2055 return;
2056}
2057
2058#if ENABLE(CLASSIC_INTERPRETER)
2059bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
2060{
2061 if (m_globalResolveInstructions.isEmpty())
2062 return false;
2063
2064 int low = 0;
2065 int high = m_globalResolveInstructions.size();
2066 while (low < high) {
2067 int mid = low + (high - low) / 2;
2068 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
2069 low = mid + 1;
2070 else
2071 high = mid;
2072 }
2073
2074 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
2075 return false;
2076 return true;
2077}
2078#endif
2079#if ENABLE(JIT)
2080bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
2081{
2082 if (m_globalResolveInfos.isEmpty())
2083 return false;
2084
2085 int low = 0;
2086 int high = m_globalResolveInfos.size();
2087 while (low < high) {
2088 int mid = low + (high - low) / 2;
2089 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
2090 low = mid + 1;
2091 else
2092 high = mid;
2093 }
2094
2095 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
2096 return false;
2097 return true;
2098}
2099#endif
2100
2101void CodeBlock::shrinkToFit()
2102{
2103#if ENABLE(CLASSIC_INTERPRETER)
2104 m_propertyAccessInstructions.shrinkToFit();
2105 m_globalResolveInstructions.shrinkToFit();
2106#endif
2107#if ENABLE(JIT)
2108 m_structureStubInfos.shrinkToFit();
2109 m_globalResolveInfos.shrinkToFit();
2110 m_callLinkInfos.shrinkToFit();
2111#endif
2112
2113 m_identifiers.shrinkToFit();
2114 m_functionDecls.shrinkToFit();
2115 m_functionExprs.shrinkToFit();
2116 m_constantRegisters.shrinkToFit();
2117
2118 if (m_rareData) {
2119 m_rareData->m_exceptionHandlers.shrinkToFit();
2120 m_rareData->m_regexps.shrinkToFit();
2121 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
2122 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
2123 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
2124 m_rareData->m_expressionInfo.shrinkToFit();
2125 m_rareData->m_lineInfo.shrinkToFit();
2126 }
2127}
2128
2129void CodeBlock::createActivation(CallFrame* callFrame)
2130{
2131 ASSERT(codeType() == FunctionCode);
2132 ASSERT(needsFullScopeChain());
2133 ASSERT(!callFrame->uncheckedR(activationRegister()).jsValue());
2134 JSActivation* activation = JSActivation::create(callFrame->globalData(), callFrame, static_cast<FunctionExecutable*>(ownerExecutable()));
2135 callFrame->uncheckedR(activationRegister()) = JSValue(activation);
2136 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
2137}
2138
2139unsigned CodeBlock::addOrFindConstant(JSValue v)
2140{
2141 unsigned numberOfConstants = numberOfConstantRegisters();
2142 for (unsigned i = 0; i < numberOfConstants; ++i) {
2143 if (getConstant(FirstConstantRegisterIndex + i) == v)
2144 return i;
2145 }
2146 return addConstant(v);
2147}
2148
2149#if ENABLE(JIT)
2150void CodeBlock::unlinkCalls()
2151{
2152 if (!!m_alternative)
2153 m_alternative->unlinkCalls();
2154#if ENABLE(LLINT)
2155 for (size_t i = 0; i < m_llintCallLinkInfos.size(); ++i) {
2156 if (m_llintCallLinkInfos[i].isLinked())
2157 m_llintCallLinkInfos[i].unlink();
2158 }
2159#endif
2160 if (!(m_callLinkInfos.size() || m_methodCallLinkInfos.size()))
2161 return;
2162 if (!m_globalData->canUseJIT())
2163 return;
2164 RepatchBuffer repatchBuffer(this);
2165 for (size_t i = 0; i < m_callLinkInfos.size(); i++) {
2166 if (!m_callLinkInfos[i].isLinked())
2167 continue;
2168 m_callLinkInfos[i].unlink(*m_globalData, repatchBuffer);
2169 }
2170}
2171
2172void CodeBlock::unlinkIncomingCalls()
2173{
2174#if ENABLE(LLINT)
2175 while (m_incomingLLIntCalls.begin() != m_incomingLLIntCalls.end())
2176 m_incomingLLIntCalls.begin()->unlink();
2177#endif
2178 if (m_incomingCalls.isEmpty())
2179 return;
2180 RepatchBuffer repatchBuffer(this);
2181 while (m_incomingCalls.begin() != m_incomingCalls.end())
2182 m_incomingCalls.begin()->unlink(*m_globalData, repatchBuffer);
2183}
2184
2185unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress)
2186{
2187#if ENABLE(LLINT)
2188 if (returnAddress.value() >= bitwise_cast<void*>(&llint_begin)
2189 && returnAddress.value() <= bitwise_cast<void*>(&llint_end)) {
2190 ASSERT(exec->codeBlock());
2191 ASSERT(exec->codeBlock() == this);
2192 ASSERT(JITCode::isBaselineCode(getJITType()));
2193 Instruction* instruction = exec->currentVPC();
2194 ASSERT(instruction);
2195
2196 // The LLInt stores the PC after the call instruction rather than the PC of
2197 // the call instruction. This requires some correcting. We rely on the fact
2198 // that the preceding instruction must be one of the call instructions, so
2199 // either it's a call_varargs or it's a call, construct, or eval.
2200 ASSERT(OPCODE_LENGTH(op_call_varargs) <= OPCODE_LENGTH(op_call));
2201 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
2202 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
2203 if (instruction[-OPCODE_LENGTH(op_call_varargs)].u.pointer == bitwise_cast<void*>(llint_op_call_varargs)) {
2204 // We know that the preceding instruction must be op_call_varargs because there is no way that
2205 // the pointer to the call_varargs could be an operand to the call.
2206 instruction -= OPCODE_LENGTH(op_call_varargs);
2207 ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call)
2208 && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_construct)
2209 && instruction[-OPCODE_LENGTH(op_call)].u.pointer != bitwise_cast<void*>(llint_op_call_eval));
2210 } else {
2211 // Must be that the last instruction was some op_call.
2212 ASSERT(instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call)
2213 || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_construct)
2214 || instruction[-OPCODE_LENGTH(op_call)].u.pointer == bitwise_cast<void*>(llint_op_call_eval));
2215 instruction -= OPCODE_LENGTH(op_call);
2216 }
2217
2218 return bytecodeOffset(instruction);
2219 }
2220#else
2221 UNUSED_PARAM(exec);
2222#endif
2223 if (!m_rareData)
2224 return 1;
2225 Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector;
2226 if (!callIndices.size())
2227 return 1;
2228 return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset;
2229}
2230#endif
2231
2232void CodeBlock::clearEvalCache()
2233{
2234 if (!!m_alternative)
2235 m_alternative->clearEvalCache();
2236 if (!m_rareData)
2237 return;
2238 m_rareData->m_evalCodeCache.clear();
2239}
2240
2241template<typename T>
2242inline void replaceExistingEntries(Vector<T>& target, Vector<T>& source)
2243{
2244 ASSERT(target.size() <= source.size());
2245 for (size_t i = 0; i < target.size(); ++i)
2246 target[i] = source[i];
2247}
2248
2249void CodeBlock::copyPostParseDataFrom(CodeBlock* alternative)
2250{
2251 if (!alternative)
2252 return;
2253
2254 replaceExistingEntries(m_constantRegisters, alternative->m_constantRegisters);
2255 replaceExistingEntries(m_functionDecls, alternative->m_functionDecls);
2256 replaceExistingEntries(m_functionExprs, alternative->m_functionExprs);
2257 if (!!m_rareData && !!alternative->m_rareData)
2258 replaceExistingEntries(m_rareData->m_constantBuffers, alternative->m_rareData->m_constantBuffers);
2259}
2260
2261void CodeBlock::copyPostParseDataFromAlternative()
2262{
2263 copyPostParseDataFrom(m_alternative.get());
2264}
2265
2266#if ENABLE(JIT)
2267CodeBlock* ProgramCodeBlock::replacement()
2268{
2269 return &static_cast<ProgramExecutable*>(ownerExecutable())->generatedBytecode();
2270}
2271
2272CodeBlock* EvalCodeBlock::replacement()
2273{
2274 return &static_cast<EvalExecutable*>(ownerExecutable())->generatedBytecode();
2275}
2276
2277CodeBlock* FunctionCodeBlock::replacement()
2278{
2279 return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall);
2280}
2281
2282JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
2283{
2284 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2285 return 0;
2286 JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
2287 return error;
2288}
2289
2290JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
2291{
2292 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2293 return 0;
2294 JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
2295 return error;
2296}
2297
2298JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
2299{
2300 if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType()))
2301 return 0;
2302 JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, m_isConstructor ? CodeForConstruct : CodeForCall);
2303 return error;
2304}
2305
2306bool ProgramCodeBlock::canCompileWithDFGInternal()
2307{
2308 return DFG::canCompileProgram(this);
2309}
2310
2311bool EvalCodeBlock::canCompileWithDFGInternal()
2312{
2313 return DFG::canCompileEval(this);
2314}
2315
2316bool FunctionCodeBlock::canCompileWithDFGInternal()
2317{
2318 if (m_isConstructor)
2319 return DFG::canCompileFunctionForConstruct(this);
2320 return DFG::canCompileFunctionForCall(this);
2321}
2322
2323void ProgramCodeBlock::jettison()
2324{
2325 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2326 ASSERT(this == replacement());
2327 static_cast<ProgramExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
2328}
2329
2330void EvalCodeBlock::jettison()
2331{
2332 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2333 ASSERT(this == replacement());
2334 static_cast<EvalExecutable*>(ownerExecutable())->jettisonOptimizedCode(*globalData());
2335}
2336
2337void FunctionCodeBlock::jettison()
2338{
2339 ASSERT(JITCode::isOptimizingJIT(getJITType()));
2340 ASSERT(this == replacement());
2341 static_cast<FunctionExecutable*>(ownerExecutable())->jettisonOptimizedCodeFor(*globalData(), m_isConstructor ? CodeForConstruct : CodeForCall);
2342}
2343
2344bool ProgramCodeBlock::jitCompileImpl(JSGlobalData& globalData)
2345{
2346 ASSERT(getJITType() == JITCode::InterpreterThunk);
2347 ASSERT(this == replacement());
2348 return static_cast<ProgramExecutable*>(ownerExecutable())->jitCompile(globalData);
2349}
2350
2351bool EvalCodeBlock::jitCompileImpl(JSGlobalData& globalData)
2352{
2353 ASSERT(getJITType() == JITCode::InterpreterThunk);
2354 ASSERT(this == replacement());
2355 return static_cast<EvalExecutable*>(ownerExecutable())->jitCompile(globalData);
2356}
2357
2358bool FunctionCodeBlock::jitCompileImpl(JSGlobalData& globalData)
2359{
2360 ASSERT(getJITType() == JITCode::InterpreterThunk);
2361 ASSERT(this == replacement());
2362 return static_cast<FunctionExecutable*>(ownerExecutable())->jitCompileFor(globalData, m_isConstructor ? CodeForConstruct : CodeForCall);
2363}
2364#endif
2365
2366#if ENABLE(VALUE_PROFILER)
2367bool CodeBlock::shouldOptimizeNow()
2368{
2369#if ENABLE(JIT_VERBOSE_OSR)
2370 dataLog("Considering optimizing %p...\n", this);
2371#endif
2372
2373#if ENABLE(VERBOSE_VALUE_PROFILE)
2374 dumpValueProfiles();
2375#endif
2376
2377 if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
2378 return true;
2379
2380 unsigned numberOfLiveNonArgumentValueProfiles = 0;
2381 unsigned numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
2382 for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
2383 ValueProfile* profile = getFromAllValueProfiles(i);
2384 unsigned numSamples = profile->totalNumberOfSamples();
2385 if (numSamples > ValueProfile::numberOfBuckets)
2386 numSamples = ValueProfile::numberOfBuckets; // We don't want profiles that are extremely hot to be given more weight.
2387 numberOfSamplesInProfiles += numSamples;
2388 if (profile->m_bytecodeOffset < 0) {
2389 profile->computeUpdatedPrediction();
2390 continue;
2391 }
2392 if (profile->numberOfSamples() || profile->m_prediction != PredictNone)
2393 numberOfLiveNonArgumentValueProfiles++;
2394 profile->computeUpdatedPrediction();
2395 }
2396
2397#if ENABLE(JIT_VERBOSE_OSR)
2398 dataLog("Profile hotness: %lf, %lf\n", (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles(), (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / numberOfValueProfiles());
2399#endif
2400
2401 if ((!numberOfValueProfiles() || (double)numberOfLiveNonArgumentValueProfiles / numberOfValueProfiles() >= Options::desiredProfileLivenessRate)
2402 && (!totalNumberOfValueProfiles() || (double)numberOfSamplesInProfiles / ValueProfile::numberOfBuckets / totalNumberOfValueProfiles() >= Options::desiredProfileFullnessRate)
2403 && static_cast<unsigned>(m_optimizationDelayCounter) + 1 >= Options::minimumOptimizationDelay)
2404 return true;
2405
2406 ASSERT(m_optimizationDelayCounter < std::numeric_limits<uint8_t>::max());
2407 m_optimizationDelayCounter++;
2408 optimizeAfterWarmUp();
2409 return false;
2410}
2411#endif
2412
2413#if ENABLE(DFG_JIT)
2414void CodeBlock::tallyFrequentExitSites()
2415{
2416 ASSERT(getJITType() == JITCode::DFGJIT);
2417 ASSERT(alternative()->getJITType() == JITCode::BaselineJIT);
2418 ASSERT(!!m_dfgData);
2419
2420 CodeBlock* profiledBlock = alternative();
2421
2422 for (unsigned i = 0; i < m_dfgData->osrExit.size(); ++i) {
2423 DFG::OSRExit& exit = m_dfgData->osrExit[i];
2424
2425 if (!exit.considerAddingAsFrequentExitSite(this, profiledBlock))
2426 continue;
2427
2428#if DFG_ENABLE(DEBUG_VERBOSE)
2429 dataLog("OSR exit #%u (bc#%u, @%u, %s) for code block %p occurred frequently; counting as frequent exit site.\n", i, exit.m_codeOrigin.bytecodeIndex, exit.m_nodeIndex, DFG::exitKindToString(exit.m_kind), this);
2430#endif
2431 }
2432}
2433#endif // ENABLE(DFG_JIT)
2434
2435#if ENABLE(VERBOSE_VALUE_PROFILE)
2436void CodeBlock::dumpValueProfiles()
2437{
2438 dataLog("ValueProfile for %p:\n", this);
2439 for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
2440 ValueProfile* profile = getFromAllValueProfiles(i);
2441 if (profile->m_bytecodeOffset < 0) {
2442 ASSERT(profile->m_bytecodeOffset == -1);
2443 dataLog(" arg = %u: ", i);
2444 } else
2445 dataLog(" bc = %d: ", profile->m_bytecodeOffset);
2446 if (!profile->numberOfSamples() && profile->m_prediction == PredictNone) {
2447 dataLog("<empty>\n");
2448 continue;
2449 }
2450 profile->dump(WTF::dataFile());
2451 dataLog("\n");
2452 }
2453 dataLog("RareCaseProfile for %p:\n", this);
2454 for (unsigned i = 0; i < numberOfRareCaseProfiles(); ++i) {
2455 RareCaseProfile* profile = rareCaseProfile(i);
2456 dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
2457 }
2458 dataLog("SpecialFastCaseProfile for %p:\n", this);
2459 for (unsigned i = 0; i < numberOfSpecialFastCaseProfiles(); ++i) {
2460 RareCaseProfile* profile = specialFastCaseProfile(i);
2461 dataLog(" bc = %d: %u\n", profile->m_bytecodeOffset, profile->m_counter);
2462 }
2463}
2464#endif
2465
2466size_t CodeBlock::predictedMachineCodeSize()
2467{
2468 // This will be called from CodeBlock::CodeBlock before either m_globalData or the
2469 // instructions have been initialized. It's OK to return 0 because what will really
2470 // matter is the recomputation of this value when the slow path is triggered.
2471 if (!m_globalData)
2472 return 0;
2473
2474 if (!m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT)
2475 return 0; // It's as good of a prediction as we'll get.
2476
2477 // Be conservative: return a size that will be an overestimation 84% of the time.
2478 double multiplier = m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.mean() +
2479 m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.standardDeviation();
2480
2481 // Be paranoid: silently reject bogus multipiers. Silently doing the "wrong" thing
2482 // here is OK, since this whole method is just a heuristic.
2483 if (multiplier < 0 || multiplier > 1000)
2484 return 0;
2485
2486 double doubleResult = multiplier * m_instructions.size();
2487
2488 // Be even more paranoid: silently reject values that won't fit into a size_t. If
2489 // the function is so huge that we can't even fit it into virtual memory then we
2490 // should probably have some other guards in place to prevent us from even getting
2491 // to this point.
2492 if (doubleResult > std::numeric_limits<size_t>::max())
2493 return 0;
2494
2495 return static_cast<size_t>(doubleResult);
2496}
2497
2498bool CodeBlock::usesOpcode(OpcodeID opcodeID)
2499{
2500 Interpreter* interpreter = globalData()->interpreter;
2501 Instruction* instructionsBegin = instructions().begin();
2502 unsigned instructionCount = instructions().size();
2503
2504 for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
2505 switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
2506#define DEFINE_OP(curOpcode, length) \
2507 case curOpcode: \
2508 if (curOpcode == opcodeID) \
2509 return true; \
2510 bytecodeOffset += length; \
2511 break;
2512 FOR_EACH_OPCODE_ID(DEFINE_OP)
2513#undef DEFINE_OP
2514 default:
2515 ASSERT_NOT_REACHED();
2516 break;
2517 }
2518 }
2519
2520 return false;
2521}
2522
2523} // namespace JSC