source: webkit/trunk/JavaScriptCore/bytecode/CodeBlock.cpp@ 52028

Last change on this file since 52028 was 52028, checked in by [email protected], 15 years ago

https://bugs.webkit.org/show_bug.cgi?id=32454
Refactor construction of simple strings to avoid string concatenation.

Reviewed by Oliver Hunt.

Building strings through concatenation has a memory and performance cost -
a memory cost since we must over-allocate the buffer to leave space to append
into, and performance in that the string may still require reallocation (and
thus copying during construction). Instead move the full construction to
within a single function call (makeString), so that the arguments' lengths
can be calculated and an appropriate sized buffer allocated before copying
any characters.

~No performance change (~2% progression on date tests).

  • bytecode/CodeBlock.cpp:

(JSC::escapeQuotes):
(JSC::valueToSourceString):
(JSC::constantName):
(JSC::idName):
(JSC::CodeBlock::registerName):
(JSC::regexpToSourceString):
(JSC::regexpName):

  • bytecompiler/NodesCodegen.cpp:

(JSC::substitute):

  • profiler/Profiler.cpp:

(JSC::Profiler::createCallIdentifier):

  • runtime/DateConstructor.cpp:

(JSC::callDate):

  • runtime/DateConversion.cpp:

(JSC::formatDate):
(JSC::formatDateUTCVariant):
(JSC::formatTime):
(JSC::formatTimeUTC):

  • runtime/DateConversion.h:

(JSC::):

  • runtime/DatePrototype.cpp:

(JSC::dateProtoFuncToString):
(JSC::dateProtoFuncToUTCString):
(JSC::dateProtoFuncToDateString):
(JSC::dateProtoFuncToTimeString):
(JSC::dateProtoFuncToGMTString):

  • runtime/ErrorPrototype.cpp:

(JSC::errorProtoFuncToString):

  • runtime/ExceptionHelpers.cpp:

(JSC::createUndefinedVariableError):
(JSC::createErrorMessage):
(JSC::createInvalidParamError):

  • runtime/FunctionPrototype.cpp:

(JSC::insertSemicolonIfNeeded):
(JSC::functionProtoFuncToString):

  • runtime/ObjectPrototype.cpp:

(JSC::objectProtoFuncToString):

  • runtime/RegExpConstructor.cpp:

(JSC::constructRegExp):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::match):

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncCompile):
(JSC::regExpProtoFuncToString):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncBig):
(JSC::stringProtoFuncSmall):
(JSC::stringProtoFuncBlink):
(JSC::stringProtoFuncBold):
(JSC::stringProtoFuncFixed):
(JSC::stringProtoFuncItalics):
(JSC::stringProtoFuncStrike):
(JSC::stringProtoFuncSub):
(JSC::stringProtoFuncSup):
(JSC::stringProtoFuncFontcolor):
(JSC::stringProtoFuncFontsize):
(JSC::stringProtoFuncAnchor):

  • runtime/UString.h:

(JSC::):
(JSC::makeString):

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