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 #endif
401 #if ENABLE(INTERPRETER)
402 if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
403 printf("\nStructures:\n");
404
405 if (!m_globalResolveInstructions.isEmpty()) {
406 size_t i = 0;
407 do {
408 printStructures(&m_instructions[m_globalResolveInstructions[i]]);
409 ++i;
410 } while (i < m_globalResolveInstructions.size());
411 }
412 if (!m_propertyAccessInstructions.isEmpty()) {
413 size_t i = 0;
414 do {
415 printStructures(&m_instructions[m_propertyAccessInstructions[i]]);
416 ++i;
417 } while (i < m_propertyAccessInstructions.size());
418 }
419 #endif
420
421 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
422 printf("\nException Handlers:\n");
423 unsigned i = 0;
424 do {
425 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);
426 ++i;
427 } while (i < m_rareData->m_exceptionHandlers.size());
428 }
429
430 if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
431 printf("Immediate Switch Jump Tables:\n");
432 unsigned i = 0;
433 do {
434 printf(" %1d = {\n", i);
435 int entry = 0;
436 Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
437 for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
438 if (!*iter)
439 continue;
440 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
441 }
442 printf(" }\n");
443 ++i;
444 } while (i < m_rareData->m_immediateSwitchJumpTables.size());
445 }
446
447 if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
448 printf("\nCharacter Switch Jump Tables:\n");
449 unsigned i = 0;
450 do {
451 printf(" %1d = {\n", i);
452 int entry = 0;
453 Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
454 for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
455 if (!*iter)
456 continue;
457 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
458 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
459 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).utf8().data(), *iter);
460 }
461 printf(" }\n");
462 ++i;
463 } while (i < m_rareData->m_characterSwitchJumpTables.size());
464 }
465
466 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
467 printf("\nString Switch Jump Tables:\n");
468 unsigned i = 0;
469 do {
470 printf(" %1d = {\n", i);
471 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
472 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
473 printf("\t\t\"%s\" => %04d\n", UString(iter->first).utf8().data(), iter->second.branchOffset);
474 printf(" }\n");
475 ++i;
476 } while (i < m_rareData->m_stringSwitchJumpTables.size());
477 }
478
479 printf("\n");
480 }
481
dump(ExecState * exec,const Vector<Instruction>::const_iterator & begin,Vector<Instruction>::const_iterator & it) const482 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
483 {
484 int location = it - begin;
485 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
486 case op_enter: {
487 printf("[%4d] enter\n", location);
488 break;
489 }
490 case op_create_activation: {
491 int r0 = (++it)->u.operand;
492 printf("[%4d] create_activation %s\n", location, registerName(exec, r0).data());
493 break;
494 }
495 case op_create_arguments: {
496 int r0 = (++it)->u.operand;
497 printf("[%4d] create_arguments\t %s\n", location, registerName(exec, r0).data());
498 break;
499 }
500 case op_init_lazy_reg: {
501 int r0 = (++it)->u.operand;
502 printf("[%4d] init_lazy_reg\t %s\n", location, registerName(exec, r0).data());
503 break;
504 }
505 case op_get_callee: {
506 int r0 = (++it)->u.operand;
507 printf("[%4d] op_get_callee %s\n", location, registerName(exec, r0).data());
508 break;
509 }
510 case op_create_this: {
511 int r0 = (++it)->u.operand;
512 int r1 = (++it)->u.operand;
513 printf("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
514 break;
515 }
516 case op_convert_this: {
517 int r0 = (++it)->u.operand;
518 printf("[%4d] convert_this %s\n", location, registerName(exec, r0).data());
519 break;
520 }
521 case op_convert_this_strict: {
522 int r0 = (++it)->u.operand;
523 printf("[%4d] convert_this_strict %s\n", location, registerName(exec, r0).data());
524 break;
525 }
526 case op_new_object: {
527 int r0 = (++it)->u.operand;
528 printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).data());
529 break;
530 }
531 case op_new_array: {
532 int dst = (++it)->u.operand;
533 int argv = (++it)->u.operand;
534 int argc = (++it)->u.operand;
535 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).data(), registerName(exec, argv).data(), argc);
536 break;
537 }
538 case op_new_regexp: {
539 int r0 = (++it)->u.operand;
540 int re0 = (++it)->u.operand;
541 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(exec, r0).data(), regexpName(re0, regexp(re0)).data());
542 break;
543 }
544 case op_mov: {
545 int r0 = (++it)->u.operand;
546 int r1 = (++it)->u.operand;
547 printf("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
548 break;
549 }
550 case op_not: {
551 printUnaryOp(exec, location, it, "not");
552 break;
553 }
554 case op_eq: {
555 printBinaryOp(exec, location, it, "eq");
556 break;
557 }
558 case op_eq_null: {
559 printUnaryOp(exec, location, it, "eq_null");
560 break;
561 }
562 case op_neq: {
563 printBinaryOp(exec, location, it, "neq");
564 break;
565 }
566 case op_neq_null: {
567 printUnaryOp(exec, location, it, "neq_null");
568 break;
569 }
570 case op_stricteq: {
571 printBinaryOp(exec, location, it, "stricteq");
572 break;
573 }
574 case op_nstricteq: {
575 printBinaryOp(exec, location, it, "nstricteq");
576 break;
577 }
578 case op_less: {
579 printBinaryOp(exec, location, it, "less");
580 break;
581 }
582 case op_lesseq: {
583 printBinaryOp(exec, location, it, "lesseq");
584 break;
585 }
586 case op_pre_inc: {
587 int r0 = (++it)->u.operand;
588 printf("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).data());
589 break;
590 }
591 case op_pre_dec: {
592 int r0 = (++it)->u.operand;
593 printf("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).data());
594 break;
595 }
596 case op_post_inc: {
597 printUnaryOp(exec, location, it, "post_inc");
598 break;
599 }
600 case op_post_dec: {
601 printUnaryOp(exec, location, it, "post_dec");
602 break;
603 }
604 case op_to_jsnumber: {
605 printUnaryOp(exec, location, it, "to_jsnumber");
606 break;
607 }
608 case op_negate: {
609 printUnaryOp(exec, location, it, "negate");
610 break;
611 }
612 case op_add: {
613 printBinaryOp(exec, location, it, "add");
614 ++it;
615 break;
616 }
617 case op_mul: {
618 printBinaryOp(exec, location, it, "mul");
619 ++it;
620 break;
621 }
622 case op_div: {
623 printBinaryOp(exec, location, it, "div");
624 ++it;
625 break;
626 }
627 case op_mod: {
628 printBinaryOp(exec, location, it, "mod");
629 break;
630 }
631 case op_sub: {
632 printBinaryOp(exec, location, it, "sub");
633 ++it;
634 break;
635 }
636 case op_lshift: {
637 printBinaryOp(exec, location, it, "lshift");
638 break;
639 }
640 case op_rshift: {
641 printBinaryOp(exec, location, it, "rshift");
642 break;
643 }
644 case op_urshift: {
645 printBinaryOp(exec, location, it, "urshift");
646 break;
647 }
648 case op_bitand: {
649 printBinaryOp(exec, location, it, "bitand");
650 ++it;
651 break;
652 }
653 case op_bitxor: {
654 printBinaryOp(exec, location, it, "bitxor");
655 ++it;
656 break;
657 }
658 case op_bitor: {
659 printBinaryOp(exec, location, it, "bitor");
660 ++it;
661 break;
662 }
663 case op_bitnot: {
664 printUnaryOp(exec, location, it, "bitnot");
665 break;
666 }
667 case op_check_has_instance: {
668 int base = (++it)->u.operand;
669 printf("[%4d] check_has_instance\t\t %s\n", location, registerName(exec, base).data());
670 break;
671 }
672 case op_instanceof: {
673 int r0 = (++it)->u.operand;
674 int r1 = (++it)->u.operand;
675 int r2 = (++it)->u.operand;
676 int r3 = (++it)->u.operand;
677 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());
678 break;
679 }
680 case op_typeof: {
681 printUnaryOp(exec, location, it, "typeof");
682 break;
683 }
684 case op_is_undefined: {
685 printUnaryOp(exec, location, it, "is_undefined");
686 break;
687 }
688 case op_is_boolean: {
689 printUnaryOp(exec, location, it, "is_boolean");
690 break;
691 }
692 case op_is_number: {
693 printUnaryOp(exec, location, it, "is_number");
694 break;
695 }
696 case op_is_string: {
697 printUnaryOp(exec, location, it, "is_string");
698 break;
699 }
700 case op_is_object: {
701 printUnaryOp(exec, location, it, "is_object");
702 break;
703 }
704 case op_is_function: {
705 printUnaryOp(exec, location, it, "is_function");
706 break;
707 }
708 case op_in: {
709 printBinaryOp(exec, location, it, "in");
710 break;
711 }
712 case op_resolve: {
713 int r0 = (++it)->u.operand;
714 int id0 = (++it)->u.operand;
715 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
716 break;
717 }
718 case op_resolve_skip: {
719 int r0 = (++it)->u.operand;
720 int id0 = (++it)->u.operand;
721 int skipLevels = (++it)->u.operand;
722 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), skipLevels);
723 break;
724 }
725 case op_resolve_global: {
726 int r0 = (++it)->u.operand;
727 int id0 = (++it)->u.operand;
728 printf("[%4d] resolve_global\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
729 it += 2;
730 break;
731 }
732 case op_resolve_global_dynamic: {
733 int r0 = (++it)->u.operand;
734 int id0 = (++it)->u.operand;
735 JSValue scope = JSValue((++it)->u.jsCell.get());
736 ++it;
737 int depth = (++it)->u.operand;
738 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);
739 break;
740 }
741 case op_get_scoped_var: {
742 int r0 = (++it)->u.operand;
743 int index = (++it)->u.operand;
744 int skipLevels = (++it)->u.operand;
745 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).data(), index, skipLevels);
746 break;
747 }
748 case op_put_scoped_var: {
749 int index = (++it)->u.operand;
750 int skipLevels = (++it)->u.operand;
751 int r0 = (++it)->u.operand;
752 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).data());
753 break;
754 }
755 case op_get_global_var: {
756 int r0 = (++it)->u.operand;
757 int index = (++it)->u.operand;
758 printf("[%4d] get_global_var\t %s, %d\n", location, registerName(exec, r0).data(), index);
759 break;
760 }
761 case op_put_global_var: {
762 int index = (++it)->u.operand;
763 int r0 = (++it)->u.operand;
764 printf("[%4d] put_global_var\t %d, %s\n", location, index, registerName(exec, r0).data());
765 break;
766 }
767 case op_resolve_base: {
768 int r0 = (++it)->u.operand;
769 int id0 = (++it)->u.operand;
770 int isStrict = (++it)->u.operand;
771 printf("[%4d] resolve_base%s\t %s, %s\n", location, isStrict ? "_strict" : "", registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
772 break;
773 }
774 case op_ensure_property_exists: {
775 int r0 = (++it)->u.operand;
776 int id0 = (++it)->u.operand;
777 printf("[%4d] ensure_property_exists\t %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data());
778 break;
779 }
780 case op_resolve_with_base: {
781 int r0 = (++it)->u.operand;
782 int r1 = (++it)->u.operand;
783 int id0 = (++it)->u.operand;
784 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), idName(id0, m_identifiers[id0]).data());
785 break;
786 }
787 case op_get_by_id: {
788 printGetByIdOp(exec, location, it, "get_by_id");
789 break;
790 }
791 case op_get_by_id_self: {
792 printGetByIdOp(exec, location, it, "get_by_id_self");
793 break;
794 }
795 case op_get_by_id_self_list: {
796 printGetByIdOp(exec, location, it, "get_by_id_self_list");
797 break;
798 }
799 case op_get_by_id_proto: {
800 printGetByIdOp(exec, location, it, "get_by_id_proto");
801 break;
802 }
803 case op_get_by_id_proto_list: {
804 printGetByIdOp(exec, location, it, "op_get_by_id_proto_list");
805 break;
806 }
807 case op_get_by_id_chain: {
808 printGetByIdOp(exec, location, it, "get_by_id_chain");
809 break;
810 }
811 case op_get_by_id_getter_self: {
812 printGetByIdOp(exec, location, it, "get_by_id_getter_self");
813 break;
814 }
815 case op_get_by_id_getter_self_list: {
816 printGetByIdOp(exec, location, it, "get_by_id_getter_self_list");
817 break;
818 }
819 case op_get_by_id_getter_proto: {
820 printGetByIdOp(exec, location, it, "get_by_id_getter_proto");
821 break;
822 }
823 case op_get_by_id_getter_proto_list: {
824 printGetByIdOp(exec, location, it, "get_by_id_getter_proto_list");
825 break;
826 }
827 case op_get_by_id_getter_chain: {
828 printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
829 break;
830 }
831 case op_get_by_id_custom_self: {
832 printGetByIdOp(exec, location, it, "get_by_id_custom_self");
833 break;
834 }
835 case op_get_by_id_custom_self_list: {
836 printGetByIdOp(exec, location, it, "get_by_id_custom_self_list");
837 break;
838 }
839 case op_get_by_id_custom_proto: {
840 printGetByIdOp(exec, location, it, "get_by_id_custom_proto");
841 break;
842 }
843 case op_get_by_id_custom_proto_list: {
844 printGetByIdOp(exec, location, it, "get_by_id_custom_proto_list");
845 break;
846 }
847 case op_get_by_id_custom_chain: {
848 printGetByIdOp(exec, location, it, "get_by_id_custom_chain");
849 break;
850 }
851 case op_get_by_id_generic: {
852 printGetByIdOp(exec, location, it, "get_by_id_generic");
853 break;
854 }
855 case op_get_array_length: {
856 printGetByIdOp(exec, location, it, "get_array_length");
857 break;
858 }
859 case op_get_string_length: {
860 printGetByIdOp(exec, location, it, "get_string_length");
861 break;
862 }
863 case op_get_arguments_length: {
864 printUnaryOp(exec, location, it, "get_arguments_length");
865 it++;
866 break;
867 }
868 case op_put_by_id: {
869 printPutByIdOp(exec, location, it, "put_by_id");
870 break;
871 }
872 case op_put_by_id_replace: {
873 printPutByIdOp(exec, location, it, "put_by_id_replace");
874 break;
875 }
876 case op_put_by_id_transition: {
877 printPutByIdOp(exec, location, it, "put_by_id_transition");
878 break;
879 }
880 case op_put_by_id_generic: {
881 printPutByIdOp(exec, location, it, "put_by_id_generic");
882 break;
883 }
884 case op_put_getter: {
885 int r0 = (++it)->u.operand;
886 int id0 = (++it)->u.operand;
887 int r1 = (++it)->u.operand;
888 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
889 break;
890 }
891 case op_put_setter: {
892 int r0 = (++it)->u.operand;
893 int id0 = (++it)->u.operand;
894 int r1 = (++it)->u.operand;
895 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).data(), idName(id0, m_identifiers[id0]).data(), registerName(exec, r1).data());
896 break;
897 }
898 case op_method_check: {
899 printf("[%4d] method_check\n", location);
900 break;
901 }
902 case op_del_by_id: {
903 int r0 = (++it)->u.operand;
904 int r1 = (++it)->u.operand;
905 int id0 = (++it)->u.operand;
906 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());
907 break;
908 }
909 case op_get_by_val: {
910 int r0 = (++it)->u.operand;
911 int r1 = (++it)->u.operand;
912 int r2 = (++it)->u.operand;
913 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
914 break;
915 }
916 case op_get_argument_by_val: {
917 int r0 = (++it)->u.operand;
918 int r1 = (++it)->u.operand;
919 int r2 = (++it)->u.operand;
920 printf("[%4d] get_argument_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
921 break;
922 }
923 case op_get_by_pname: {
924 int r0 = (++it)->u.operand;
925 int r1 = (++it)->u.operand;
926 int r2 = (++it)->u.operand;
927 int r3 = (++it)->u.operand;
928 int r4 = (++it)->u.operand;
929 int r5 = (++it)->u.operand;
930 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());
931 break;
932 }
933 case op_put_by_val: {
934 int r0 = (++it)->u.operand;
935 int r1 = (++it)->u.operand;
936 int r2 = (++it)->u.operand;
937 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
938 break;
939 }
940 case op_del_by_val: {
941 int r0 = (++it)->u.operand;
942 int r1 = (++it)->u.operand;
943 int r2 = (++it)->u.operand;
944 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), registerName(exec, r2).data());
945 break;
946 }
947 case op_put_by_index: {
948 int r0 = (++it)->u.operand;
949 unsigned n0 = (++it)->u.operand;
950 int r1 = (++it)->u.operand;
951 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).data(), n0, registerName(exec, r1).data());
952 break;
953 }
954 case op_jmp: {
955 int offset = (++it)->u.operand;
956 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset);
957 break;
958 }
959 case op_loop: {
960 int offset = (++it)->u.operand;
961 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset);
962 break;
963 }
964 case op_jtrue: {
965 printConditionalJump(exec, begin, it, location, "jtrue");
966 break;
967 }
968 case op_loop_if_true: {
969 printConditionalJump(exec, begin, it, location, "loop_if_true");
970 break;
971 }
972 case op_loop_if_false: {
973 printConditionalJump(exec, begin, it, location, "loop_if_false");
974 break;
975 }
976 case op_jfalse: {
977 printConditionalJump(exec, begin, it, location, "jfalse");
978 break;
979 }
980 case op_jeq_null: {
981 printConditionalJump(exec, begin, it, location, "jeq_null");
982 break;
983 }
984 case op_jneq_null: {
985 printConditionalJump(exec, begin, it, location, "jneq_null");
986 break;
987 }
988 case op_jneq_ptr: {
989 int r0 = (++it)->u.operand;
990 int r1 = (++it)->u.operand;
991 int offset = (++it)->u.operand;
992 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
993 break;
994 }
995 case op_jnless: {
996 int r0 = (++it)->u.operand;
997 int r1 = (++it)->u.operand;
998 int offset = (++it)->u.operand;
999 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1000 break;
1001 }
1002 case op_jnlesseq: {
1003 int r0 = (++it)->u.operand;
1004 int r1 = (++it)->u.operand;
1005 int offset = (++it)->u.operand;
1006 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1007 break;
1008 }
1009 case op_loop_if_less: {
1010 int r0 = (++it)->u.operand;
1011 int r1 = (++it)->u.operand;
1012 int offset = (++it)->u.operand;
1013 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1014 break;
1015 }
1016 case op_jless: {
1017 int r0 = (++it)->u.operand;
1018 int r1 = (++it)->u.operand;
1019 int offset = (++it)->u.operand;
1020 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1021 break;
1022 }
1023 case op_jlesseq: {
1024 int r0 = (++it)->u.operand;
1025 int r1 = (++it)->u.operand;
1026 int offset = (++it)->u.operand;
1027 printf("[%4d] jlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1028 break;
1029 }
1030 case op_loop_if_lesseq: {
1031 int r0 = (++it)->u.operand;
1032 int r1 = (++it)->u.operand;
1033 int offset = (++it)->u.operand;
1034 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), offset, location + offset);
1035 break;
1036 }
1037 case op_switch_imm: {
1038 int tableIndex = (++it)->u.operand;
1039 int defaultTarget = (++it)->u.operand;
1040 int scrutineeRegister = (++it)->u.operand;
1041 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1042 break;
1043 }
1044 case op_switch_char: {
1045 int tableIndex = (++it)->u.operand;
1046 int defaultTarget = (++it)->u.operand;
1047 int scrutineeRegister = (++it)->u.operand;
1048 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1049 break;
1050 }
1051 case op_switch_string: {
1052 int tableIndex = (++it)->u.operand;
1053 int defaultTarget = (++it)->u.operand;
1054 int scrutineeRegister = (++it)->u.operand;
1055 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).data());
1056 break;
1057 }
1058 case op_new_func: {
1059 int r0 = (++it)->u.operand;
1060 int f0 = (++it)->u.operand;
1061 int shouldCheck = (++it)->u.operand;
1062 printf("[%4d] new_func\t\t %s, f%d, %s\n", location, registerName(exec, r0).data(), f0, shouldCheck ? "<Checked>" : "<Unchecked>");
1063 break;
1064 }
1065 case op_new_func_exp: {
1066 int r0 = (++it)->u.operand;
1067 int f0 = (++it)->u.operand;
1068 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).data(), f0);
1069 break;
1070 }
1071 case op_call: {
1072 int func = (++it)->u.operand;
1073 int argCount = (++it)->u.operand;
1074 int registerOffset = (++it)->u.operand;
1075 printf("[%4d] call\t\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1076 break;
1077 }
1078 case op_call_eval: {
1079 int func = (++it)->u.operand;
1080 int argCount = (++it)->u.operand;
1081 int registerOffset = (++it)->u.operand;
1082 printf("[%4d] call_eval\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1083 break;
1084 }
1085 case op_call_varargs: {
1086 int func = (++it)->u.operand;
1087 int argCount = (++it)->u.operand;
1088 int registerOffset = (++it)->u.operand;
1089 printf("[%4d] call_varargs\t %s, %s, %d\n", location, registerName(exec, func).data(), registerName(exec, argCount).data(), registerOffset);
1090 break;
1091 }
1092 case op_load_varargs: {
1093 printUnaryOp(exec, location, it, "load_varargs");
1094 break;
1095 }
1096 case op_tear_off_activation: {
1097 int r0 = (++it)->u.operand;
1098 int r1 = (++it)->u.operand;
1099 printf("[%4d] tear_off_activation\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1100 break;
1101 }
1102 case op_tear_off_arguments: {
1103 int r0 = (++it)->u.operand;
1104 printf("[%4d] tear_off_arguments\t %s\n", location, registerName(exec, r0).data());
1105 break;
1106 }
1107 case op_ret: {
1108 int r0 = (++it)->u.operand;
1109 printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).data());
1110 break;
1111 }
1112 case op_call_put_result: {
1113 int r0 = (++it)->u.operand;
1114 printf("[%4d] op_call_put_result\t\t %s\n", location, registerName(exec, r0).data());
1115 break;
1116 }
1117 case op_ret_object_or_this: {
1118 int r0 = (++it)->u.operand;
1119 int r1 = (++it)->u.operand;
1120 printf("[%4d] constructor_ret\t\t %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1121 break;
1122 }
1123 case op_construct: {
1124 int func = (++it)->u.operand;
1125 int argCount = (++it)->u.operand;
1126 int registerOffset = (++it)->u.operand;
1127 printf("[%4d] construct\t %s, %d, %d\n", location, registerName(exec, func).data(), argCount, registerOffset);
1128 break;
1129 }
1130 case op_strcat: {
1131 int r0 = (++it)->u.operand;
1132 int r1 = (++it)->u.operand;
1133 int count = (++it)->u.operand;
1134 printf("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).data(), registerName(exec, r1).data(), count);
1135 break;
1136 }
1137 case op_to_primitive: {
1138 int r0 = (++it)->u.operand;
1139 int r1 = (++it)->u.operand;
1140 printf("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
1141 break;
1142 }
1143 case op_get_pnames: {
1144 int r0 = it[1].u.operand;
1145 int r1 = it[2].u.operand;
1146 int r2 = it[3].u.operand;
1147 int r3 = it[4].u.operand;
1148 int offset = it[5].u.operand;
1149 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);
1150 it += OPCODE_LENGTH(op_get_pnames) - 1;
1151 break;
1152 }
1153 case op_next_pname: {
1154 int dest = it[1].u.operand;
1155 int base = it[2].u.operand;
1156 int i = it[3].u.operand;
1157 int size = it[4].u.operand;
1158 int iter = it[5].u.operand;
1159 int offset = it[6].u.operand;
1160 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);
1161 it += OPCODE_LENGTH(op_next_pname) - 1;
1162 break;
1163 }
1164 case op_push_scope: {
1165 int r0 = (++it)->u.operand;
1166 printf("[%4d] push_scope\t %s\n", location, registerName(exec, r0).data());
1167 break;
1168 }
1169 case op_pop_scope: {
1170 printf("[%4d] pop_scope\n", location);
1171 break;
1172 }
1173 case op_push_new_scope: {
1174 int r0 = (++it)->u.operand;
1175 int id0 = (++it)->u.operand;
1176 int r1 = (++it)->u.operand;
1177 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());
1178 break;
1179 }
1180 case op_jmp_scopes: {
1181 int scopeDelta = (++it)->u.operand;
1182 int offset = (++it)->u.operand;
1183 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset);
1184 break;
1185 }
1186 case op_catch: {
1187 int r0 = (++it)->u.operand;
1188 printf("[%4d] catch\t\t %s\n", location, registerName(exec, r0).data());
1189 break;
1190 }
1191 case op_throw: {
1192 int r0 = (++it)->u.operand;
1193 printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).data());
1194 break;
1195 }
1196 case op_throw_reference_error: {
1197 int k0 = (++it)->u.operand;
1198 printf("[%4d] throw_reference_error\t %s\n", location, constantName(exec, k0, getConstant(k0)).data());
1199 break;
1200 }
1201 case op_jsr: {
1202 int retAddrDst = (++it)->u.operand;
1203 int offset = (++it)->u.operand;
1204 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).data(), offset, location + offset);
1205 break;
1206 }
1207 case op_sret: {
1208 int retAddrSrc = (++it)->u.operand;
1209 printf("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).data());
1210 break;
1211 }
1212 case op_debug: {
1213 int debugHookID = (++it)->u.operand;
1214 int firstLine = (++it)->u.operand;
1215 int lastLine = (++it)->u.operand;
1216 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1217 break;
1218 }
1219 case op_profile_will_call: {
1220 int function = (++it)->u.operand;
1221 printf("[%4d] profile_will_call %s\n", location, registerName(exec, function).data());
1222 break;
1223 }
1224 case op_profile_did_call: {
1225 int function = (++it)->u.operand;
1226 printf("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).data());
1227 break;
1228 }
1229 case op_end: {
1230 int r0 = (++it)->u.operand;
1231 printf("[%4d] end\t\t %s\n", location, registerName(exec, r0).data());
1232 break;
1233 }
1234 }
1235 }
1236
1237 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1238
1239 #if DUMP_CODE_BLOCK_STATISTICS
1240 static HashSet<CodeBlock*> liveCodeBlockSet;
1241 #endif
1242
1243 #define FOR_EACH_MEMBER_VECTOR(macro) \
1244 macro(instructions) \
1245 macro(globalResolveInfos) \
1246 macro(structureStubInfos) \
1247 macro(callLinkInfos) \
1248 macro(linkedCallerList) \
1249 macro(identifiers) \
1250 macro(functionExpressions) \
1251 macro(constantRegisters)
1252
1253 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1254 macro(regexps) \
1255 macro(functions) \
1256 macro(exceptionHandlers) \
1257 macro(immediateSwitchJumpTables) \
1258 macro(characterSwitchJumpTables) \
1259 macro(stringSwitchJumpTables) \
1260 macro(evalCodeCache) \
1261 macro(expressionInfo) \
1262 macro(lineInfo) \
1263 macro(callReturnIndexVector)
1264
1265 template<typename T>
sizeInBytes(const Vector<T> & vector)1266 static size_t sizeInBytes(const Vector<T>& vector)
1267 {
1268 return vector.capacity() * sizeof(T);
1269 }
1270
dumpStatistics()1271 void CodeBlock::dumpStatistics()
1272 {
1273 #if DUMP_CODE_BLOCK_STATISTICS
1274 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1275 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1276 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1277 #undef DEFINE_VARS
1278
1279 // Non-vector data members
1280 size_t evalCodeCacheIsNotEmpty = 0;
1281
1282 size_t symbolTableIsNotEmpty = 0;
1283 size_t symbolTableTotalSize = 0;
1284
1285 size_t hasRareData = 0;
1286
1287 size_t isFunctionCode = 0;
1288 size_t isGlobalCode = 0;
1289 size_t isEvalCode = 0;
1290
1291 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1292 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1293 CodeBlock* codeBlock = *it;
1294
1295 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1296 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1297 #undef GET_STATS
1298
1299 if (!codeBlock->m_symbolTable.isEmpty()) {
1300 symbolTableIsNotEmpty++;
1301 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1302 }
1303
1304 if (codeBlock->m_rareData) {
1305 hasRareData++;
1306 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1307 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1308 #undef GET_STATS
1309
1310 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1311 evalCodeCacheIsNotEmpty++;
1312 }
1313
1314 switch (codeBlock->codeType()) {
1315 case FunctionCode:
1316 ++isFunctionCode;
1317 break;
1318 case GlobalCode:
1319 ++isGlobalCode;
1320 break;
1321 case EvalCode:
1322 ++isEvalCode;
1323 break;
1324 }
1325 }
1326
1327 size_t totalSize = 0;
1328
1329 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1330 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1331 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1332 #undef GET_TOTAL_SIZE
1333
1334 totalSize += symbolTableTotalSize;
1335 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1336
1337 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1338 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1339 printf("Size of all CodeBlocks: %zu\n", totalSize);
1340 printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1341
1342 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1343 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1344 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1345
1346 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1347
1348 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1349 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1350 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1351 #undef PRINT_STATS
1352
1353 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1354 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1355
1356 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1357
1358 #else
1359 printf("Dumping CodeBlock statistics is not enabled.\n");
1360 #endif
1361 }
1362
CodeBlock(ScriptExecutable * ownerExecutable,CodeType codeType,JSGlobalObject * globalObject,PassRefPtr<SourceProvider> sourceProvider,unsigned sourceOffset,SymbolTable * symTab,bool isConstructor)1363 CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor)
1364 : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject)
1365 , m_heap(&m_globalObject->globalData().heap)
1366 , m_numCalleeRegisters(0)
1367 , m_numVars(0)
1368 , m_numParameters(0)
1369 , m_isConstructor(isConstructor)
1370 , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
1371 , m_globalData(0)
1372 #ifndef NDEBUG
1373 , m_instructionCount(0)
1374 #endif
1375 , m_argumentsRegister(-1)
1376 , m_needsFullScopeChain(ownerExecutable->needsActivation())
1377 , m_usesEval(ownerExecutable->usesEval())
1378 , m_isNumericCompareFunction(false)
1379 , m_isStrictMode(ownerExecutable->isStrictMode())
1380 , m_codeType(codeType)
1381 , m_source(sourceProvider)
1382 , m_sourceOffset(sourceOffset)
1383 , m_symbolTable(symTab)
1384 {
1385 ASSERT(m_source);
1386
1387 #if DUMP_CODE_BLOCK_STATISTICS
1388 liveCodeBlockSet.add(this);
1389 #endif
1390 }
1391
~CodeBlock()1392 CodeBlock::~CodeBlock()
1393 {
1394 #if ENABLE(JIT)
1395 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1396 m_structureStubInfos[i].deref();
1397 #endif // ENABLE(JIT)
1398
1399 #if DUMP_CODE_BLOCK_STATISTICS
1400 liveCodeBlockSet.remove(this);
1401 #endif
1402 }
1403
visitStructures(SlotVisitor & visitor,Instruction * vPC) const1404 void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) const
1405 {
1406 Interpreter* interpreter = m_globalData->interpreter;
1407
1408 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)) {
1409 visitor.append(&vPC[4].u.structure);
1410 return;
1411 }
1412 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)) {
1413 visitor.append(&vPC[4].u.structure);
1414 visitor.append(&vPC[5].u.structure);
1415 return;
1416 }
1417 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)) {
1418 visitor.append(&vPC[4].u.structure);
1419 visitor.append(&vPC[5].u.structureChain);
1420 return;
1421 }
1422 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1423 visitor.append(&vPC[4].u.structure);
1424 visitor.append(&vPC[5].u.structure);
1425 visitor.append(&vPC[6].u.structureChain);
1426 return;
1427 }
1428 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1429 visitor.append(&vPC[4].u.structure);
1430 return;
1431 }
1432 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global) || vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global_dynamic)) {
1433 if (vPC[3].u.structure)
1434 visitor.append(&vPC[3].u.structure);
1435 return;
1436 }
1437 if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
1438 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))
1439 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto_list))
1440 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list))
1441 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_proto_list))
1442 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self_list))) {
1443 PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
1444 polymorphicStructures->visitAggregate(visitor, vPC[5].u.operand);
1445 delete polymorphicStructures;
1446 return;
1447 }
1448
1449 // These instructions don't ref their Structures.
1450 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));
1451 }
1452
visitAggregate(SlotVisitor & visitor)1453 void EvalCodeCache::visitAggregate(SlotVisitor& visitor)
1454 {
1455 EvalCacheMap::iterator end = m_cacheMap.end();
1456 for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr)
1457 visitor.append(&ptr->second);
1458 }
1459
visitAggregate(SlotVisitor & visitor)1460 void CodeBlock::visitAggregate(SlotVisitor& visitor)
1461 {
1462 visitor.append(&m_globalObject);
1463 visitor.append(&m_ownerExecutable);
1464 if (m_rareData)
1465 m_rareData->m_evalCodeCache.visitAggregate(visitor);
1466 visitor.appendValues(m_constantRegisters.data(), m_constantRegisters.size());
1467 for (size_t i = 0; i < m_functionExprs.size(); ++i)
1468 visitor.append(&m_functionExprs[i]);
1469 for (size_t i = 0; i < m_functionDecls.size(); ++i)
1470 visitor.append(&m_functionDecls[i]);
1471 #if ENABLE(JIT_OPTIMIZE_CALL)
1472 for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i)
1473 if (callLinkInfo(i).isLinked())
1474 visitor.append(&callLinkInfo(i).callee);
1475 #endif
1476 #if ENABLE(INTERPRETER)
1477 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1478 visitStructures(visitor, &m_instructions[m_propertyAccessInstructions[i]]);
1479 #endif
1480 #if ENABLE(JIT)
1481 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1482 if (m_globalResolveInfos[i].structure)
1483 visitor.append(&m_globalResolveInfos[i].structure);
1484 }
1485
1486 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1487 m_structureStubInfos[i].visitAggregate(visitor);
1488
1489 for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
1490 if (m_methodCallLinkInfos[i].cachedStructure) {
1491 // Both members must be filled at the same time
1492 visitor.append(&m_methodCallLinkInfos[i].cachedStructure);
1493 ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
1494 visitor.append(&m_methodCallLinkInfos[i].cachedPrototypeStructure);
1495 }
1496 }
1497 #endif
1498 }
1499
handlerForBytecodeOffset(unsigned bytecodeOffset)1500 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1501 {
1502 ASSERT(bytecodeOffset < m_instructionCount);
1503
1504 if (!m_rareData)
1505 return 0;
1506
1507 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1508 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1509 // Handlers are ordered innermost first, so the first handler we encounter
1510 // that contains the source address is the correct handler to use.
1511 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1512 return &exceptionHandlers[i];
1513 }
1514
1515 return 0;
1516 }
1517
lineNumberForBytecodeOffset(unsigned bytecodeOffset)1518 int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
1519 {
1520 ASSERT(bytecodeOffset < m_instructionCount);
1521
1522 if (!m_rareData)
1523 return m_ownerExecutable->source().firstLine();
1524
1525 Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
1526
1527 int low = 0;
1528 int high = lineInfo.size();
1529 while (low < high) {
1530 int mid = low + (high - low) / 2;
1531 if (lineInfo[mid].instructionOffset <= bytecodeOffset)
1532 low = mid + 1;
1533 else
1534 high = mid;
1535 }
1536
1537 if (!low)
1538 return m_ownerExecutable->source().firstLine();
1539 return lineInfo[low - 1].lineNumber;
1540 }
1541
expressionRangeForBytecodeOffset(unsigned bytecodeOffset,int & divot,int & startOffset,int & endOffset)1542 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1543 {
1544 ASSERT(bytecodeOffset < m_instructionCount);
1545
1546 if (!m_rareData) {
1547 startOffset = 0;
1548 endOffset = 0;
1549 divot = 0;
1550 return;
1551 }
1552
1553 Vector<ExpressionRangeInfo>& expressionInfo = m_rareData->m_expressionInfo;
1554
1555 int low = 0;
1556 int high = expressionInfo.size();
1557 while (low < high) {
1558 int mid = low + (high - low) / 2;
1559 if (expressionInfo[mid].instructionOffset <= bytecodeOffset)
1560 low = mid + 1;
1561 else
1562 high = mid;
1563 }
1564
1565 ASSERT(low);
1566 if (!low) {
1567 startOffset = 0;
1568 endOffset = 0;
1569 divot = 0;
1570 return;
1571 }
1572
1573 startOffset = expressionInfo[low - 1].startOffset;
1574 endOffset = expressionInfo[low - 1].endOffset;
1575 divot = expressionInfo[low - 1].divotPoint + m_sourceOffset;
1576 return;
1577 }
1578
1579 #if ENABLE(INTERPRETER)
hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)1580 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1581 {
1582 if (m_globalResolveInstructions.isEmpty())
1583 return false;
1584
1585 int low = 0;
1586 int high = m_globalResolveInstructions.size();
1587 while (low < high) {
1588 int mid = low + (high - low) / 2;
1589 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1590 low = mid + 1;
1591 else
1592 high = mid;
1593 }
1594
1595 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1596 return false;
1597 return true;
1598 }
1599 #endif
1600 #if ENABLE(JIT)
hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)1601 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1602 {
1603 if (m_globalResolveInfos.isEmpty())
1604 return false;
1605
1606 int low = 0;
1607 int high = m_globalResolveInfos.size();
1608 while (low < high) {
1609 int mid = low + (high - low) / 2;
1610 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1611 low = mid + 1;
1612 else
1613 high = mid;
1614 }
1615
1616 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1617 return false;
1618 return true;
1619 }
1620 #endif
1621
shrinkToFit()1622 void CodeBlock::shrinkToFit()
1623 {
1624 m_instructions.shrinkToFit();
1625
1626 #if ENABLE(INTERPRETER)
1627 m_propertyAccessInstructions.shrinkToFit();
1628 m_globalResolveInstructions.shrinkToFit();
1629 #endif
1630 #if ENABLE(JIT)
1631 m_structureStubInfos.shrinkToFit();
1632 m_globalResolveInfos.shrinkToFit();
1633 m_callLinkInfos.shrinkToFit();
1634 #endif
1635
1636 m_identifiers.shrinkToFit();
1637 m_functionDecls.shrinkToFit();
1638 m_functionExprs.shrinkToFit();
1639 m_constantRegisters.shrinkToFit();
1640
1641 if (m_rareData) {
1642 m_rareData->m_exceptionHandlers.shrinkToFit();
1643 m_rareData->m_regexps.shrinkToFit();
1644 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1645 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1646 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1647 m_rareData->m_expressionInfo.shrinkToFit();
1648 m_rareData->m_lineInfo.shrinkToFit();
1649 }
1650 }
1651
createActivation(CallFrame * callFrame)1652 void CodeBlock::createActivation(CallFrame* callFrame)
1653 {
1654 ASSERT(codeType() == FunctionCode);
1655 ASSERT(needsFullScopeChain());
1656 ASSERT(!callFrame->uncheckedR(activationRegister()).jsValue());
1657 JSActivation* activation = new (callFrame) JSActivation(callFrame, static_cast<FunctionExecutable*>(ownerExecutable()));
1658 callFrame->uncheckedR(activationRegister()) = JSValue(activation);
1659 callFrame->setScopeChain(callFrame->scopeChain()->push(activation));
1660 }
1661
1662 } // namespace JSC
1663