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 "Debugger.h"
35 #include "Interpreter.h"
36 #include "JIT.h"
37 #include "JSActivation.h"
38 #include "JSFunction.h"
39 #include "JSStaticScopeObject.h"
40 #include "JSValue.h"
41 #include "UStringConcatenate.h"
42 #include <stdio.h>
43 #include <wtf/StringExtras.h>
44
45 #define DUMP_CODE_BLOCK_STATISTICS 0
46
47 namespace JSC {
48
49 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
50
escapeQuotes(const UString & str)51 static UString escapeQuotes(const UString& str)
52 {
53 UString result = str;
54 size_t pos = 0;
55 while ((pos = result.find('\"', pos)) != notFound) {
56 result = makeUString(result.substringSharingImpl(0, pos), "\"\\\"\"", result.substringSharingImpl(pos + 1));
57 pos += 4;
58 }
59 return result;
60 }
61
valueToSourceString(ExecState * exec,JSValue val)62 static UString valueToSourceString(ExecState* exec, JSValue val)
63 {
64 if (!val)
65 return "0";
66
67 if (val.isString())
68 return makeUString("\"", escapeQuotes(val.toString(exec)), "\"");
69
70 return val.toString(exec);
71 }
72
constantName(ExecState * exec,int k,JSValue value)73 static CString constantName(ExecState* exec, int k, JSValue value)
74 {
75 return makeUString(valueToSourceString(exec, value), "(@k", UString::number(k - FirstConstantRegisterIndex), ")").utf8();
76 }
77
idName(int id0,const Identifier & ident)78 static CString idName(int id0, const Identifier& ident)
79 {
80 return makeUString(ident.ustring(), "(@id", UString::number(id0), ")").utf8();
81 }
82
registerName(ExecState * exec,int r) const83 CString CodeBlock::registerName(ExecState* exec, int r) const
84 {
85 if (r == missingThisObjectMarker())
86 return "<null>";
87
88 if (isConstantRegisterIndex(r))
89 return constantName(exec, r, getConstant(r));
90
91 return makeUString("r", UString::number(r)).utf8();
92 }
93
regexpToSourceString(RegExp * regExp)94 static UString regexpToSourceString(RegExp* regExp)
95 {
96 char postfix[5] = { '/', 0, 0, 0, 0 };
97 int index = 1;
98 if (regExp->global())
99 postfix[index++] = 'g';
100 if (regExp->ignoreCase())
101 postfix[index++] = 'i';
102 if (regExp->multiline())
103 postfix[index] = 'm';
104
105 return makeUString("/", regExp->pattern(), postfix);
106 }
107
regexpName(int re,RegExp * regexp)108 static CString regexpName(int re, RegExp* regexp)
109 {
110 return makeUString(regexpToSourceString(regexp), "(@re", UString::number(re), ")").utf8();
111 }
112
pointerToSourceString(void * p)113 static UString pointerToSourceString(void* p)
114 {
115 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
116 snprintf(buffer, sizeof(buffer), "%p", p);
117 return buffer;
118 }
119
debugHookName(int debugHookID)120 NEVER_INLINE static const char* debugHookName(int debugHookID)
121 {
122 switch (static_cast<DebugHookID>(debugHookID)) {
123 case DidEnterCallFrame:
124 return "didEnterCallFrame";
125 case WillLeaveCallFrame:
126 return "willLeaveCallFrame";
127 case WillExecuteStatement:
128 return "willExecuteStatement";
129 case WillExecuteProgram:
130 return "willExecuteProgram";
131 case DidExecuteProgram:
132 return "didExecuteProgram";
133 case DidReachBreakpoint:
134 return "didReachBreakpoint";
135 }
136
137 ASSERT_NOT_REACHED();
138 return "";
139 }
140
printUnaryOp(ExecState * exec,int location,Vector<Instruction>::const_iterator & it,const char * op) const141 void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
142 {
143 int r0 = (++it)->u.operand;
144 int r1 = (++it)->u.operand;
145
146 printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data());
147 }
148
printBinaryOp(ExecState * exec,int location,Vector<Instruction>::const_iterator & it,const char * op) const149 void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
150 {
151 int r0 = (++it)->u.operand;
152 int r1 = (++it)->u.operand;
153 int r2 = (++it)->u.operand;
154 printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
155 }
156
printConditionalJump(ExecState * exec,const Vector<Instruction>::const_iterator &,Vector<Instruction>::const_iterator & it,int location,const char * op) const157 void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) const
158 {
159 int r0 = (++it)->u.operand;
160 int offset = (++it)->u.operand;
161 printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(exec, r0).data(), offset, location + offset);
162 }
163
printGetByIdOp(ExecState * exec,int location,Vector<Instruction>::const_iterator & it,const char * op) const164 void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
165 {
166 int r0 = (++it)->u.operand;
167 int r1 = (++it)->u.operand;
168 int id0 = (++it)->u.operand;
169 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
170 it += 4;
171 }
172
printPutByIdOp(ExecState * exec,int location,Vector<Instruction>::const_iterator & it,const char * op) const173 void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const
174 {
175 int r0 = (++it)->u.operand;
176 int id0 = (++it)->u.operand;
177 int r1 = (++it)->u.operand;
178 printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
179 it += 5;
180 }
181
182 #if ENABLE(JIT)
isGlobalResolve(OpcodeID opcodeID)183 static bool isGlobalResolve(OpcodeID opcodeID)
184 {
185 return opcodeID == op_resolve_global || opcodeID == op_resolve_global_dynamic;
186 }
187
isPropertyAccess(OpcodeID opcodeID)188 static bool isPropertyAccess(OpcodeID opcodeID)
189 {
190 switch (opcodeID) {
191 case op_get_by_id_self:
192 case op_get_by_id_proto:
193 case op_get_by_id_chain:
194 case op_get_by_id_self_list:
195 case op_get_by_id_proto_list:
196 case op_put_by_id_transition:
197 case op_put_by_id_replace:
198 case op_get_by_id:
199 case op_put_by_id:
200 case op_get_by_id_generic:
201 case op_put_by_id_generic:
202 case op_get_array_length:
203 case op_get_string_length:
204 return true;
205 default:
206 return false;
207 }
208 }
209
instructionOffsetForNth(ExecState * exec,const Vector<Instruction> & instructions,int nth,bool (* predicate)(OpcodeID))210 static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
211 {
212 size_t i = 0;
213 while (i < instructions.size()) {
214 OpcodeID currentOpcode = exec->interpreter()->getOpcodeID(instructions[i].u.opcode);
215 if (predicate(currentOpcode)) {
216 if (!--nth)
217 return i;
218 }
219 i += opcodeLengths[currentOpcode];
220 }
221
222 ASSERT_NOT_REACHED();
223 return 0;
224 }
225
printGlobalResolveInfo(const GlobalResolveInfo & resolveInfo,unsigned instructionOffset)226 static void printGlobalResolveInfo(const GlobalResolveInfo& resolveInfo, unsigned instructionOffset)
227 {
228 printf(" [%4d] %s: %s\n", instructionOffset, "resolve_global", pointerToSourceString(resolveInfo.structure).utf8().data());
229 }
230
printStructureStubInfo(const StructureStubInfo & stubInfo,unsigned instructionOffset)231 static void printStructureStubInfo(const StructureStubInfo& stubInfo, unsigned instructionOffset)
232 {
233 switch (stubInfo.accessType) {
234 case access_get_by_id_self:
235 printf(" [%4d] %s: %s\n", instructionOffset, "get_by_id_self", pointerToSourceString(stubInfo.u.getByIdSelf.baseObjectStructure).utf8().data());
236 return;
237 case access_get_by_id_proto:
238 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(stubInfo.u.getByIdProto.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).utf8().data());
239 return;
240 case access_get_by_id_chain:
241 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(stubInfo.u.getByIdChain.baseObjectStructure).utf8().data(), pointerToSourceString(stubInfo.u.getByIdChain.chain).utf8().data());
242 return;
243 case access_get_by_id_self_list:
244 printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_self_list", pointerToSourceString(stubInfo.u.getByIdSelfList.structureList).utf8().data(), stubInfo.u.getByIdSelfList.listSize);
245 return;
246 case access_get_by_id_proto_list:
247 printf(" [%4d] %s: %s (%d)\n", instructionOffset, "op_get_by_id_proto_list", pointerToSourceString(stubInfo.u.getByIdProtoList.structureList).utf8().data(), stubInfo.u.getByIdProtoList.listSize);
248 return;
249 case access_put_by_id_transition:
250 printf(" [%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());
251 return;
252 case access_put_by_id_replace:
253 printf(" [%4d] %s: %s\n", instructionOffset, "put_by_id_replace", pointerToSourceString(stubInfo.u.putByIdReplace.baseObjectStructure).utf8().data());
254 return;
255 case access_get_by_id:
256 printf(" [%4d] %s\n", instructionOffset, "get_by_id");
257 return;
258 case access_put_by_id:
259 printf(" [%4d] %s\n", instructionOffset, "put_by_id");
260 return;
261 case access_get_by_id_generic:
262 printf(" [%4d] %s\n", instructionOffset, "op_get_by_id_generic");
263 return;
264 case access_put_by_id_generic:
265 printf(" [%4d] %s\n", instructionOffset, "op_put_by_id_generic");
266 return;
267 case access_get_array_length:
268 printf(" [%4d] %s\n", instructionOffset, "op_get_array_length");
269 return;
270 case access_get_string_length:
271 printf(" [%4d] %s\n", instructionOffset, "op_get_string_length");
272 return;
273 default:
274 ASSERT_NOT_REACHED();
275 }
276 }
277 #endif
278
printStructure(const char * name,const Instruction * vPC,int operand) const279 void CodeBlock::printStructure(const char* name, const Instruction* vPC, int operand) const
280 {
281 unsigned instructionOffset = vPC - m_instructions.begin();
282 printf(" [%4d] %s: %s\n", instructionOffset, name, pointerToSourceString(vPC[operand].u.structure).utf8().data());
283 }
284
printStructures(const Instruction * vPC) const285 void CodeBlock::printStructures(const Instruction* vPC) const
286 {
287 Interpreter* interpreter = m_globalData->interpreter;
288 unsigned instructionOffset = vPC - m_instructions.begin();
289
290 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id)) {
291 printStructure("get_by_id", vPC, 4);
292 return;
293 }
294 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
295 printStructure("get_by_id_self", vPC, 4);
296 return;
297 }
298 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
299 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_proto", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data());
300 return;
301 }
302 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
303 printf(" [%4d] %s: %s, %s, %s\n", instructionOffset, "put_by_id_transition", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structure).utf8().data(), pointerToSourceString(vPC[6].u.structureChain).utf8().data());
304 return;
305 }
306 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
307 printf(" [%4d] %s: %s, %s\n", instructionOffset, "get_by_id_chain", pointerToSourceString(vPC[4].u.structure).utf8().data(), pointerToSourceString(vPC[5].u.structureChain).utf8().data());
308 return;
309 }
310 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id)) {
311 printStructure("put_by_id", vPC, 4);
312 return;
313 }
314 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
315 printStructure("put_by_id_replace", vPC, 4);
316 return;
317 }
318 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
319 printStructure("resolve_global", vPC, 4);
320 return;
321 }
322 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
323 printStructure("resolve_global_dynamic", vPC, 4);
324 return;
325 }
326
327 // These m_instructions doesn't ref Structures.
328 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));
329 }
330
dump(ExecState * exec) const331 void CodeBlock::dump(ExecState* exec) const
332 {
333 if (m_instructions.isEmpty()) {
334 printf("No instructions available.\n");
335 return;
336 }
337
338 size_t instructionCount = 0;
339
340 for (size_t i = 0; i < m_instructions.size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(m_instructions[i].u.opcode)])
341 ++instructionCount;
342
343 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
344 static_cast<unsigned long>(instructionCount),
345 static_cast<unsigned long>(m_instructions.size() * sizeof(Instruction)),
346 this, m_numParameters, m_numCalleeRegisters);
347
348 Vector<Instruction>::const_iterator begin = m_instructions.begin();
349 Vector<Instruction>::const_iterator end = m_instructions.end();
350 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
351 dump(exec, begin, it);
352
353 if (!m_identifiers.isEmpty()) {
354 printf("\nIdentifiers:\n");
355 size_t i = 0;
356 do {
357 printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ustring().utf8().data());
358 ++i;
359 } while (i != m_identifiers.size());
360 }
361
362 if (!m_constantRegisters.isEmpty()) {
363 printf("\nConstants:\n");
364 unsigned registerIndex = m_numVars;
365 size_t i = 0;
366 do {
367 printf(" k%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].get()).utf8().data());
368 ++i;
369 ++registerIndex;
370 } while (i < m_constantRegisters.size());
371 }
372
373 if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
374 printf("\nm_regexps:\n");
375 size_t i = 0;
376 do {
377 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data());
378 ++i;
379 } while (i < m_rareData->m_regexps.size());
380 }
381
382 #if ENABLE(JIT)
383 if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
384 printf("\nStructures:\n");
385
386 if (!m_globalResolveInfos.isEmpty()) {
387 size_t i = 0;
388 do {
389 printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isGlobalResolve));
390 ++i;
391 } while (i < m_globalResolveInfos.size());
392 }
393 if (!m_structureStubInfos.isEmpty()) {
394 size_t i = 0;
395 do {
396 printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isPropertyAccess));
397 ++i;
398 } while (i < m_structureStubInfos.size());
399 }
400 #else
401 if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
402 printf("\nStructures:\n");
403
404 if (!m_globalResolveInstructions.isEmpty()) {
405 size_t i = 0;
406 do {
407 printStructures(&m_instructions[m_globalResolveInstructions[i]]);
408 ++i;
409 } while (i < m_globalResolveInstructions.size());
410 }
411 if (!m_propertyAccessInstructions.isEmpty()) {
412 size_t i = 0;
413 do {
414 printStructures(&m_instructions[m_propertyAccessInstructions[i]]);
415 ++i;
416 } while (i < m_propertyAccessInstructions.size());
417 }
418 #endif
419
420 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
421 printf("\nException Handlers:\n");
422 unsigned i = 0;
423 do {
424 printf("\t %d: { start: [%4d] end: [%4d] target: [%4d] }\n", i + 1, m_rareData->m_exceptionHandlers[i].start, m_rareData->m_exceptionHandlers[i].end, m_rareData->m_exceptionHandlers[i].target);
425 ++i;
426 } while (i < m_rareData->m_exceptionHandlers.size());
427 }
428
429 if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
430 printf("Immediate Switch Jump Tables:\n");
431 unsigned i = 0;
432 do {
433 printf(" %1d = {\n", i);
434 int entry = 0;
435 Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
436 for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
437 if (!*iter)
438 continue;
439 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
440 }
441 printf(" }\n");
442 ++i;
443 } while (i < m_rareData->m_immediateSwitchJumpTables.size());
444 }
445
446 if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
447 printf("\nCharacter Switch Jump Tables:\n");
448 unsigned i = 0;
449 do {
450 printf(" %1d = {\n", i);
451 int entry = 0;
452 Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
453 for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
454 if (!*iter)
455 continue;
456 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
457 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
458 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter);
459 }
460 printf(" }\n");
461 ++i;
462 } while (i < m_rareData->m_characterSwitchJumpTables.size());
463 }
464
465 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
466 printf("\nString Switch Jump Tables:\n");
467 unsigned i = 0;
468 do {
469 printf(" %1d = {\n", i);
470 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
471 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
472 printf("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset);
473 printf(" }\n");
474 ++i;
475 } while (i < m_rareData->m_stringSwitchJumpTables.size());
476 }
477
478 printf("\n");
479 }
480
dump(ExecState * exec,const Vector<Instruction>::const_iterator & begin,Vector<Instruction>::const_iterator & it) const481 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
482 {
483 int location = it - begin;
484 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
485 case op_enter: {
486 printf("[%4d] enter\n", location);
487 break;
488 }
489 case op_create_activation: {
490 int r0 = (++it)->u.operand;
491 printf("[%4d] create_activation %s\n", location, registerName(exec, r0).data());
492 break;
493 }
494 case op_create_arguments: {
495 int r0 = (++it)->u.operand;
496 printf("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data());
497 break;
498 }
499 case op_init_lazy_reg: {
500 int r0 = (++it)->u.operand;
501 printf("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data());
502 break;
503 }
504 case op_get_callee: {
505 int r0 = (++it)->u.operand;
506 printf("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data());
507 break;
508 }
509 case op_create_this: {
510 int r0 = (++it)->u.operand;
511 int r1 = (++it)->u.operand;
512 printf("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
513 break;
514 }
515 case op_convert_this: {
516 int r0 = (++it)->u.operand;
517 printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data());
518 break;
519 }
520 case op_convert_this_strict: {
521 int r0 = (++it)->u.operand;
522 printf("[%4d] convert_this_strict %s\n", location, registerName(exec, r0).data());
523 break;
524 }
525 case op_new_object: {
526 int r0 = (++it)->u.operand;
527 printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
528 break;
529 }
530 case op_new_array: {
531 int dst = (++it)->u.operand;
532 int argv = (++it)->u.operand;
533 int argc = (++it)->u.operand;
534 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
535 break;
536 }
537 case op_new_regexp: {
538 int r0 = (++it)->u.operand;
539 int re0 = (++it)->u.operand;
540 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(exec, r0).data(), regexpName(re0, regexp(re0)).data());
541 break;
542 }
543 case op_mov: {
544 int r0 = (++it)->u.operand;
545 int r1 = (++it)->u.operand;
546 printf("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
547 break;
548 }
549 case op_not: {
550 printUnaryOp(exec, location, it, "not");
551 break;
552 }
553 case op_eq: {
554 printBinaryOp(exec, location, it, "eq");
555 break;
556 }
557 case op_eq_null: {
558 printUnaryOp(exec, location, it, "eq_null");
559 break;
560 }
561 case op_neq: {
562 printBinaryOp(exec, location, it, "neq");
563 break;
564 }
565 case op_neq_null: {
566 printUnaryOp(exec, location, it, "neq_null");
567 break;
568 }
569 case op_stricteq: {
570 printBinaryOp(exec, location, it, "stricteq");
571 break;
572 }
573 case op_nstricteq: {
574 printBinaryOp(exec, location, it, "nstricteq");
575 break;
576 }
577 case op_less: {
578 printBinaryOp(exec, location, it, "less");
579 break;
580 }
581 case op_lesseq: {
582 printBinaryOp(exec, location, it, "lesseq");
583 break;
584 }
585 case op_pre_inc: {
586 int r0 = (++it)->u.operand;
587 printf("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).data());
588 break;
589 }
590 case op_pre_dec: {
591 int r0 = (++it)->u.operand;
592 printf("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).data());
593 break;
594 }
595 case op_post_inc: {
596 printUnaryOp(exec, location, it, "post_inc");
597 break;
598 }
599 case op_post_dec: {
600 printUnaryOp(exec, location, it, "post_dec");
601 break;
602 }
603 case op_to_jsnumber: {
604 printUnaryOp(exec, location, it, "to_jsnumber");
605 break;
606 }
607 case op_negate: {
608 printUnaryOp(exec, location, it, "negate");
609 break;
610 }
611 case op_add: {
612 printBinaryOp(exec, location, it, "add");
613 ++it;
614 break;
615 }
616 case op_mul: {
617 printBinaryOp(exec, location, it, "mul");
618 ++it;
619 break;
620 }
621 case op_div: {
622 printBinaryOp(exec, location, it, "div");
623 ++it;
624 break;
625 }
626 case op_mod: {
627 printBinaryOp(exec, location, it, "mod");
628 break;
629 }
630 case op_sub: {
631 printBinaryOp(exec, location, it, "sub");
632 ++it;
633 break;
634 }
635 case op_lshift: {
636 printBinaryOp(exec, location, it, "lshift");
637 break;
638 }
639 case op_rshift: {
640 printBinaryOp(exec, location, it, "rshift");
641 break;
642 }
643 case op_urshift: {
644 printBinaryOp(exec, location, it, "urshift");
645 break;
646 }
647 case op_bitand: {
648 printBinaryOp(exec, location, it, "bitand");
649 ++it;
650 break;
651 }
652 case op_bitxor: {
653 printBinaryOp(exec, location, it, "bitxor");
654 ++it;
655 break;
656 }
657 case op_bitor: {
658 printBinaryOp(exec, location, it, "bitor");
659 ++it;
660 break;
661 }
662 case op_bitnot: {
663 printUnaryOp(exec, location, it, "bitnot");
664 break;
665 }
666 case op_check_has_instance: {
667 int base = (++it)->u.operand;
668 printf("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data());
669 break;
670 }
671 case op_instanceof: {
672 int r0 = (++it)->u.operand;
673 int r1 = (++it)->u.operand;
674 int r2 = (++it)->u.operand;
675 int r3 = (++it)->u.operand;
676 printf("[%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());
677 break;
678 }
679 case op_typeof: {
680 printUnaryOp(exec, location, it, "typeof");
681 break;
682 }
683 case op_is_undefined: {
684 printUnaryOp(exec, location, it, "is_undefined");
685 break;
686 }
687 case op_is_boolean: {
688 printUnaryOp(exec, location, it, "is_boolean");
689 break;
690 }
691 case op_is_number: {
692 printUnaryOp(exec, location, it, "is_number");
693 break;
694 }
695 case op_is_string: {
696 printUnaryOp(exec, location, it, "is_string");
697 break;
698 }
699 case op_is_object: {
700 printUnaryOp(exec, location, it, "is_object");
701 break;
702 }
703 case op_is_function: {
704 printUnaryOp(exec, location, it, "is_function");
705 break;
706 }
707 case op_in: {
708 printBinaryOp(exec, location, it, "in");
709 break;
710 }
711 case op_resolve: {
712 int r0 = (++it)->u.operand;
713 int id0 = (++it)->u.operand;
714 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
715 break;
716 }
717 case op_resolve_skip: {
718 int r0 = (++it)->u.operand;
719 int id0 = (++it)->u.operand;
720 int skipLevels = (++it)->u.operand;
721 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels);
722 break;
723 }
724 case op_resolve_global: {
725 int r0 = (++it)->u.operand;
726 int id0 = (++it)->u.operand;
727 printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
728 it += 2;
729 break;
730 }
731 case op_resolve_global_dynamic: {
732 int r0 = (++it)->u.operand;
733 int id0 = (++it)->u.operand;
734 JSValue scope = JSValue((++it)->u.jsCell.get());
735 ++it;
736 int depth = (++it)->u.operand;
737 printf("[%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);
738 break;
739 }
740 case op_get_scoped_var: {
741 int r0 = (++it)->u.operand;
742 int index = (++it)->u.operand;
743 int skipLevels = (++it)->u.operand;
744 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels);
745 break;
746 }
747 case op_put_scoped_var: {
748 int index = (++it)->u.operand;
749 int skipLevels = (++it)->u.operand;
750 int r0 = (++it)->u.operand;
751 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).data());
752 break;
753 }
754 case op_get_global_var: {
755 int r0 = (++it)->u.operand;
756 int index = (++it)->u.operand;
757 printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index);
758 break;
759 }
760 case op_put_global_var: {
761 int index = (++it)->u.operand;
762 int r0 = (++it)->u.operand;
763 printf("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data());
764 break;
765 }
766 case op_resolve_base: {
767 int r0 = (++it)->u.operand;
768 int id0 = (++it)->u.operand;
769 int isStrict = (++it)->u.operand;
770 printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
771 break;
772 }
773 case op_ensure_property_exists: {
774 int r0 = (++it)->u.operand;
775 int id0 = (++it)->u.operand;
776 printf("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
777 break;
778 }
779 case op_resolve_with_base: {
780 int r0 = (++it)->u.operand;
781 int r1 = (++it)->u.operand;
782 int id0 = (++it)->u.operand;
783 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
784 break;
785 }
786 case op_get_by_id: {
787 printGetByIdOp(exec, location, it, "get_by_id");
788 break;
789 }
790 case op_get_by_id_self: {
791 printGetByIdOp(exec, location, it, "get_by_id_self");
792 break;
793 }
794 case op_get_by_id_self_list: {
795 printGetByIdOp(exec, location, it, "get_by_id_self_list");
796 break;
797 }
798 case op_get_by_id_proto: {
799 printGetByIdOp(exec, location, it, "get_by_id_proto");
800 break;
801 }
802 case op_get_by_id_proto_list: {
803 printGetByIdOp(exec, location, it, "op_get_by_id_proto_list");
804 break;
805 }
806 case op_get_by_id_chain: {
807 printGetByIdOp(exec, location, it, "get_by_id_chain");
808 break;
809 }
810 case op_get_by_id_getter_self: {
811 printGetByIdOp(exec, location, it, "get_by_id_getter_self");
812 break;
813 }
814 case op_get_by_id_getter_self_list: {
815 printGetByIdOp(exec, location, it, "get_by_id_getter_self_list");
816 break;
817 }
818 case op_get_by_id_getter_proto: {
819 printGetByIdOp(exec, location, it, "get_by_id_getter_proto");
820 break;
821 }
822 case op_get_by_id_getter_proto_list: {
823 printGetByIdOp(exec, location, it, "get_by_id_getter_proto_list");
824 break;
825 }
826 case op_get_by_id_getter_chain: {
827 printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
828 break;
829 }
830 case op_get_by_id_custom_self: {
831 printGetByIdOp(exec, location, it, "get_by_id_custom_self");
832 break;
833 }
834 case op_get_by_id_custom_self_list: {
835 printGetByIdOp(exec, location, it, "get_by_id_custom_self_list");
836 break;
837 }
838 case op_get_by_id_custom_proto: {
839 printGetByIdOp(exec, location, it, "get_by_id_custom_proto");
840 break;
841 }
842 case op_get_by_id_custom_proto_list: {
843 printGetByIdOp(exec, location, it, "get_by_id_custom_proto_list");
844 break;
845 }
846 case op_get_by_id_custom_chain: {
847 printGetByIdOp(exec, location, it, "get_by_id_custom_chain");
848 break;
849 }
850 case op_get_by_id_generic: {
851 printGetByIdOp(exec, location, it, "get_by_id_generic");
852 break;
853 }
854 case op_get_array_length: {
855 printGetByIdOp(exec, location, it, "get_array_length");
856 break;
857 }
858 case op_get_string_length: {
859 printGetByIdOp(exec, location, it, "get_string_length");
860 break;
861 }
862 case op_get_arguments_length: {
863 printUnaryOp(exec, location, it, "get_arguments_length");
864 it++;
865 break;
866 }
867 case op_put_by_id: {
868 printPutByIdOp(exec, location, it, "put_by_id");
869 break;
870 }
871 case op_put_by_id_replace: {
872 printPutByIdOp(exec, location, it, "put_by_id_replace");
873 break;
874 }
875 case op_put_by_id_transition: {
876 printPutByIdOp(exec, location, it, "put_by_id_transition");
877 break;
878 }
879 case op_put_by_id_generic: {
880 printPutByIdOp(exec, location, it, "put_by_id_generic");
881 break;
882 }
883 case op_put_getter: {
884 int r0 = (++it)->u.operand;
885 int id0 = (++it)->u.operand;
886 int r1 = (++it)->u.operand;
887 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
888 break;
889 }
890 case op_put_setter: {
891 int r0 = (++it)->u.operand;
892 int id0 = (++it)->u.operand;
893 int r1 = (++it)->u.operand;
894 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
895 break;
896 }
897 case op_method_check: {
898 printf("[%4d] method_check\n", location);
899 break;
900 }
901 case op_del_by_id: {
902 int r0 = (++it)->u.operand;
903 int r1 = (++it)->u.operand;
904 int id0 = (++it)->u.operand;
905 printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
906 break;
907 }
908 case op_get_by_val: {
909 int r0 = (++it)->u.operand;
910 int r1 = (++it)->u.operand;
911 int r2 = (++it)->u.operand;
912 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
913 break;
914 }
915 case op_get_argument_by_val: {
916 int r0 = (++it)->u.operand;
917 int r1 = (++it)->u.operand;
918 int r2 = (++it)->u.operand;
919 printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
920 break;
921 }
922 case op_get_by_pname: {
923 int r0 = (++it)->u.operand;
924 int r1 = (++it)->u.operand;
925 int r2 = (++it)->u.operand;
926 int r3 = (++it)->u.operand;
927 int r4 = (++it)->u.operand;
928 int r5 = (++it)->u.operand;
929 printf("[%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());
930 break;
931 }
932 case op_put_by_val: {
933 int r0 = (++it)->u.operand;
934 int r1 = (++it)->u.operand;
935 int r2 = (++it)->u.operand;
936 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
937 break;
938 }
939 case op_del_by_val: {
940 int r0 = (++it)->u.operand;
941 int r1 = (++it)->u.operand;
942 int r2 = (++it)->u.operand;
943 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
944 break;
945 }
946 case op_put_by_index: {
947 int r0 = (++it)->u.operand;
948 unsigned n0 = (++it)->u.operand;
949 int r1 = (++it)->u.operand;
950 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data());
951 break;
952 }
953 case op_jmp: {
954 int offset = (++it)->u.operand;
955 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset);
956 break;
957 }
958 case op_loop: {
959 int offset = (++it)->u.operand;
960 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset);
961 break;
962 }
963 case op_jtrue: {
964 printConditionalJump(exec, begin, it, location, "jtrue");
965 break;
966 }
967 case op_loop_if_true: {
968 printConditionalJump(exec, begin, it, location, "loop_if_true");
969 break;
970 }
971 case op_loop_if_false: {
972 printConditionalJump(exec, begin, it, location, "loop_if_false");
973 break;
974 }
975 case op_jfalse: {
976 printConditionalJump(exec, begin, it, location, "jfalse");
977 break;
978 }
979 case op_jeq_null: {
980 printConditionalJump(exec, begin, it, location, "jeq_null");
981 break;
982 }
983 case op_jneq_null: {
984 printConditionalJump(exec, begin, it, location, "jneq_null");
985 break;
986 }
987 case op_jneq_ptr: {
988 int r0 = (++it)->u.operand;
989 int r1 = (++it)->u.operand;
990 int offset = (++it)->u.operand;
991 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
992 break;
993 }
994 case op_jnless: {
995 int r0 = (++it)->u.operand;
996 int r1 = (++it)->u.operand;
997 int offset = (++it)->u.operand;
998 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
999 break;
1000 }
1001 case op_jnlesseq: {
1002 int r0 = (++it)->u.operand;
1003 int r1 = (++it)->u.operand;
1004 int offset = (++it)->u.operand;
1005 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1006 break;
1007 }
1008 case op_loop_if_less: {
1009 int r0 = (++it)->u.operand;
1010 int r1 = (++it)->u.operand;
1011 int offset = (++it)->u.operand;
1012 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1013 break;
1014 }
1015 case op_jless: {
1016 int r0 = (++it)->u.operand;
1017 int r1 = (++it)->u.operand;
1018 int offset = (++it)->u.operand;
1019 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1020 break;
1021 }
1022 case op_jlesseq: {
1023 int r0 = (++it)->u.operand;
1024 int r1 = (++it)->u.operand;
1025 int offset = (++it)->u.operand;
1026 printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1027 break;
1028 }
1029 case op_loop_if_lesseq: {
1030 int r0 = (++it)->u.operand;
1031 int r1 = (++it)->u.operand;
1032 int offset = (++it)->u.operand;
1033 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1034 break;
1035 }
1036 case op_switch_imm: {
1037 int tableIndex = (++it)->u.operand;
1038 int defaultTarget = (++it)->u.operand;
1039 int scrutineeRegister = (++it)->u.operand;
1040 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1041 break;
1042 }
1043 case op_switch_char: {
1044 int tableIndex = (++it)->u.operand;
1045 int defaultTarget = (++it)->u.operand;
1046 int scrutineeRegister = (++it)->u.operand;
1047 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1048 break;
1049 }
1050 case op_switch_string: {
1051 int tableIndex = (++it)->u.operand;
1052 int defaultTarget = (++it)->u.operand;
1053 int scrutineeRegister = (++it)->u.operand;
1054 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1055 break;
1056 }
1057 case op_new_func: {
1058 int r0 = (++it)->u.operand;
1059 int f0 = (++it)->u.operand;
1060 int shouldCheck = (++it)->u.operand;
1061 printf("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
1062 break;
1063 }
1064 case op_new_func_exp: {
1065 int r0 = (++it)->u.operand;
1066 int f0 = (++it)->u.operand;
1067 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).data(), f0);
1068 break;
1069 }
1070 case op_call: {
1071 int func = (++it)->u.operand;
1072 int argCount = (++it)->u.operand;
1073 int registerOffset = (++it)->u.operand;
1074 printf("[%4d] call\t\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1075 break;
1076 }
1077 case op_call_eval: {
1078 int func = (++it)->u.operand;
1079 int argCount = (++it)->u.operand;
1080 int registerOffset = (++it)->u.operand;
1081 printf("[%4d] call_eval\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1082 break;
1083 }
1084 case op_call_varargs: {
1085 int func = (++it)->u.operand;
1086 int argCount = (++it)->u.operand;
1087 int registerOffset = (++it)->u.operand;
1088 printf("[%4d] call_varargs\t %s, %s, %d\n", location, registerName(exec, func).data(), registerName(exec, argCount).data(), registerOffset);
1089 break;
1090 }
1091 case op_load_varargs: {
1092 printUnaryOp(exec, location, it, "load_varargs");
1093 break;
1094 }
1095 case op_tear_off_activation: {
1096 int r0 = (++it)->u.operand;
1097 int r1 = (++it)->u.operand;
1098 printf("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1099 break;
1100 }
1101 case op_tear_off_arguments: {
1102 int r0 = (++it)->u.operand;
1103 printf("[%4d] tear_off_arguments\t %s\n", location, registerName(exec, r0).data());
1104 break;
1105 }
1106 case op_ret: {
1107 int r0 = (++it)->u.operand;
1108 printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data());
1109 break;
1110 }
1111 case op_call_put_result: {
1112 int r0 = (++it)->u.operand;
1113 printf("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
1114 break;
1115 }
1116 case op_ret_object_or_this: {
1117 int r0 = (++it)->u.operand;
1118 int r1 = (++it)->u.operand;
1119 printf("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1120 break;
1121 }
1122 case op_construct: {
1123 int func = (++it)->u.operand;
1124 int argCount = (++it)->u.operand;
1125 int registerOffset = (++it)->u.operand;
1126 printf("[%4d] construct\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1127 break;
1128 }
1129 case op_strcat: {
1130 int r0 = (++it)->u.operand;
1131 int r1 = (++it)->u.operand;
1132 int count = (++it)->u.operand;
1133 printf("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count);
1134 break;
1135 }
1136 case op_to_primitive: {
1137 int r0 = (++it)->u.operand;
1138 int r1 = (++it)->u.operand;
1139 printf("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1140 break;
1141 }
1142 case op_get_pnames: {
1143 int r0 = it[1].u.operand;
1144 int r1 = it[2].u.operand;
1145 int r2 = it[3].u.operand;
1146 int r3 = it[4].u.operand;
1147 int offset = it[5].u.operand;
1148 printf("[%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);
1149 it += OPCODE_LENGTH(op_get_pnames) - 1;
1150 break;
1151 }
1152 case op_next_pname: {
1153 int dest = it[1].u.operand;
1154 int base = it[2].u.operand;
1155 int i = it[3].u.operand;
1156 int size = it[4].u.operand;
1157 int iter = it[5].u.operand;
1158 int offset = it[6].u.operand;
1159 printf("[%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);
1160 it += OPCODE_LENGTH(op_next_pname) - 1;
1161 break;
1162 }
1163 case op_push_scope: {
1164 int r0 = (++it)->u.operand;
1165 printf("[%4d] push_scope\t %s\n", location, registerName(exec, r0).data());
1166 break;
1167 }
1168 case op_pop_scope: {
1169 printf("[%4d] pop_scope\n", location);
1170 break;
1171 }
1172 case op_push_new_scope: {
1173 int r0 = (++it)->u.operand;
1174 int id0 = (++it)->u.operand;
1175 int r1 = (++it)->u.operand;
1176 printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
1177 break;
1178 }
1179 case op_jmp_scopes: {
1180 int scopeDelta = (++it)->u.operand;
1181 int offset = (++it)->u.operand;
1182 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset);
1183 break;
1184 }
1185 case op_catch: {
1186 int r0 = (++it)->u.operand;
1187 printf("[%4d] catch\t\t %s\n", location, registerName(exec, r0).data());
1188 break;
1189 }
1190 case op_throw: {
1191 int r0 = (++it)->u.operand;
1192 printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data());
1193 break;
1194 }
1195 case op_throw_reference_error: {
1196 int k0 = (++it)->u.operand;
1197 printf("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data());
1198 break;
1199 }
1200 case op_jsr: {
1201 int retAddrDst = (++it)->u.operand;
1202 int offset = (++it)->u.operand;
1203 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).data(), offset, location + offset);
1204 break;
1205 }
1206 case op_sret: {
1207 int retAddrSrc = (++it)->u.operand;
1208 printf("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).data());
1209 break;
1210 }
1211 case op_debug: {
1212 int debugHookID = (++it)->u.operand;
1213 int firstLine = (++it)->u.operand;
1214 int lastLine = (++it)->u.operand;
1215 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1216 break;
1217 }
1218 case op_profile_will_call: {
1219 int function = (++it)->u.operand;
1220 printf("[%4d] profile_will_call %s\n", location, registerName(exec, function).data());
1221 break;
1222 }
1223 case op_profile_did_call: {
1224 int function = (++it)->u.operand;
1225 printf("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).data());
1226 break;
1227 }
1228 case op_end: {
1229 int r0 = (++it)->u.operand;
1230 printf("[%4d] end\t\t %s\n", location, registerName(exec, r0).data());
1231 break;
1232 }
1233 }
1234 }
1235
1236 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1237
1238 #if DUMP_CODE_BLOCK_STATISTICS
1239 static HashSet<CodeBlock*> liveCodeBlockSet;
1240 #endif
1241
1242 #define FOR_EACH_MEMBER_VECTOR(macro) \
1243 macro(instructions) \
1244 macro(globalResolveInfos) \
1245 macro(structureStubInfos) \
1246 macro(callLinkInfos) \
1247 macro(linkedCallerList) \
1248 macro(identifiers) \
1249 macro(functionExpressions) \
1250 macro(constantRegisters)
1251
1252 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1253 macro(regexps) \
1254 macro(functions) \
1255 macro(exceptionHandlers) \
1256 macro(immediateSwitchJumpTables) \
1257 macro(characterSwitchJumpTables) \
1258 macro(stringSwitchJumpTables) \
1259 macro(evalCodeCache) \
1260 macro(expressionInfo) \
1261 macro(lineInfo) \
1262 macro(callReturnIndexVector)
1263
1264 template<typename T>
sizeInBytes(const Vector<T> & vector)1265 static size_t sizeInBytes(const Vector<T>& vector)
1266 {
1267 return vector.capacity() * sizeof(T);
1268 }
1269
dumpStatistics()1270 void CodeBlock::dumpStatistics()
1271 {
1272 #if DUMP_CODE_BLOCK_STATISTICS
1273 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1274 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1275 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1276 #undef DEFINE_VARS
1277
1278 // Non-vector data members
1279 size_t evalCodeCacheIsNotEmpty = 0;
1280
1281 size_t symbolTableIsNotEmpty = 0;
1282 size_t symbolTableTotalSize = 0;
1283
1284 size_t hasRareData = 0;
1285
1286 size_t isFunctionCode = 0;
1287 size_t isGlobalCode = 0;
1288 size_t isEvalCode = 0;
1289
1290 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1291 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1292 CodeBlock* codeBlock = *it;
1293
1294 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1295 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1296 #undef GET_STATS
1297
1298 if (!codeBlock->m_symbolTable.isEmpty()) {
1299 symbolTableIsNotEmpty++;
1300 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1301 }
1302
1303 if (codeBlock->m_rareData) {
1304 hasRareData++;
1305 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1306 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1307 #undef GET_STATS
1308
1309 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1310 evalCodeCacheIsNotEmpty++;
1311 }
1312
1313 switch (codeBlock->codeType()) {
1314 case FunctionCode:
1315 ++isFunctionCode;
1316 break;
1317 case GlobalCode:
1318 ++isGlobalCode;
1319 break;
1320 case EvalCode:
1321 ++isEvalCode;
1322 break;
1323 }
1324 }
1325
1326 size_t totalSize = 0;
1327
1328 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1329 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1330 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1331 #undef GET_TOTAL_SIZE
1332
1333 totalSize += symbolTableTotalSize;
1334 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1335
1336 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1337 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1338 printf("Size of all CodeBlocks: %zu\n", totalSize);
1339 printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1340
1341 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1342 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1343 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1344
1345 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1346
1347 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1348 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1349 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1350 #undef PRINT_STATS
1351
1352 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1353 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1354
1355 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1356
1357 #else
1358 printf("Dumping CodeBlock statistics is not enabled.\n");
1359 #endif
1360 }
1361
CodeBlock(ScriptExecutable * ownerExecutable,CodeType codeType,JSGlobalObject * globalObject,PassRefPtr<SourceProvider> sourceProvider,unsigned sourceOffset,SymbolTable * symTab,bool isConstructor)1362 CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor)
1363 : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject)
1364 , m_heap(&m_globalObject->globalData().heap)
1365 , m_numCalleeRegisters(0)
1366 , m_numVars(0)
1367 , m_numParameters(0)
1368 , m_isConstructor(isConstructor)
1369 , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
1370 , m_globalData(0)
1371 #ifndef NDEBUG
1372 , m_instructionCount(0)
1373 #endif
1374 , m_argumentsRegister(-1)
1375 , m_needsFullScopeChain(ownerExecutable->needsActivation())
1376 , m_usesEval(ownerExecutable->usesEval())
1377 , m_isNumericCompareFunction(false)
1378 , m_isStrictMode(ownerExecutable->isStrictMode())
1379 , m_codeType(codeType)
1380 , m_source(sourceProvider)
1381 , m_sourceOffset(sourceOffset)
1382 , m_symbolTable(symTab)
1383 {
1384 ASSERT(m_source);
1385
1386 #if DUMP_CODE_BLOCK_STATISTICS
1387 liveCodeBlockSet.add(this);
1388 #endif
1389 }
1390
~CodeBlock()1391 CodeBlock::~CodeBlock()
1392 {
1393 #if ENABLE(JIT)
1394 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1395 m_structureStubInfos[i].deref();
1396 #endif // ENABLE(JIT)
1397
1398 #if DUMP_CODE_BLOCK_STATISTICS
1399 liveCodeBlockSet.remove(this);
1400 #endif
1401 }
1402
markStructures(MarkStack & markStack,Instruction * vPC) const1403 void CodeBlock::markStructures(MarkStack& markStack, Instruction* vPC) const
1404 {
1405 Interpreter* interpreter = m_globalData->interpreter;
1406
1407 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)) {
1408 markStack.append(&vPC[4].u.structure);
1409 return;
1410 }
1411 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)) {
1412 markStack.append(&vPC[4].u.structure);
1413 markStack.append(&vPC[5].u.structure);
1414 return;
1415 }
1416 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)) {
1417 markStack.append(&vPC[4].u.structure);
1418 markStack.append(&vPC[5].u.structureChain);
1419 return;
1420 }
1421 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1422 markStack.append(&vPC[4].u.structure);
1423 markStack.append(&vPC[5].u.structure);
1424 markStack.append(&vPC[6].u.structureChain);
1425 return;
1426 }
1427 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1428 markStack.append(&vPC[4].u.structure);
1429 return;
1430 }
1431 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global) || vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
1432 if (vPC[3].u.structure)
1433 markStack.append(&vPC[3].u.structure);
1434 return;
1435 }
1436 if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
1437 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))
1438 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto_list))
1439 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list))
1440 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto_list))
1441 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self_list))) {
1442 PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
1443 polymorphicStructures->markAggregate(markStack, vPC[5].u.operand);
1444 delete polymorphicStructures;
1445 return;
1446 }
1447
1448 // These instructions don't ref their Structures.
1449 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));
1450 }
1451
markAggregate(MarkStack & markStack)1452 void EvalCodeCache::markAggregate(MarkStack& markStack)
1453 {
1454 EvalCacheMap::iterator end = m_cacheMap.end();
1455 for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr)
1456 markStack.append(&ptr->second);
1457 }
1458
markAggregate(MarkStack & markStack)1459 void CodeBlock::markAggregate(MarkStack& markStack)
1460 {
1461 markStack.append(&m_globalObject);
1462 markStack.append(&m_ownerExecutable);
1463 if (m_rareData)
1464 m_rareData->m_evalCodeCache.markAggregate(markStack);
1465 markStack.appendValues(m_constantRegisters.data(), m_constantRegisters.size());
1466 for (size_t i = 0; i < m_functionExprs.size(); ++i)
1467 markStack.append(&m_functionExprs[i]);
1468 for (size_t i = 0; i < m_functionDecls.size(); ++i)
1469 markStack.append(&m_functionDecls[i]);
1470 #if ENABLE(JIT_OPTIMIZE_CALL)
1471 for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i)
1472 if (callLinkInfo(i).isLinked())
1473 markStack.append(&callLinkInfo(i).callee);
1474 #endif
1475 #if ENABLE(INTERPRETER)
1476 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1477 markStructures(markStack, &m_instructions[m_propertyAccessInstructions[i]]);
1478 #endif
1479 #if ENABLE(JIT)
1480 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1481 if (m_globalResolveInfos[i].structure)
1482 markStack.append(&m_globalResolveInfos[i].structure);
1483 }
1484
1485 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1486 m_structureStubInfos[i].markAggregate(markStack);
1487
1488 for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
1489 if (m_methodCallLinkInfos[i].cachedStructure) {
1490 // Both members must be filled at the same time
1491 markStack.append(&m_methodCallLinkInfos[i].cachedStructure);
1492 ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
1493 markStack.append(&m_methodCallLinkInfos[i].cachedPrototypeStructure);
1494 }
1495 }
1496 #endif
1497 }
1498
handlerForBytecodeOffset(unsigned bytecodeOffset)1499 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1500 {
1501 ASSERT(bytecodeOffset < m_instructionCount);
1502
1503 if (!m_rareData)
1504 return 0;
1505
1506 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1507 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1508 // Handlers are ordered innermost first, so the first handler we encounter
1509 // that contains the source address is the correct handler to use.
1510 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1511 return &exceptionHandlers[i];
1512 }
1513
1514 return 0;
1515 }
1516
lineNumberForBytecodeOffset(unsigned bytecodeOffset)1517 int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
1518 {
1519 ASSERT(bytecodeOffset < m_instructionCount);
1520
1521 if (!m_rareData)
1522 return m_ownerExecutable->source().firstLine();
1523
1524 Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
1525
1526 int low = 0;
1527 int high = lineInfo.size();
1528 while (low < high) {
1529 int mid = low + (high - low) / 2;
1530 if (lineInfo[mid].instructionOffset <= bytecodeOffset)
1531 low = mid + 1;
1532 else
1533 high = mid;
1534 }
1535
1536 if (!low)
1537 return m_ownerExecutable->source().firstLine();
1538 return lineInfo[low - 1].lineNumber;
1539 }
1540
expressionRangeForBytecodeOffset(unsigned bytecodeOffset,int & divot,int & startOffset,int & endOffset)1541 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1542 {
1543 ASSERT(bytecodeOffset < m_instructionCount);
1544
1545 if (!m_rareData) {
1546 startOffset = 0;
1547 endOffset = 0;
1548 divot = 0;
1549 return;
1550 }
1551
1552 Vector<ExpressionRangeInfo>& expressionInfo = m_rareData->m_expressionInfo;
1553
1554 int low = 0;
1555 int high = expressionInfo.size();
1556 while (low < high) {
1557 int mid = low + (high - low) / 2;
1558 if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
1559 low = mid + 1;
1560 else
1561 high = mid;
1562 }
1563
1564 ASSERT(low);
1565 if (!low) {
1566 startOffset = 0;
1567 endOffset = 0;
1568 divot = 0;
1569 return;
1570 }
1571
1572 startOffset = expressionInfo[low - 1].startOffset;
1573 endOffset = expressionInfo[low - 1].endOffset;
1574 divot = expressionInfo[low - 1].divotPoint + m_sourceOffset;
1575 return;
1576 }
1577
1578 #if ENABLE(INTERPRETER)
hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)1579 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1580 {
1581 if (m_globalResolveInstructions.isEmpty())
1582 return false;
1583
1584 int low = 0;
1585 int high = m_globalResolveInstructions.size();
1586 while (low < high) {
1587 int mid = low + (high - low) / 2;
1588 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1589 low = mid + 1;
1590 else
1591 high = mid;
1592 }
1593
1594 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1595 return false;
1596 return true;
1597 }
1598 #endif
1599 #if ENABLE(JIT)
hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)1600 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1601 {
1602 if (m_globalResolveInfos.isEmpty())
1603 return false;
1604
1605 int low = 0;
1606 int high = m_globalResolveInfos.size();
1607 while (low < high) {
1608 int mid = low + (high - low) / 2;
1609 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1610 low = mid + 1;
1611 else
1612 high = mid;
1613 }
1614
1615 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1616 return false;
1617 return true;
1618 }
1619 #endif
1620
shrinkToFit()1621 void CodeBlock::shrinkToFit()
1622 {
1623 m_instructions.shrinkToFit();
1624
1625 #if ENABLE(INTERPRETER)
1626 m_propertyAccessInstructions.shrinkToFit();
1627 m_globalResolveInstructions.shrinkToFit();
1628 #endif
1629 #if ENABLE(JIT)
1630 m_structureStubInfos.shrinkToFit();
1631 m_globalResolveInfos.shrinkToFit();
1632 m_callLinkInfos.shrinkToFit();
1633 #endif
1634
1635 m_identifiers.shrinkToFit();
1636 m_functionDecls.shrinkToFit();
1637 m_functionExprs.shrinkToFit();
1638 m_constantRegisters.shrinkToFit();
1639
1640 if (m_rareData) {
1641 m_rareData->m_exceptionHandlers.shrinkToFit();
1642 m_rareData->m_regexps.shrinkToFit();
1643 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1644 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1645 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1646 m_rareData->m_expressionInfo.shrinkToFit();
1647 m_rareData->m_lineInfo.shrinkToFit();
1648 }
1649 }
1650
createActivation(CallFrame * callFrame)1651 void CodeBlock::createActivation(CallFrame* callFrame)
1652 {
1653 ASSERT(codeType() == FunctionCode);
1654 ASSERT(needsFullScopeChain());
1655 ASSERT(!callFrame->uncheckedR(activationRegister()).jsValue());
1656 JSActivation* activation = new (callFrame) JSActivation(callFrame, static_cast<FunctionExecutable*>(ownerExecutable()));
1657 callFrame->uncheckedR(activationRegister()) = JSValue(activation);
1658 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
1659 }
1660
1661 } // namespace JSC
1662