1 /*
2 * Copyright (C) 2008, 2009 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 "JIT.h"
34 #include "JSValue.h"
35 #include "Interpreter.h"
36 #include "Debugger.h"
37 #include "BytecodeGenerator.h"
38 #include <stdio.h>
39 #include <wtf/StringExtras.h>
40
41 #define DUMP_CODE_BLOCK_STATISTICS 0
42
43 namespace JSC {
44
45 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
46
escapeQuotes(const UString & str)47 static UString escapeQuotes(const UString& str)
48 {
49 UString result = str;
50 int pos = 0;
51 while ((pos = result.find('\"', pos)) >= 0) {
52 result = result.substr(0, pos) + "\"\\\"\"" + result.substr(pos + 1);
53 pos += 4;
54 }
55 return result;
56 }
57
valueToSourceString(ExecState * exec,JSValue val)58 static UString valueToSourceString(ExecState* exec, JSValue val)
59 {
60 if (!val)
61 return "0";
62
63 if (val.isString()) {
64 UString result("\"");
65 result += escapeQuotes(val.toString(exec)) + "\"";
66 return result;
67 }
68
69 return val.toString(exec);
70 }
71
registerName(int r)72 static CString registerName(int r)
73 {
74 if (r == missingThisObjectMarker())
75 return "<null>";
76
77 return (UString("r") + UString::from(r)).UTF8String();
78 }
79
constantName(ExecState * exec,int k,JSValue value)80 static CString constantName(ExecState* exec, int k, JSValue value)
81 {
82 return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String();
83 }
84
idName(int id0,const Identifier & ident)85 static CString idName(int id0, const Identifier& ident)
86 {
87 return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String();
88 }
89
regexpToSourceString(RegExp * regExp)90 static UString regexpToSourceString(RegExp* regExp)
91 {
92 UString pattern = UString("/") + regExp->pattern() + "/";
93 if (regExp->global())
94 pattern += "g";
95 if (regExp->ignoreCase())
96 pattern += "i";
97 if (regExp->multiline())
98 pattern += "m";
99
100 return pattern;
101 }
102
regexpName(int re,RegExp * regexp)103 static CString regexpName(int re, RegExp* regexp)
104 {
105 return (regexpToSourceString(regexp) + "(@re" + UString::from(re) + ")").UTF8String();
106 }
107
pointerToSourceString(void * p)108 static UString pointerToSourceString(void* p)
109 {
110 char buffer[2 + 2 * sizeof(void*) + 1]; // 0x [two characters per byte] \0
111 snprintf(buffer, sizeof(buffer), "%p", p);
112 return buffer;
113 }
114
debugHookName(int debugHookID)115 NEVER_INLINE static const char* debugHookName(int debugHookID)
116 {
117 switch (static_cast<DebugHookID>(debugHookID)) {
118 case DidEnterCallFrame:
119 return "didEnterCallFrame";
120 case WillLeaveCallFrame:
121 return "willLeaveCallFrame";
122 case WillExecuteStatement:
123 return "willExecuteStatement";
124 case WillExecuteProgram:
125 return "willExecuteProgram";
126 case DidExecuteProgram:
127 return "didExecuteProgram";
128 case DidReachBreakpoint:
129 return "didReachBreakpoint";
130 }
131
132 ASSERT_NOT_REACHED();
133 return "";
134 }
135
locationForOffset(const Vector<Instruction>::const_iterator & begin,Vector<Instruction>::const_iterator & it,int offset)136 static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset)
137 {
138 return it - begin + offset;
139 }
140
printUnaryOp(int location,Vector<Instruction>::const_iterator & it,const char * op)141 static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
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(r0).c_str(), registerName(r1).c_str());
147 }
148
printBinaryOp(int location,Vector<Instruction>::const_iterator & it,const char * op)149 static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op)
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(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
155 }
156
printConditionalJump(const Vector<Instruction>::const_iterator & begin,Vector<Instruction>::const_iterator & it,int location,const char * op)157 static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op)
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(r0).c_str(), offset, locationForOffset(begin, it, offset));
162 }
163
printGetByIdOp(int location,Vector<Instruction>::const_iterator & it,const Vector<Identifier> & m_identifiers,const char * op)164 static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
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(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
170 it += 4;
171 }
172
printPutByIdOp(int location,Vector<Instruction>::const_iterator & it,const Vector<Identifier> & m_identifiers,const char * op)173 static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op)
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(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
179 it += 4;
180 }
181
182 #if ENABLE(JIT)
isGlobalResolve(OpcodeID opcodeID)183 static bool isGlobalResolve(OpcodeID opcodeID)
184 {
185 return opcodeID == op_resolve_global;
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).UTF8String().c_str());
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).UTF8String().c_str());
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).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdProto.prototypeStructure).UTF8String().c_str());
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).UTF8String().c_str(), pointerToSourceString(stubInfo.u.getByIdChain.chain).UTF8String().c_str());
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).UTF8String().c_str(), 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).UTF8String().c_str(), 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).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.structure).UTF8String().c_str(), pointerToSourceString(stubInfo.u.putByIdTransition.chain).UTF8String().c_str());
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).UTF8String().c_str());
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).UTF8String().c_str());
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).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str());
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).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structure).UTF8String().c_str(), pointerToSourceString(vPC[6].u.structureChain).UTF8String().c_str());
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).UTF8String().c_str(), pointerToSourceString(vPC[5].u.structureChain).UTF8String().c_str());
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
323 // These m_instructions doesn't ref Structures.
324 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));
325 }
326
dump(ExecState * exec) const327 void CodeBlock::dump(ExecState* exec) const
328 {
329 if (m_instructions.isEmpty()) {
330 printf("No instructions available.\n");
331 return;
332 }
333
334 size_t instructionCount = 0;
335
336 for (size_t i = 0; i < m_instructions.size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(m_instructions[i].u.opcode)])
337 ++instructionCount;
338
339 printf("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
340 static_cast<unsigned long>(instructionCount),
341 static_cast<unsigned long>(m_instructions.size() * sizeof(Instruction)),
342 this, m_numParameters, m_numCalleeRegisters);
343
344 Vector<Instruction>::const_iterator begin = m_instructions.begin();
345 Vector<Instruction>::const_iterator end = m_instructions.end();
346 for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
347 dump(exec, begin, it);
348
349 if (!m_identifiers.isEmpty()) {
350 printf("\nIdentifiers:\n");
351 size_t i = 0;
352 do {
353 printf(" id%u = %s\n", static_cast<unsigned>(i), m_identifiers[i].ascii());
354 ++i;
355 } while (i != m_identifiers.size());
356 }
357
358 if (!m_constantRegisters.isEmpty()) {
359 printf("\nConstants:\n");
360 unsigned registerIndex = m_numVars;
361 size_t i = 0;
362 do {
363 printf(" r%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue()).ascii());
364 ++i;
365 ++registerIndex;
366 } while (i < m_constantRegisters.size());
367 }
368
369 if (m_rareData && !m_rareData->m_regexps.isEmpty()) {
370 printf("\nm_regexps:\n");
371 size_t i = 0;
372 do {
373 printf(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).ascii());
374 ++i;
375 } while (i < m_rareData->m_regexps.size());
376 }
377
378 #if ENABLE(JIT)
379 if (!m_globalResolveInfos.isEmpty() || !m_structureStubInfos.isEmpty())
380 printf("\nStructures:\n");
381
382 if (!m_globalResolveInfos.isEmpty()) {
383 size_t i = 0;
384 do {
385 printGlobalResolveInfo(m_globalResolveInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isGlobalResolve));
386 ++i;
387 } while (i < m_globalResolveInfos.size());
388 }
389 if (!m_structureStubInfos.isEmpty()) {
390 size_t i = 0;
391 do {
392 printStructureStubInfo(m_structureStubInfos[i], instructionOffsetForNth(exec, m_instructions, i + 1, isPropertyAccess));
393 ++i;
394 } while (i < m_structureStubInfos.size());
395 }
396 #else
397 if (!m_globalResolveInstructions.isEmpty() || !m_propertyAccessInstructions.isEmpty())
398 printf("\nStructures:\n");
399
400 if (!m_globalResolveInstructions.isEmpty()) {
401 size_t i = 0;
402 do {
403 printStructures(&m_instructions[m_globalResolveInstructions[i]]);
404 ++i;
405 } while (i < m_globalResolveInstructions.size());
406 }
407 if (!m_propertyAccessInstructions.isEmpty()) {
408 size_t i = 0;
409 do {
410 printStructures(&m_instructions[m_propertyAccessInstructions[i]]);
411 ++i;
412 } while (i < m_propertyAccessInstructions.size());
413 }
414 #endif
415
416 if (m_rareData && !m_rareData->m_exceptionHandlers.isEmpty()) {
417 printf("\nException Handlers:\n");
418 unsigned i = 0;
419 do {
420 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);
421 ++i;
422 } while (i < m_rareData->m_exceptionHandlers.size());
423 }
424
425 if (m_rareData && !m_rareData->m_immediateSwitchJumpTables.isEmpty()) {
426 printf("Immediate Switch Jump Tables:\n");
427 unsigned i = 0;
428 do {
429 printf(" %1d = {\n", i);
430 int entry = 0;
431 Vector<int32_t>::const_iterator end = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.end();
432 for (Vector<int32_t>::const_iterator iter = m_rareData->m_immediateSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
433 if (!*iter)
434 continue;
435 printf("\t\t%4d => %04d\n", entry + m_rareData->m_immediateSwitchJumpTables[i].min, *iter);
436 }
437 printf(" }\n");
438 ++i;
439 } while (i < m_rareData->m_immediateSwitchJumpTables.size());
440 }
441
442 if (m_rareData && !m_rareData->m_characterSwitchJumpTables.isEmpty()) {
443 printf("\nCharacter Switch Jump Tables:\n");
444 unsigned i = 0;
445 do {
446 printf(" %1d = {\n", i);
447 int entry = 0;
448 Vector<int32_t>::const_iterator end = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.end();
449 for (Vector<int32_t>::const_iterator iter = m_rareData->m_characterSwitchJumpTables[i].branchOffsets.begin(); iter != end; ++iter, ++entry) {
450 if (!*iter)
451 continue;
452 ASSERT(!((i + m_rareData->m_characterSwitchJumpTables[i].min) & ~0xFFFF));
453 UChar ch = static_cast<UChar>(entry + m_rareData->m_characterSwitchJumpTables[i].min);
454 printf("\t\t\"%s\" => %04d\n", UString(&ch, 1).ascii(), *iter);
455 }
456 printf(" }\n");
457 ++i;
458 } while (i < m_rareData->m_characterSwitchJumpTables.size());
459 }
460
461 if (m_rareData && !m_rareData->m_stringSwitchJumpTables.isEmpty()) {
462 printf("\nString Switch Jump Tables:\n");
463 unsigned i = 0;
464 do {
465 printf(" %1d = {\n", i);
466 StringJumpTable::StringOffsetTable::const_iterator end = m_rareData->m_stringSwitchJumpTables[i].offsetTable.end();
467 for (StringJumpTable::StringOffsetTable::const_iterator iter = m_rareData->m_stringSwitchJumpTables[i].offsetTable.begin(); iter != end; ++iter)
468 printf("\t\t\"%s\" => %04d\n", UString(iter->first).ascii(), iter->second.branchOffset);
469 printf(" }\n");
470 ++i;
471 } while (i < m_rareData->m_stringSwitchJumpTables.size());
472 }
473
474 printf("\n");
475 }
476
dump(ExecState * exec,const Vector<Instruction>::const_iterator & begin,Vector<Instruction>::const_iterator & it) const477 void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it) const
478 {
479 int location = it - begin;
480 switch (exec->interpreter()->getOpcodeID(it->u.opcode)) {
481 case op_enter: {
482 printf("[%4d] enter\n", location);
483 break;
484 }
485 case op_enter_with_activation: {
486 int r0 = (++it)->u.operand;
487 printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str());
488 break;
489 }
490 case op_create_arguments: {
491 printf("[%4d] create_arguments\n", location);
492 break;
493 }
494 case op_init_arguments: {
495 printf("[%4d] init_arguments\n", location);
496 break;
497 }
498 case op_convert_this: {
499 int r0 = (++it)->u.operand;
500 printf("[%4d] convert_this %s\n", location, registerName(r0).c_str());
501 break;
502 }
503 case op_new_object: {
504 int r0 = (++it)->u.operand;
505 printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str());
506 break;
507 }
508 case op_new_array: {
509 int dst = (++it)->u.operand;
510 int argv = (++it)->u.operand;
511 int argc = (++it)->u.operand;
512 printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc);
513 break;
514 }
515 case op_new_regexp: {
516 int r0 = (++it)->u.operand;
517 int re0 = (++it)->u.operand;
518 printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexp(re0)).c_str());
519 break;
520 }
521 case op_mov: {
522 int r0 = (++it)->u.operand;
523 int r1 = (++it)->u.operand;
524 printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
525 break;
526 }
527 case op_not: {
528 printUnaryOp(location, it, "not");
529 break;
530 }
531 case op_eq: {
532 printBinaryOp(location, it, "eq");
533 break;
534 }
535 case op_eq_null: {
536 printUnaryOp(location, it, "eq_null");
537 break;
538 }
539 case op_neq: {
540 printBinaryOp(location, it, "neq");
541 break;
542 }
543 case op_neq_null: {
544 printUnaryOp(location, it, "neq_null");
545 break;
546 }
547 case op_stricteq: {
548 printBinaryOp(location, it, "stricteq");
549 break;
550 }
551 case op_nstricteq: {
552 printBinaryOp(location, it, "nstricteq");
553 break;
554 }
555 case op_less: {
556 printBinaryOp(location, it, "less");
557 break;
558 }
559 case op_lesseq: {
560 printBinaryOp(location, it, "lesseq");
561 break;
562 }
563 case op_pre_inc: {
564 int r0 = (++it)->u.operand;
565 printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str());
566 break;
567 }
568 case op_pre_dec: {
569 int r0 = (++it)->u.operand;
570 printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str());
571 break;
572 }
573 case op_post_inc: {
574 printUnaryOp(location, it, "post_inc");
575 break;
576 }
577 case op_post_dec: {
578 printUnaryOp(location, it, "post_dec");
579 break;
580 }
581 case op_to_jsnumber: {
582 printUnaryOp(location, it, "to_jsnumber");
583 break;
584 }
585 case op_negate: {
586 printUnaryOp(location, it, "negate");
587 break;
588 }
589 case op_add: {
590 printBinaryOp(location, it, "add");
591 ++it;
592 break;
593 }
594 case op_mul: {
595 printBinaryOp(location, it, "mul");
596 ++it;
597 break;
598 }
599 case op_div: {
600 printBinaryOp(location, it, "div");
601 ++it;
602 break;
603 }
604 case op_mod: {
605 printBinaryOp(location, it, "mod");
606 break;
607 }
608 case op_sub: {
609 printBinaryOp(location, it, "sub");
610 ++it;
611 break;
612 }
613 case op_lshift: {
614 printBinaryOp(location, it, "lshift");
615 break;
616 }
617 case op_rshift: {
618 printBinaryOp(location, it, "rshift");
619 break;
620 }
621 case op_urshift: {
622 printBinaryOp(location, it, "urshift");
623 break;
624 }
625 case op_bitand: {
626 printBinaryOp(location, it, "bitand");
627 ++it;
628 break;
629 }
630 case op_bitxor: {
631 printBinaryOp(location, it, "bitxor");
632 ++it;
633 break;
634 }
635 case op_bitor: {
636 printBinaryOp(location, it, "bitor");
637 ++it;
638 break;
639 }
640 case op_bitnot: {
641 printUnaryOp(location, it, "bitnot");
642 break;
643 }
644 case op_instanceof: {
645 int r0 = (++it)->u.operand;
646 int r1 = (++it)->u.operand;
647 int r2 = (++it)->u.operand;
648 int r3 = (++it)->u.operand;
649 printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str());
650 break;
651 }
652 case op_typeof: {
653 printUnaryOp(location, it, "typeof");
654 break;
655 }
656 case op_is_undefined: {
657 printUnaryOp(location, it, "is_undefined");
658 break;
659 }
660 case op_is_boolean: {
661 printUnaryOp(location, it, "is_boolean");
662 break;
663 }
664 case op_is_number: {
665 printUnaryOp(location, it, "is_number");
666 break;
667 }
668 case op_is_string: {
669 printUnaryOp(location, it, "is_string");
670 break;
671 }
672 case op_is_object: {
673 printUnaryOp(location, it, "is_object");
674 break;
675 }
676 case op_is_function: {
677 printUnaryOp(location, it, "is_function");
678 break;
679 }
680 case op_in: {
681 printBinaryOp(location, it, "in");
682 break;
683 }
684 case op_resolve: {
685 int r0 = (++it)->u.operand;
686 int id0 = (++it)->u.operand;
687 printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
688 break;
689 }
690 case op_resolve_skip: {
691 int r0 = (++it)->u.operand;
692 int id0 = (++it)->u.operand;
693 int skipLevels = (++it)->u.operand;
694 printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), skipLevels);
695 break;
696 }
697 case op_resolve_global: {
698 int r0 = (++it)->u.operand;
699 JSValue scope = JSValue((++it)->u.jsCell);
700 int id0 = (++it)->u.operand;
701 printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).c_str());
702 it += 2;
703 break;
704 }
705 case op_get_scoped_var: {
706 int r0 = (++it)->u.operand;
707 int index = (++it)->u.operand;
708 int skipLevels = (++it)->u.operand;
709 printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels);
710 break;
711 }
712 case op_put_scoped_var: {
713 int index = (++it)->u.operand;
714 int skipLevels = (++it)->u.operand;
715 int r0 = (++it)->u.operand;
716 printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str());
717 break;
718 }
719 case op_get_global_var: {
720 int r0 = (++it)->u.operand;
721 JSValue scope = JSValue((++it)->u.jsCell);
722 int index = (++it)->u.operand;
723 printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index);
724 break;
725 }
726 case op_put_global_var: {
727 JSValue scope = JSValue((++it)->u.jsCell);
728 int index = (++it)->u.operand;
729 int r0 = (++it)->u.operand;
730 printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str());
731 break;
732 }
733 case op_resolve_base: {
734 int r0 = (++it)->u.operand;
735 int id0 = (++it)->u.operand;
736 printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str());
737 break;
738 }
739 case op_resolve_with_base: {
740 int r0 = (++it)->u.operand;
741 int r1 = (++it)->u.operand;
742 int id0 = (++it)->u.operand;
743 printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
744 break;
745 }
746 case op_get_by_id: {
747 printGetByIdOp(location, it, m_identifiers, "get_by_id");
748 break;
749 }
750 case op_get_by_id_self: {
751 printGetByIdOp(location, it, m_identifiers, "get_by_id_self");
752 break;
753 }
754 case op_get_by_id_self_list: {
755 printGetByIdOp(location, it, m_identifiers, "get_by_id_self_list");
756 break;
757 }
758 case op_get_by_id_proto: {
759 printGetByIdOp(location, it, m_identifiers, "get_by_id_proto");
760 break;
761 }
762 case op_get_by_id_proto_list: {
763 printGetByIdOp(location, it, m_identifiers, "op_get_by_id_proto_list");
764 break;
765 }
766 case op_get_by_id_chain: {
767 printGetByIdOp(location, it, m_identifiers, "get_by_id_chain");
768 break;
769 }
770 case op_get_by_id_generic: {
771 printGetByIdOp(location, it, m_identifiers, "get_by_id_generic");
772 break;
773 }
774 case op_get_array_length: {
775 printGetByIdOp(location, it, m_identifiers, "get_array_length");
776 break;
777 }
778 case op_get_string_length: {
779 printGetByIdOp(location, it, m_identifiers, "get_string_length");
780 break;
781 }
782 case op_put_by_id: {
783 printPutByIdOp(location, it, m_identifiers, "put_by_id");
784 break;
785 }
786 case op_put_by_id_replace: {
787 printPutByIdOp(location, it, m_identifiers, "put_by_id_replace");
788 break;
789 }
790 case op_put_by_id_transition: {
791 printPutByIdOp(location, it, m_identifiers, "put_by_id_transition");
792 break;
793 }
794 case op_put_by_id_generic: {
795 printPutByIdOp(location, it, m_identifiers, "put_by_id_generic");
796 break;
797 }
798 case op_put_getter: {
799 int r0 = (++it)->u.operand;
800 int id0 = (++it)->u.operand;
801 int r1 = (++it)->u.operand;
802 printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
803 break;
804 }
805 case op_put_setter: {
806 int r0 = (++it)->u.operand;
807 int id0 = (++it)->u.operand;
808 int r1 = (++it)->u.operand;
809 printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
810 break;
811 }
812 case op_method_check: {
813 printf("[%4d] op_method_check\n", location);
814 break;
815 }
816 case op_del_by_id: {
817 int r0 = (++it)->u.operand;
818 int r1 = (++it)->u.operand;
819 int id0 = (++it)->u.operand;
820 printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str());
821 break;
822 }
823 case op_get_by_val: {
824 int r0 = (++it)->u.operand;
825 int r1 = (++it)->u.operand;
826 int r2 = (++it)->u.operand;
827 printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
828 break;
829 }
830 case op_put_by_val: {
831 int r0 = (++it)->u.operand;
832 int r1 = (++it)->u.operand;
833 int r2 = (++it)->u.operand;
834 printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
835 break;
836 }
837 case op_del_by_val: {
838 int r0 = (++it)->u.operand;
839 int r1 = (++it)->u.operand;
840 int r2 = (++it)->u.operand;
841 printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str());
842 break;
843 }
844 case op_put_by_index: {
845 int r0 = (++it)->u.operand;
846 unsigned n0 = (++it)->u.operand;
847 int r1 = (++it)->u.operand;
848 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str());
849 break;
850 }
851 case op_jmp: {
852 int offset = (++it)->u.operand;
853 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
854 break;
855 }
856 case op_loop: {
857 int offset = (++it)->u.operand;
858 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset));
859 break;
860 }
861 case op_jtrue: {
862 printConditionalJump(begin, it, location, "jtrue");
863 break;
864 }
865 case op_loop_if_true: {
866 printConditionalJump(begin, it, location, "loop_if_true");
867 break;
868 }
869 case op_jfalse: {
870 printConditionalJump(begin, it, location, "jfalse");
871 break;
872 }
873 case op_jeq_null: {
874 printConditionalJump(begin, it, location, "jeq_null");
875 break;
876 }
877 case op_jneq_null: {
878 printConditionalJump(begin, it, location, "jneq_null");
879 break;
880 }
881 case op_jneq_ptr: {
882 int r0 = (++it)->u.operand;
883 int r1 = (++it)->u.operand;
884 int offset = (++it)->u.operand;
885 printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
886 break;
887 }
888 case op_jnless: {
889 int r0 = (++it)->u.operand;
890 int r1 = (++it)->u.operand;
891 int offset = (++it)->u.operand;
892 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
893 break;
894 }
895 case op_jnlesseq: {
896 int r0 = (++it)->u.operand;
897 int r1 = (++it)->u.operand;
898 int offset = (++it)->u.operand;
899 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
900 break;
901 }
902 case op_loop_if_less: {
903 int r0 = (++it)->u.operand;
904 int r1 = (++it)->u.operand;
905 int offset = (++it)->u.operand;
906 printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
907 break;
908 }
909 case op_loop_if_lesseq: {
910 int r0 = (++it)->u.operand;
911 int r1 = (++it)->u.operand;
912 int offset = (++it)->u.operand;
913 printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset));
914 break;
915 }
916 case op_switch_imm: {
917 int tableIndex = (++it)->u.operand;
918 int defaultTarget = (++it)->u.operand;
919 int scrutineeRegister = (++it)->u.operand;
920 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
921 break;
922 }
923 case op_switch_char: {
924 int tableIndex = (++it)->u.operand;
925 int defaultTarget = (++it)->u.operand;
926 int scrutineeRegister = (++it)->u.operand;
927 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
928 break;
929 }
930 case op_switch_string: {
931 int tableIndex = (++it)->u.operand;
932 int defaultTarget = (++it)->u.operand;
933 int scrutineeRegister = (++it)->u.operand;
934 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str());
935 break;
936 }
937 case op_new_func: {
938 int r0 = (++it)->u.operand;
939 int f0 = (++it)->u.operand;
940 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0);
941 break;
942 }
943 case op_new_func_exp: {
944 int r0 = (++it)->u.operand;
945 int f0 = (++it)->u.operand;
946 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0);
947 break;
948 }
949 case op_call: {
950 int dst = (++it)->u.operand;
951 int func = (++it)->u.operand;
952 int argCount = (++it)->u.operand;
953 int registerOffset = (++it)->u.operand;
954 printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
955 break;
956 }
957 case op_call_eval: {
958 int dst = (++it)->u.operand;
959 int func = (++it)->u.operand;
960 int argCount = (++it)->u.operand;
961 int registerOffset = (++it)->u.operand;
962 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset);
963 break;
964 }
965 case op_call_varargs: {
966 int dst = (++it)->u.operand;
967 int func = (++it)->u.operand;
968 int argCount = (++it)->u.operand;
969 int registerOffset = (++it)->u.operand;
970 printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), registerName(argCount).c_str(), registerOffset);
971 break;
972 }
973 case op_load_varargs: {
974 printUnaryOp(location, it, "load_varargs");
975 break;
976 }
977 case op_tear_off_activation: {
978 int r0 = (++it)->u.operand;
979 printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str());
980 break;
981 }
982 case op_tear_off_arguments: {
983 printf("[%4d] tear_off_arguments\n", location);
984 break;
985 }
986 case op_ret: {
987 int r0 = (++it)->u.operand;
988 printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str());
989 break;
990 }
991 case op_construct: {
992 int dst = (++it)->u.operand;
993 int func = (++it)->u.operand;
994 int argCount = (++it)->u.operand;
995 int registerOffset = (++it)->u.operand;
996 int proto = (++it)->u.operand;
997 int thisRegister = (++it)->u.operand;
998 printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset, registerName(proto).c_str(), registerName(thisRegister).c_str());
999 break;
1000 }
1001 case op_construct_verify: {
1002 int r0 = (++it)->u.operand;
1003 int r1 = (++it)->u.operand;
1004 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
1005 break;
1006 }
1007 case op_strcat: {
1008 int r0 = (++it)->u.operand;
1009 int r1 = (++it)->u.operand;
1010 int count = (++it)->u.operand;
1011 printf("[%4d] op_strcat\t %s, %s, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), count);
1012 break;
1013 }
1014 case op_to_primitive: {
1015 int r0 = (++it)->u.operand;
1016 int r1 = (++it)->u.operand;
1017 printf("[%4d] op_to_primitive\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
1018 break;
1019 }
1020 case op_get_pnames: {
1021 int r0 = (++it)->u.operand;
1022 int r1 = (++it)->u.operand;
1023 printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
1024 break;
1025 }
1026 case op_next_pname: {
1027 int dest = (++it)->u.operand;
1028 int iter = (++it)->u.operand;
1029 int offset = (++it)->u.operand;
1030 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, locationForOffset(begin, it, offset));
1031 break;
1032 }
1033 case op_push_scope: {
1034 int r0 = (++it)->u.operand;
1035 printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str());
1036 break;
1037 }
1038 case op_pop_scope: {
1039 printf("[%4d] pop_scope\n", location);
1040 break;
1041 }
1042 case op_push_new_scope: {
1043 int r0 = (++it)->u.operand;
1044 int id0 = (++it)->u.operand;
1045 int r1 = (++it)->u.operand;
1046 printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str());
1047 break;
1048 }
1049 case op_jmp_scopes: {
1050 int scopeDelta = (++it)->u.operand;
1051 int offset = (++it)->u.operand;
1052 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, locationForOffset(begin, it, offset));
1053 break;
1054 }
1055 case op_catch: {
1056 int r0 = (++it)->u.operand;
1057 printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str());
1058 break;
1059 }
1060 case op_throw: {
1061 int r0 = (++it)->u.operand;
1062 printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str());
1063 break;
1064 }
1065 case op_new_error: {
1066 int r0 = (++it)->u.operand;
1067 int errorType = (++it)->u.operand;
1068 int k0 = (++it)->u.operand;
1069 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, getConstant(k0)).c_str());
1070 break;
1071 }
1072 case op_jsr: {
1073 int retAddrDst = (++it)->u.operand;
1074 int offset = (++it)->u.operand;
1075 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, locationForOffset(begin, it, offset));
1076 break;
1077 }
1078 case op_sret: {
1079 int retAddrSrc = (++it)->u.operand;
1080 printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str());
1081 break;
1082 }
1083 case op_debug: {
1084 int debugHookID = (++it)->u.operand;
1085 int firstLine = (++it)->u.operand;
1086 int lastLine = (++it)->u.operand;
1087 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1088 break;
1089 }
1090 case op_profile_will_call: {
1091 int function = (++it)->u.operand;
1092 printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str());
1093 break;
1094 }
1095 case op_profile_did_call: {
1096 int function = (++it)->u.operand;
1097 printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str());
1098 break;
1099 }
1100 case op_end: {
1101 int r0 = (++it)->u.operand;
1102 printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str());
1103 break;
1104 }
1105 }
1106 }
1107
1108 #endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1109
1110 #if DUMP_CODE_BLOCK_STATISTICS
1111 static HashSet<CodeBlock*> liveCodeBlockSet;
1112 #endif
1113
1114 #define FOR_EACH_MEMBER_VECTOR(macro) \
1115 macro(instructions) \
1116 macro(globalResolveInfos) \
1117 macro(structureStubInfos) \
1118 macro(callLinkInfos) \
1119 macro(linkedCallerList) \
1120 macro(identifiers) \
1121 macro(functionExpressions) \
1122 macro(constantRegisters)
1123
1124 #define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1125 macro(regexps) \
1126 macro(functions) \
1127 macro(exceptionHandlers) \
1128 macro(immediateSwitchJumpTables) \
1129 macro(characterSwitchJumpTables) \
1130 macro(stringSwitchJumpTables) \
1131 macro(functionRegisterInfos)
1132
1133 #define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1134 macro(expressionInfo) \
1135 macro(lineInfo) \
1136 macro(getByIdExceptionInfo) \
1137 macro(pcVector)
1138
1139 template<typename T>
sizeInBytes(const Vector<T> & vector)1140 static size_t sizeInBytes(const Vector<T>& vector)
1141 {
1142 return vector.capacity() * sizeof(T);
1143 }
1144
dumpStatistics()1145 void CodeBlock::dumpStatistics()
1146 {
1147 #if DUMP_CODE_BLOCK_STATISTICS
1148 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1149 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1150 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1151 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS)
1152 #undef DEFINE_VARS
1153
1154 // Non-vector data members
1155 size_t evalCodeCacheIsNotEmpty = 0;
1156
1157 size_t symbolTableIsNotEmpty = 0;
1158 size_t symbolTableTotalSize = 0;
1159
1160 size_t hasExceptionInfo = 0;
1161 size_t hasRareData = 0;
1162
1163 size_t isFunctionCode = 0;
1164 size_t isGlobalCode = 0;
1165 size_t isEvalCode = 0;
1166
1167 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1168 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1169 CodeBlock* codeBlock = *it;
1170
1171 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1172 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1173 #undef GET_STATS
1174
1175 if (!codeBlock->m_symbolTable.isEmpty()) {
1176 symbolTableIsNotEmpty++;
1177 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1178 }
1179
1180 if (codeBlock->m_exceptionInfo) {
1181 hasExceptionInfo++;
1182 #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
1183 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS)
1184 #undef GET_STATS
1185 }
1186
1187 if (codeBlock->m_rareData) {
1188 hasRareData++;
1189 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1190 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1191 #undef GET_STATS
1192
1193 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1194 evalCodeCacheIsNotEmpty++;
1195 }
1196
1197 switch (codeBlock->codeType()) {
1198 case FunctionCode:
1199 ++isFunctionCode;
1200 break;
1201 case GlobalCode:
1202 ++isGlobalCode;
1203 break;
1204 case EvalCode:
1205 ++isEvalCode;
1206 break;
1207 }
1208 }
1209
1210 size_t totalSize = 0;
1211
1212 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1213 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1214 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1215 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE)
1216 #undef GET_TOTAL_SIZE
1217
1218 totalSize += symbolTableTotalSize;
1219 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1220
1221 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1222 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1223 printf("Size of all CodeBlocks: %zu\n", totalSize);
1224 printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1225
1226 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1227 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1228 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1229
1230 printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo, static_cast<double>(hasExceptionInfo) * 100.0 / liveCodeBlockSet.size());
1231 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1232
1233 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1234 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1235 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1236 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS)
1237 #undef PRINT_STATS
1238
1239 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1240 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1241
1242 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1243
1244 #else
1245 printf("Dumping CodeBlock statistics is not enabled.\n");
1246 #endif
1247 }
1248
CodeBlock(ScopeNode * ownerNode)1249 CodeBlock::CodeBlock(ScopeNode* ownerNode)
1250 : m_numCalleeRegisters(0)
1251 , m_numVars(0)
1252 , m_numParameters(0)
1253 , m_ownerNode(ownerNode)
1254 , m_globalData(0)
1255 #ifndef NDEBUG
1256 , m_instructionCount(0)
1257 #endif
1258 , m_needsFullScopeChain(false)
1259 , m_usesEval(false)
1260 , m_isNumericCompareFunction(false)
1261 , m_codeType(NativeCode)
1262 , m_source(0)
1263 , m_sourceOffset(0)
1264 , m_exceptionInfo(0)
1265 {
1266 #if DUMP_CODE_BLOCK_STATISTICS
1267 liveCodeBlockSet.add(this);
1268 #endif
1269 }
1270
CodeBlock(ScopeNode * ownerNode,CodeType codeType,PassRefPtr<SourceProvider> sourceProvider,unsigned sourceOffset)1271 CodeBlock::CodeBlock(ScopeNode* ownerNode, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset)
1272 : m_numCalleeRegisters(0)
1273 , m_numVars(0)
1274 , m_numParameters(0)
1275 , m_ownerNode(ownerNode)
1276 , m_globalData(0)
1277 #ifndef NDEBUG
1278 , m_instructionCount(0)
1279 #endif
1280 , m_needsFullScopeChain(ownerNode->needsActivation())
1281 , m_usesEval(ownerNode->usesEval())
1282 , m_isNumericCompareFunction(false)
1283 , m_codeType(codeType)
1284 , m_source(sourceProvider)
1285 , m_sourceOffset(sourceOffset)
1286 , m_exceptionInfo(new ExceptionInfo)
1287 {
1288 ASSERT(m_source);
1289
1290 #if DUMP_CODE_BLOCK_STATISTICS
1291 liveCodeBlockSet.add(this);
1292 #endif
1293 }
1294
~CodeBlock()1295 CodeBlock::~CodeBlock()
1296 {
1297 #if !ENABLE(JIT)
1298 for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
1299 derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
1300
1301 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1302 derefStructures(&m_instructions[m_propertyAccessInstructions[i]]);
1303 #else
1304 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1305 if (m_globalResolveInfos[i].structure)
1306 m_globalResolveInfos[i].structure->deref();
1307 }
1308
1309 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1310 m_structureStubInfos[i].deref();
1311
1312 for (size_t size = m_callLinkInfos.size(), i = 0; i < size; ++i) {
1313 CallLinkInfo* callLinkInfo = &m_callLinkInfos[i];
1314 if (callLinkInfo->isLinked())
1315 callLinkInfo->callee->removeCaller(callLinkInfo);
1316 }
1317
1318 for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
1319 if (Structure* structure = m_methodCallLinkInfos[i].cachedStructure) {
1320 structure->deref();
1321 // Both members must be filled at the same time
1322 ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
1323 m_methodCallLinkInfos[i].cachedPrototypeStructure->deref();
1324 }
1325 }
1326
1327 #if ENABLE(JIT_OPTIMIZE_CALL)
1328 unlinkCallers();
1329 #endif
1330
1331 #endif // !ENABLE(JIT)
1332
1333 #if DUMP_CODE_BLOCK_STATISTICS
1334 liveCodeBlockSet.remove(this);
1335 #endif
1336 }
1337
1338 #if ENABLE(JIT_OPTIMIZE_CALL)
unlinkCallers()1339 void CodeBlock::unlinkCallers()
1340 {
1341 size_t size = m_linkedCallerList.size();
1342 for (size_t i = 0; i < size; ++i) {
1343 CallLinkInfo* currentCaller = m_linkedCallerList[i];
1344 JIT::unlinkCall(currentCaller);
1345 currentCaller->setUnlinked();
1346 }
1347 m_linkedCallerList.clear();
1348 }
1349 #endif
1350
derefStructures(Instruction * vPC) const1351 void CodeBlock::derefStructures(Instruction* vPC) const
1352 {
1353 ASSERT(m_codeType != NativeCode);
1354 Interpreter* interpreter = m_globalData->interpreter;
1355
1356 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1357 vPC[4].u.structure->deref();
1358 return;
1359 }
1360 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1361 vPC[4].u.structure->deref();
1362 vPC[5].u.structure->deref();
1363 return;
1364 }
1365 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1366 vPC[4].u.structure->deref();
1367 vPC[5].u.structureChain->deref();
1368 return;
1369 }
1370 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1371 vPC[4].u.structure->deref();
1372 vPC[5].u.structure->deref();
1373 vPC[6].u.structureChain->deref();
1374 return;
1375 }
1376 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1377 vPC[4].u.structure->deref();
1378 return;
1379 }
1380 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
1381 if(vPC[4].u.structure)
1382 vPC[4].u.structure->deref();
1383 return;
1384 }
1385 if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
1386 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))) {
1387 PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
1388 polymorphicStructures->derefStructures(vPC[5].u.operand);
1389 delete polymorphicStructures;
1390 return;
1391 }
1392
1393 // These instructions don't ref their Structures.
1394 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));
1395 }
1396
refStructures(Instruction * vPC) const1397 void CodeBlock::refStructures(Instruction* vPC) const
1398 {
1399 ASSERT(m_codeType != NativeCode);
1400 Interpreter* interpreter = m_globalData->interpreter;
1401
1402 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) {
1403 vPC[4].u.structure->ref();
1404 return;
1405 }
1406 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto)) {
1407 vPC[4].u.structure->ref();
1408 vPC[5].u.structure->ref();
1409 return;
1410 }
1411 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain)) {
1412 vPC[4].u.structure->ref();
1413 vPC[5].u.structureChain->ref();
1414 return;
1415 }
1416 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1417 vPC[4].u.structure->ref();
1418 vPC[5].u.structure->ref();
1419 vPC[6].u.structureChain->ref();
1420 return;
1421 }
1422 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1423 vPC[4].u.structure->ref();
1424 return;
1425 }
1426
1427 // These instructions don't ref their Structures.
1428 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));
1429 }
1430
markAggregate(MarkStack & markStack)1431 void CodeBlock::markAggregate(MarkStack& markStack)
1432 {
1433 for (size_t i = 0; i < m_constantRegisters.size(); ++i) {
1434 if (!m_constantRegisters[i].marked())
1435 markStack.append(m_constantRegisters[i].jsValue());
1436 }
1437
1438 for (size_t i = 0; i < m_functionExpressions.size(); ++i)
1439 m_functionExpressions[i]->body()->markAggregate(markStack);
1440
1441 if (m_rareData) {
1442 for (size_t i = 0; i < m_rareData->m_functions.size(); ++i)
1443 m_rareData->m_functions[i]->body()->markAggregate(markStack);
1444
1445 m_rareData->m_evalCodeCache.markAggregate(markStack);
1446 }
1447 }
1448
reparseForExceptionInfoIfNecessary(CallFrame * callFrame)1449 void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
1450 {
1451 ASSERT(m_codeType != NativeCode);
1452 if (m_exceptionInfo)
1453 return;
1454
1455 ScopeChainNode* scopeChain = callFrame->scopeChain();
1456 if (m_needsFullScopeChain) {
1457 ScopeChain sc(scopeChain);
1458 int scopeDelta = sc.localDepth();
1459 if (m_codeType == EvalCode)
1460 scopeDelta -= static_cast<EvalCodeBlock*>(this)->baseScopeDepth();
1461 else if (m_codeType == FunctionCode)
1462 scopeDelta++; // Compilation of function code assumes activation is not on the scope chain yet.
1463 ASSERT(scopeDelta >= 0);
1464 while (scopeDelta--)
1465 scopeChain = scopeChain->next;
1466 }
1467
1468 switch (m_codeType) {
1469 case FunctionCode: {
1470 FunctionBodyNode* ownerFunctionBodyNode = static_cast<FunctionBodyNode*>(m_ownerNode);
1471 RefPtr<FunctionBodyNode> newFunctionBody = m_globalData->parser->reparse<FunctionBodyNode>(m_globalData, ownerFunctionBodyNode);
1472 ASSERT(newFunctionBody);
1473 newFunctionBody->finishParsing(ownerFunctionBodyNode->copyParameters(), ownerFunctionBodyNode->parameterCount());
1474
1475 m_globalData->scopeNodeBeingReparsed = newFunctionBody.get();
1476
1477 CodeBlock& newCodeBlock = newFunctionBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1478 ASSERT(newCodeBlock.m_exceptionInfo);
1479 ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1480
1481 #if ENABLE(JIT)
1482 JIT::compile(m_globalData, &newCodeBlock);
1483 ASSERT(newFunctionBody->generatedJITCode().size() == ownerNode()->generatedJITCode().size());
1484 #endif
1485
1486 m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1487
1488 m_globalData->scopeNodeBeingReparsed = 0;
1489
1490 break;
1491 }
1492 case EvalCode: {
1493 EvalNode* ownerEvalNode = static_cast<EvalNode*>(m_ownerNode);
1494 RefPtr<EvalNode> newEvalBody = m_globalData->parser->reparse<EvalNode>(m_globalData, ownerEvalNode);
1495
1496 m_globalData->scopeNodeBeingReparsed = newEvalBody.get();
1497
1498 EvalCodeBlock& newCodeBlock = newEvalBody->bytecodeForExceptionInfoReparse(scopeChain, this);
1499 ASSERT(newCodeBlock.m_exceptionInfo);
1500 ASSERT(newCodeBlock.m_instructionCount == m_instructionCount);
1501
1502 #if ENABLE(JIT)
1503 JIT::compile(m_globalData, &newCodeBlock);
1504 ASSERT(newEvalBody->generatedJITCode().size() == ownerNode()->generatedJITCode().size());
1505 #endif
1506
1507 m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release());
1508
1509 m_globalData->scopeNodeBeingReparsed = 0;
1510
1511 break;
1512 }
1513 default:
1514 // CodeBlocks for Global code blocks are transient and therefore to not gain from
1515 // from throwing out there exception information.
1516 ASSERT_NOT_REACHED();
1517 }
1518 }
1519
handlerForBytecodeOffset(unsigned bytecodeOffset)1520 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1521 {
1522 ASSERT(m_codeType != NativeCode);
1523 ASSERT(bytecodeOffset < m_instructionCount);
1524
1525 if (!m_rareData)
1526 return 0;
1527
1528 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1529 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1530 // Handlers are ordered innermost first, so the first handler we encounter
1531 // that contains the source address is the correct handler to use.
1532 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1533 return &exceptionHandlers[i];
1534 }
1535
1536 return 0;
1537 }
1538
lineNumberForBytecodeOffset(CallFrame * callFrame,unsigned bytecodeOffset)1539 int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset)
1540 {
1541 ASSERT(m_codeType != NativeCode);
1542 ASSERT(bytecodeOffset < m_instructionCount);
1543
1544 reparseForExceptionInfoIfNecessary(callFrame);
1545 ASSERT(m_exceptionInfo);
1546
1547 if (!m_exceptionInfo->m_lineInfo.size())
1548 return m_ownerNode->source().firstLine(); // Empty function
1549
1550 int low = 0;
1551 int high = m_exceptionInfo->m_lineInfo.size();
1552 while (low < high) {
1553 int mid = low + (high - low) / 2;
1554 if (m_exceptionInfo->m_lineInfo[mid].instructionOffset <= bytecodeOffset)
1555 low = mid + 1;
1556 else
1557 high = mid;
1558 }
1559
1560 if (!low)
1561 return m_ownerNode->source().firstLine();
1562 return m_exceptionInfo->m_lineInfo[low - 1].lineNumber;
1563 }
1564
expressionRangeForBytecodeOffset(CallFrame * callFrame,unsigned bytecodeOffset,int & divot,int & startOffset,int & endOffset)1565 int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1566 {
1567 ASSERT(m_codeType != NativeCode);
1568 ASSERT(bytecodeOffset < m_instructionCount);
1569
1570 reparseForExceptionInfoIfNecessary(callFrame);
1571 ASSERT(m_exceptionInfo);
1572
1573 if (!m_exceptionInfo->m_expressionInfo.size()) {
1574 // We didn't think anything could throw. Apparently we were wrong.
1575 startOffset = 0;
1576 endOffset = 0;
1577 divot = 0;
1578 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1579 }
1580
1581 int low = 0;
1582 int high = m_exceptionInfo->m_expressionInfo.size();
1583 while (low < high) {
1584 int mid = low + (high - low) / 2;
1585 if (m_exceptionInfo->m_expressionInfo[mid].instructionOffset <= bytecodeOffset)
1586 low = mid + 1;
1587 else
1588 high = mid;
1589 }
1590
1591 ASSERT(low);
1592 if (!low) {
1593 startOffset = 0;
1594 endOffset = 0;
1595 divot = 0;
1596 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1597 }
1598
1599 startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset;
1600 endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset;
1601 divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
1602 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1603 }
1604
getByIdExceptionInfoForBytecodeOffset(CallFrame * callFrame,unsigned bytecodeOffset,OpcodeID & opcodeID)1605 bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID)
1606 {
1607 ASSERT(m_codeType != NativeCode);
1608 ASSERT(bytecodeOffset < m_instructionCount);
1609
1610 reparseForExceptionInfoIfNecessary(callFrame);
1611 ASSERT(m_exceptionInfo);
1612
1613 if (!m_exceptionInfo->m_getByIdExceptionInfo.size())
1614 return false;
1615
1616 int low = 0;
1617 int high = m_exceptionInfo->m_getByIdExceptionInfo.size();
1618 while (low < high) {
1619 int mid = low + (high - low) / 2;
1620 if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset)
1621 low = mid + 1;
1622 else
1623 high = mid;
1624 }
1625
1626 if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset)
1627 return false;
1628
1629 opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpConstruct ? op_construct : op_instanceof;
1630 return true;
1631 }
1632
1633 #if ENABLE(JIT)
functionRegisterForBytecodeOffset(unsigned bytecodeOffset,int & functionRegisterIndex)1634 bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex)
1635 {
1636 ASSERT(m_codeType != NativeCode);
1637 ASSERT(bytecodeOffset < m_instructionCount);
1638
1639 if (!m_rareData || !m_rareData->m_functionRegisterInfos.size())
1640 return false;
1641
1642 int low = 0;
1643 int high = m_rareData->m_functionRegisterInfos.size();
1644 while (low < high) {
1645 int mid = low + (high - low) / 2;
1646 if (m_rareData->m_functionRegisterInfos[mid].bytecodeOffset <= bytecodeOffset)
1647 low = mid + 1;
1648 else
1649 high = mid;
1650 }
1651
1652 if (!low || m_rareData->m_functionRegisterInfos[low - 1].bytecodeOffset != bytecodeOffset)
1653 return false;
1654
1655 functionRegisterIndex = m_rareData->m_functionRegisterInfos[low - 1].functionRegisterIndex;
1656 return true;
1657 }
1658 #endif
1659
1660 #if !ENABLE(JIT)
hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)1661 bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1662 {
1663 ASSERT(m_codeType != NativeCode);
1664 if (m_globalResolveInstructions.isEmpty())
1665 return false;
1666
1667 int low = 0;
1668 int high = m_globalResolveInstructions.size();
1669 while (low < high) {
1670 int mid = low + (high - low) / 2;
1671 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1672 low = mid + 1;
1673 else
1674 high = mid;
1675 }
1676
1677 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1678 return false;
1679 return true;
1680 }
1681 #else
hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)1682 bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1683 {
1684 ASSERT(m_codeType != NativeCode);
1685 if (m_globalResolveInfos.isEmpty())
1686 return false;
1687
1688 int low = 0;
1689 int high = m_globalResolveInfos.size();
1690 while (low < high) {
1691 int mid = low + (high - low) / 2;
1692 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1693 low = mid + 1;
1694 else
1695 high = mid;
1696 }
1697
1698 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1699 return false;
1700 return true;
1701 }
1702 #endif
1703
1704 #if ENABLE(JIT)
setJITCode(JITCode jitCode)1705 void CodeBlock::setJITCode(JITCode jitCode)
1706 {
1707 ASSERT(m_codeType != NativeCode);
1708 ownerNode()->setJITCode(jitCode);
1709 #if !ENABLE(OPCODE_SAMPLING)
1710 if (!BytecodeGenerator::dumpsGeneratedCode())
1711 m_instructions.clear();
1712 #endif
1713 }
1714 #endif
1715
shrinkToFit()1716 void CodeBlock::shrinkToFit()
1717 {
1718 m_instructions.shrinkToFit();
1719
1720 #if !ENABLE(JIT)
1721 m_propertyAccessInstructions.shrinkToFit();
1722 m_globalResolveInstructions.shrinkToFit();
1723 #else
1724 m_structureStubInfos.shrinkToFit();
1725 m_globalResolveInfos.shrinkToFit();
1726 m_callLinkInfos.shrinkToFit();
1727 m_linkedCallerList.shrinkToFit();
1728 #endif
1729
1730 m_identifiers.shrinkToFit();
1731 m_functionExpressions.shrinkToFit();
1732 m_constantRegisters.shrinkToFit();
1733
1734 if (m_exceptionInfo) {
1735 m_exceptionInfo->m_expressionInfo.shrinkToFit();
1736 m_exceptionInfo->m_lineInfo.shrinkToFit();
1737 m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit();
1738 }
1739
1740 if (m_rareData) {
1741 m_rareData->m_exceptionHandlers.shrinkToFit();
1742 m_rareData->m_functions.shrinkToFit();
1743 m_rareData->m_regexps.shrinkToFit();
1744 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1745 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1746 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1747 #if ENABLE(JIT)
1748 m_rareData->m_functionRegisterInfos.shrinkToFit();
1749 #endif
1750 }
1751 }
1752
1753 } // namespace JSC
1754