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

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

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Add new opcodes for handling cached lookup of static value getters.
More or less the same as with JS getters, all that changes is that
instead of calling through a JSFunction we always know that we have
a C function to call.

For the patching routines in the JIT we now need to pass a few
new parameters to allow us to pass enough information to the stub
function to allow us to call the C function correctly. Logically
this shouldn't actually be necessary as all of these functions ignore
the identifier, but removing the ident parameter would require
somewhat involved changes to the way we implement getOwnPropertySlot,
etc.

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::dump): (JSC::CodeBlock::derefStructures): (JSC::CodeBlock::refStructures):
  • bytecode/Instruction.h: (JSC::Instruction::Instruction): (JSC::Instruction::):
  • bytecode/Opcode.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::tryCacheGetByID): (JSC::Interpreter::privateExecute):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass):
  • jit/JIT.h: (JSC::JIT::compileGetByIdProto): (JSC::JIT::compileGetByIdSelfList): (JSC::JIT::compileGetByIdProtoList): (JSC::JIT::compileGetByIdChainList): (JSC::JIT::compileGetByIdChain):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • jit/JITPropertyAccess32_64.cpp: (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • jit/JITStubs.cpp: (JSC::JITThunks::tryCacheGetByID): (JSC::DEFINE_STUB_FUNCTION):
  • jit/JITStubs.h: (JSC::):
  • runtime/JSFunction.cpp: (JSC::JSFunction::getOwnPropertySlot):
  • runtime/Lookup.h: (JSC::getStaticPropertySlot): (JSC::getStaticValueSlot):
  • runtime/PropertySlot.h: (JSC::PropertySlot::): (JSC::PropertySlot::PropertySlot): (JSC::PropertySlot::cachedPropertyType): (JSC::PropertySlot::isCacheable): (JSC::PropertySlot::isCacheableValue): (JSC::PropertySlot::setValueSlot): (JSC::PropertySlot::setCacheableCustom): (JSC::PropertySlot::setGetterSlot): (JSC::PropertySlot::setCacheableGetterSlot): (JSC::PropertySlot::clearOffset): (JSC::PropertySlot::customGetter):

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Add tests to ensure nothing horrifying happens to static property
getters if they're in a path where we end up caching lookups.

  • fast/js/pic/cached-named-property-getter-expected.txt: Added.
  • fast/js/pic/cached-named-property-getter.html: Added.

2010-03-03 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Allow static property getters to interact with JSCs caching
https://bugs.webkit.org/show_bug.cgi?id=35716

Update the obviously safe getters to allow caching

Test: fast/js/pic/cached-named-property-getter.html

  • bridge/runtime_array.cpp: (JSC::RuntimeArray::getOwnPropertySlot):
  • bridge/runtime_method.cpp: (JSC::RuntimeMethod::getOwnPropertySlot):
File size: 65.5 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 unsigned pos = 0;
53 while ((pos = result.find('\"', pos)) != UString::NotFound) {
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_getter_self: {
769 printGetByIdOp(exec, location, it, "get_by_id_getter_self");
770 break;
771 }
772 case op_get_by_id_getter_self_list: {
773 printGetByIdOp(exec, location, it, "get_by_id_getter_self_list");
774 break;
775 }
776 case op_get_by_id_getter_proto: {
777 printGetByIdOp(exec, location, it, "get_by_id_getter_proto");
778 break;
779 }
780 case op_get_by_id_getter_proto_list: {
781 printGetByIdOp(exec, location, it, "get_by_id_getter_proto_list");
782 break;
783 }
784 case op_get_by_id_getter_chain: {
785 printGetByIdOp(exec, location, it, "get_by_id_getter_chain");
786 break;
787 }
788 case op_get_by_id_custom_self: {
789 printGetByIdOp(exec, location, it, "get_by_id_custom_self");
790 break;
791 }
792 case op_get_by_id_custom_self_list: {
793 printGetByIdOp(exec, location, it, "get_by_id_custom_self_list");
794 break;
795 }
796 case op_get_by_id_custom_proto: {
797 printGetByIdOp(exec, location, it, "get_by_id_custom_proto");
798 break;
799 }
800 case op_get_by_id_custom_proto_list: {
801 printGetByIdOp(exec, location, it, "get_by_id_custom_proto_list");
802 break;
803 }
804 case op_get_by_id_custom_chain: {
805 printGetByIdOp(exec, location, it, "get_by_id_custom_chain");
806 break;
807 }
808 case op_get_by_id_generic: {
809 printGetByIdOp(exec, location, it, "get_by_id_generic");
810 break;
811 }
812 case op_get_array_length: {
813 printGetByIdOp(exec, location, it, "get_array_length");
814 break;
815 }
816 case op_get_string_length: {
817 printGetByIdOp(exec, location, it, "get_string_length");
818 break;
819 }
820 case op_put_by_id: {
821 printPutByIdOp(exec, location, it, "put_by_id");
822 break;
823 }
824 case op_put_by_id_replace: {
825 printPutByIdOp(exec, location, it, "put_by_id_replace");
826 break;
827 }
828 case op_put_by_id_transition: {
829 printPutByIdOp(exec, location, it, "put_by_id_transition");
830 break;
831 }
832 case op_put_by_id_generic: {
833 printPutByIdOp(exec, location, it, "put_by_id_generic");
834 break;
835 }
836 case op_put_getter: {
837 int r0 = (++it)->u.operand;
838 int id0 = (++it)->u.operand;
839 int r1 = (++it)->u.operand;
840 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());
841 break;
842 }
843 case op_put_setter: {
844 int r0 = (++it)->u.operand;
845 int id0 = (++it)->u.operand;
846 int r1 = (++it)->u.operand;
847 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());
848 break;
849 }
850 case op_method_check: {
851 printf("[%4d] method_check\n", location);
852 break;
853 }
854 case op_del_by_id: {
855 int r0 = (++it)->u.operand;
856 int r1 = (++it)->u.operand;
857 int id0 = (++it)->u.operand;
858 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());
859 break;
860 }
861 case op_get_by_val: {
862 int r0 = (++it)->u.operand;
863 int r1 = (++it)->u.operand;
864 int r2 = (++it)->u.operand;
865 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());
866 break;
867 }
868 case op_get_by_pname: {
869 int r0 = (++it)->u.operand;
870 int r1 = (++it)->u.operand;
871 int r2 = (++it)->u.operand;
872 int r3 = (++it)->u.operand;
873 int r4 = (++it)->u.operand;
874 int r5 = (++it)->u.operand;
875 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());
876 break;
877 }
878 case op_put_by_val: {
879 int r0 = (++it)->u.operand;
880 int r1 = (++it)->u.operand;
881 int r2 = (++it)->u.operand;
882 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());
883 break;
884 }
885 case op_del_by_val: {
886 int r0 = (++it)->u.operand;
887 int r1 = (++it)->u.operand;
888 int r2 = (++it)->u.operand;
889 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());
890 break;
891 }
892 case op_put_by_index: {
893 int r0 = (++it)->u.operand;
894 unsigned n0 = (++it)->u.operand;
895 int r1 = (++it)->u.operand;
896 printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).c_str(), n0, registerName(exec, r1).c_str());
897 break;
898 }
899 case op_jmp: {
900 int offset = (++it)->u.operand;
901 printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset);
902 break;
903 }
904 case op_loop: {
905 int offset = (++it)->u.operand;
906 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset);
907 break;
908 }
909 case op_jtrue: {
910 printConditionalJump(exec, begin, it, location, "jtrue");
911 break;
912 }
913 case op_loop_if_true: {
914 printConditionalJump(exec, begin, it, location, "loop_if_true");
915 break;
916 }
917 case op_loop_if_false: {
918 printConditionalJump(exec, begin, it, location, "loop_if_false");
919 break;
920 }
921 case op_jfalse: {
922 printConditionalJump(exec, begin, it, location, "jfalse");
923 break;
924 }
925 case op_jeq_null: {
926 printConditionalJump(exec, begin, it, location, "jeq_null");
927 break;
928 }
929 case op_jneq_null: {
930 printConditionalJump(exec, begin, it, location, "jneq_null");
931 break;
932 }
933 case op_jneq_ptr: {
934 int r0 = (++it)->u.operand;
935 int r1 = (++it)->u.operand;
936 int offset = (++it)->u.operand;
937 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);
938 break;
939 }
940 case op_jnless: {
941 int r0 = (++it)->u.operand;
942 int r1 = (++it)->u.operand;
943 int offset = (++it)->u.operand;
944 printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset);
945 break;
946 }
947 case op_jnlesseq: {
948 int r0 = (++it)->u.operand;
949 int r1 = (++it)->u.operand;
950 int offset = (++it)->u.operand;
951 printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset);
952 break;
953 }
954 case op_loop_if_less: {
955 int r0 = (++it)->u.operand;
956 int r1 = (++it)->u.operand;
957 int offset = (++it)->u.operand;
958 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);
959 break;
960 }
961 case op_jless: {
962 int r0 = (++it)->u.operand;
963 int r1 = (++it)->u.operand;
964 int offset = (++it)->u.operand;
965 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset);
966 break;
967 }
968 case op_loop_if_lesseq: {
969 int r0 = (++it)->u.operand;
970 int r1 = (++it)->u.operand;
971 int offset = (++it)->u.operand;
972 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);
973 break;
974 }
975 case op_switch_imm: {
976 int tableIndex = (++it)->u.operand;
977 int defaultTarget = (++it)->u.operand;
978 int scrutineeRegister = (++it)->u.operand;
979 printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str());
980 break;
981 }
982 case op_switch_char: {
983 int tableIndex = (++it)->u.operand;
984 int defaultTarget = (++it)->u.operand;
985 int scrutineeRegister = (++it)->u.operand;
986 printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str());
987 break;
988 }
989 case op_switch_string: {
990 int tableIndex = (++it)->u.operand;
991 int defaultTarget = (++it)->u.operand;
992 int scrutineeRegister = (++it)->u.operand;
993 printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str());
994 break;
995 }
996 case op_new_func: {
997 int r0 = (++it)->u.operand;
998 int f0 = (++it)->u.operand;
999 printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(exec, r0).c_str(), f0);
1000 break;
1001 }
1002 case op_new_func_exp: {
1003 int r0 = (++it)->u.operand;
1004 int f0 = (++it)->u.operand;
1005 printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).c_str(), f0);
1006 break;
1007 }
1008 case op_call: {
1009 int dst = (++it)->u.operand;
1010 int func = (++it)->u.operand;
1011 int argCount = (++it)->u.operand;
1012 int registerOffset = (++it)->u.operand;
1013 printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), argCount, registerOffset);
1014 break;
1015 }
1016 case op_call_eval: {
1017 int dst = (++it)->u.operand;
1018 int func = (++it)->u.operand;
1019 int argCount = (++it)->u.operand;
1020 int registerOffset = (++it)->u.operand;
1021 printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), argCount, registerOffset);
1022 break;
1023 }
1024 case op_call_varargs: {
1025 int dst = (++it)->u.operand;
1026 int func = (++it)->u.operand;
1027 int argCount = (++it)->u.operand;
1028 int registerOffset = (++it)->u.operand;
1029 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);
1030 break;
1031 }
1032 case op_load_varargs: {
1033 printUnaryOp(exec, location, it, "load_varargs");
1034 break;
1035 }
1036 case op_tear_off_activation: {
1037 int r0 = (++it)->u.operand;
1038 printf("[%4d] tear_off_activation\t %s\n", location, registerName(exec, r0).c_str());
1039 break;
1040 }
1041 case op_tear_off_arguments: {
1042 printf("[%4d] tear_off_arguments\n", location);
1043 break;
1044 }
1045 case op_ret: {
1046 int r0 = (++it)->u.operand;
1047 printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).c_str());
1048 break;
1049 }
1050 case op_construct: {
1051 int dst = (++it)->u.operand;
1052 int func = (++it)->u.operand;
1053 int argCount = (++it)->u.operand;
1054 int registerOffset = (++it)->u.operand;
1055 int proto = (++it)->u.operand;
1056 int thisRegister = (++it)->u.operand;
1057 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());
1058 break;
1059 }
1060 case op_construct_verify: {
1061 int r0 = (++it)->u.operand;
1062 int r1 = (++it)->u.operand;
1063 printf("[%4d] construct_verify\t %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str());
1064 break;
1065 }
1066 case op_strcat: {
1067 int r0 = (++it)->u.operand;
1068 int r1 = (++it)->u.operand;
1069 int count = (++it)->u.operand;
1070 printf("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), count);
1071 break;
1072 }
1073 case op_to_primitive: {
1074 int r0 = (++it)->u.operand;
1075 int r1 = (++it)->u.operand;
1076 printf("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str());
1077 break;
1078 }
1079 case op_get_pnames: {
1080 int r0 = it[1].u.operand;
1081 int r1 = it[2].u.operand;
1082 int r2 = it[3].u.operand;
1083 int r3 = it[4].u.operand;
1084 int offset = it[5].u.operand;
1085 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);
1086 it += OPCODE_LENGTH(op_get_pnames) - 1;
1087 break;
1088 }
1089 case op_next_pname: {
1090 int dest = it[1].u.operand;
1091 int iter = it[4].u.operand;
1092 int offset = it[5].u.operand;
1093 printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(exec, dest).c_str(), registerName(exec, iter).c_str(), offset, location + offset);
1094 it += OPCODE_LENGTH(op_next_pname) - 1;
1095 break;
1096 }
1097 case op_push_scope: {
1098 int r0 = (++it)->u.operand;
1099 printf("[%4d] push_scope\t %s\n", location, registerName(exec, r0).c_str());
1100 break;
1101 }
1102 case op_pop_scope: {
1103 printf("[%4d] pop_scope\n", location);
1104 break;
1105 }
1106 case op_push_new_scope: {
1107 int r0 = (++it)->u.operand;
1108 int id0 = (++it)->u.operand;
1109 int r1 = (++it)->u.operand;
1110 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());
1111 break;
1112 }
1113 case op_jmp_scopes: {
1114 int scopeDelta = (++it)->u.operand;
1115 int offset = (++it)->u.operand;
1116 printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset);
1117 break;
1118 }
1119 case op_catch: {
1120 int r0 = (++it)->u.operand;
1121 printf("[%4d] catch\t\t %s\n", location, registerName(exec, r0).c_str());
1122 break;
1123 }
1124 case op_throw: {
1125 int r0 = (++it)->u.operand;
1126 printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).c_str());
1127 break;
1128 }
1129 case op_new_error: {
1130 int r0 = (++it)->u.operand;
1131 int errorType = (++it)->u.operand;
1132 int k0 = (++it)->u.operand;
1133 printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(exec, r0).c_str(), errorType, constantName(exec, k0, getConstant(k0)).c_str());
1134 break;
1135 }
1136 case op_jsr: {
1137 int retAddrDst = (++it)->u.operand;
1138 int offset = (++it)->u.operand;
1139 printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).c_str(), offset, location + offset);
1140 break;
1141 }
1142 case op_sret: {
1143 int retAddrSrc = (++it)->u.operand;
1144 printf("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).c_str());
1145 break;
1146 }
1147 case op_debug: {
1148 int debugHookID = (++it)->u.operand;
1149 int firstLine = (++it)->u.operand;
1150 int lastLine = (++it)->u.operand;
1151 printf("[%4d] debug\t\t %s, %d, %d\n", location, debugHookName(debugHookID), firstLine, lastLine);
1152 break;
1153 }
1154 case op_profile_will_call: {
1155 int function = (++it)->u.operand;
1156 printf("[%4d] profile_will_call %s\n", location, registerName(exec, function).c_str());
1157 break;
1158 }
1159 case op_profile_did_call: {
1160 int function = (++it)->u.operand;
1161 printf("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).c_str());
1162 break;
1163 }
1164 case op_end: {
1165 int r0 = (++it)->u.operand;
1166 printf("[%4d] end\t\t %s\n", location, registerName(exec, r0).c_str());
1167 break;
1168 }
1169 }
1170}
1171
1172#endif // !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
1173
1174#if DUMP_CODE_BLOCK_STATISTICS
1175static HashSet<CodeBlock*> liveCodeBlockSet;
1176#endif
1177
1178#define FOR_EACH_MEMBER_VECTOR(macro) \
1179 macro(instructions) \
1180 macro(globalResolveInfos) \
1181 macro(structureStubInfos) \
1182 macro(callLinkInfos) \
1183 macro(linkedCallerList) \
1184 macro(identifiers) \
1185 macro(functionExpressions) \
1186 macro(constantRegisters)
1187
1188#define FOR_EACH_MEMBER_VECTOR_RARE_DATA(macro) \
1189 macro(regexps) \
1190 macro(functions) \
1191 macro(exceptionHandlers) \
1192 macro(immediateSwitchJumpTables) \
1193 macro(characterSwitchJumpTables) \
1194 macro(stringSwitchJumpTables) \
1195 macro(functionRegisterInfos)
1196
1197#define FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(macro) \
1198 macro(expressionInfo) \
1199 macro(lineInfo) \
1200 macro(getByIdExceptionInfo) \
1201 macro(pcVector)
1202
1203template<typename T>
1204static size_t sizeInBytes(const Vector<T>& vector)
1205{
1206 return vector.capacity() * sizeof(T);
1207}
1208
1209void CodeBlock::dumpStatistics()
1210{
1211#if DUMP_CODE_BLOCK_STATISTICS
1212 #define DEFINE_VARS(name) size_t name##IsNotEmpty = 0; size_t name##TotalSize = 0;
1213 FOR_EACH_MEMBER_VECTOR(DEFINE_VARS)
1214 FOR_EACH_MEMBER_VECTOR_RARE_DATA(DEFINE_VARS)
1215 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(DEFINE_VARS)
1216 #undef DEFINE_VARS
1217
1218 // Non-vector data members
1219 size_t evalCodeCacheIsNotEmpty = 0;
1220
1221 size_t symbolTableIsNotEmpty = 0;
1222 size_t symbolTableTotalSize = 0;
1223
1224 size_t hasExceptionInfo = 0;
1225 size_t hasRareData = 0;
1226
1227 size_t isFunctionCode = 0;
1228 size_t isGlobalCode = 0;
1229 size_t isEvalCode = 0;
1230
1231 HashSet<CodeBlock*>::const_iterator end = liveCodeBlockSet.end();
1232 for (HashSet<CodeBlock*>::const_iterator it = liveCodeBlockSet.begin(); it != end; ++it) {
1233 CodeBlock* codeBlock = *it;
1234
1235 #define GET_STATS(name) if (!codeBlock->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_##name); }
1236 FOR_EACH_MEMBER_VECTOR(GET_STATS)
1237 #undef GET_STATS
1238
1239 if (!codeBlock->m_symbolTable.isEmpty()) {
1240 symbolTableIsNotEmpty++;
1241 symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType)));
1242 }
1243
1244 if (codeBlock->m_exceptionInfo) {
1245 hasExceptionInfo++;
1246 #define GET_STATS(name) if (!codeBlock->m_exceptionInfo->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_exceptionInfo->m_##name); }
1247 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_STATS)
1248 #undef GET_STATS
1249 }
1250
1251 if (codeBlock->m_rareData) {
1252 hasRareData++;
1253 #define GET_STATS(name) if (!codeBlock->m_rareData->m_##name.isEmpty()) { name##IsNotEmpty++; name##TotalSize += sizeInBytes(codeBlock->m_rareData->m_##name); }
1254 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_STATS)
1255 #undef GET_STATS
1256
1257 if (!codeBlock->m_rareData->m_evalCodeCache.isEmpty())
1258 evalCodeCacheIsNotEmpty++;
1259 }
1260
1261 switch (codeBlock->codeType()) {
1262 case FunctionCode:
1263 ++isFunctionCode;
1264 break;
1265 case GlobalCode:
1266 ++isGlobalCode;
1267 break;
1268 case EvalCode:
1269 ++isEvalCode;
1270 break;
1271 }
1272 }
1273
1274 size_t totalSize = 0;
1275
1276 #define GET_TOTAL_SIZE(name) totalSize += name##TotalSize;
1277 FOR_EACH_MEMBER_VECTOR(GET_TOTAL_SIZE)
1278 FOR_EACH_MEMBER_VECTOR_RARE_DATA(GET_TOTAL_SIZE)
1279 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(GET_TOTAL_SIZE)
1280 #undef GET_TOTAL_SIZE
1281
1282 totalSize += symbolTableTotalSize;
1283 totalSize += (liveCodeBlockSet.size() * sizeof(CodeBlock));
1284
1285 printf("Number of live CodeBlocks: %d\n", liveCodeBlockSet.size());
1286 printf("Size of a single CodeBlock [sizeof(CodeBlock)]: %zu\n", sizeof(CodeBlock));
1287 printf("Size of all CodeBlocks: %zu\n", totalSize);
1288 printf("Average size of a CodeBlock: %zu\n", totalSize / liveCodeBlockSet.size());
1289
1290 printf("Number of FunctionCode CodeBlocks: %zu (%.3f%%)\n", isFunctionCode, static_cast<double>(isFunctionCode) * 100.0 / liveCodeBlockSet.size());
1291 printf("Number of GlobalCode CodeBlocks: %zu (%.3f%%)\n", isGlobalCode, static_cast<double>(isGlobalCode) * 100.0 / liveCodeBlockSet.size());
1292 printf("Number of EvalCode CodeBlocks: %zu (%.3f%%)\n", isEvalCode, static_cast<double>(isEvalCode) * 100.0 / liveCodeBlockSet.size());
1293
1294 printf("Number of CodeBlocks with exception info: %zu (%.3f%%)\n", hasExceptionInfo, static_cast<double>(hasExceptionInfo) * 100.0 / liveCodeBlockSet.size());
1295 printf("Number of CodeBlocks with rare data: %zu (%.3f%%)\n", hasRareData, static_cast<double>(hasRareData) * 100.0 / liveCodeBlockSet.size());
1296
1297 #define PRINT_STATS(name) printf("Number of CodeBlocks with " #name ": %zu\n", name##IsNotEmpty); printf("Size of all " #name ": %zu\n", name##TotalSize);
1298 FOR_EACH_MEMBER_VECTOR(PRINT_STATS)
1299 FOR_EACH_MEMBER_VECTOR_RARE_DATA(PRINT_STATS)
1300 FOR_EACH_MEMBER_VECTOR_EXCEPTION_INFO(PRINT_STATS)
1301 #undef PRINT_STATS
1302
1303 printf("Number of CodeBlocks with evalCodeCache: %zu\n", evalCodeCacheIsNotEmpty);
1304 printf("Number of CodeBlocks with symbolTable: %zu\n", symbolTableIsNotEmpty);
1305
1306 printf("Size of all symbolTables: %zu\n", symbolTableTotalSize);
1307
1308#else
1309 printf("Dumping CodeBlock statistics is not enabled.\n");
1310#endif
1311}
1312
1313CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab)
1314 : m_numCalleeRegisters(0)
1315 , m_numVars(0)
1316 , m_numParameters(0)
1317 , m_ownerExecutable(ownerExecutable)
1318 , m_globalData(0)
1319#ifndef NDEBUG
1320 , m_instructionCount(0)
1321#endif
1322 , m_needsFullScopeChain(ownerExecutable->needsActivation())
1323 , m_usesEval(ownerExecutable->usesEval())
1324 , m_isNumericCompareFunction(false)
1325 , m_codeType(codeType)
1326 , m_source(sourceProvider)
1327 , m_sourceOffset(sourceOffset)
1328 , m_symbolTable(symTab)
1329 , m_exceptionInfo(new ExceptionInfo)
1330{
1331 ASSERT(m_source);
1332
1333#if DUMP_CODE_BLOCK_STATISTICS
1334 liveCodeBlockSet.add(this);
1335#endif
1336}
1337
1338CodeBlock::~CodeBlock()
1339{
1340#if !ENABLE(JIT)
1341 for (size_t size = m_globalResolveInstructions.size(), i = 0; i < size; ++i)
1342 derefStructures(&m_instructions[m_globalResolveInstructions[i]]);
1343
1344 for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i)
1345 derefStructures(&m_instructions[m_propertyAccessInstructions[i]]);
1346#else
1347 for (size_t size = m_globalResolveInfos.size(), i = 0; i < size; ++i) {
1348 if (m_globalResolveInfos[i].structure)
1349 m_globalResolveInfos[i].structure->deref();
1350 }
1351
1352 for (size_t size = m_structureStubInfos.size(), i = 0; i < size; ++i)
1353 m_structureStubInfos[i].deref();
1354
1355 for (size_t size = m_callLinkInfos.size(), i = 0; i < size; ++i) {
1356 CallLinkInfo* callLinkInfo = &m_callLinkInfos[i];
1357 if (callLinkInfo->isLinked())
1358 callLinkInfo->callee->removeCaller(callLinkInfo);
1359 }
1360
1361 for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) {
1362 if (Structure* structure = m_methodCallLinkInfos[i].cachedStructure) {
1363 structure->deref();
1364 // Both members must be filled at the same time
1365 ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure);
1366 m_methodCallLinkInfos[i].cachedPrototypeStructure->deref();
1367 }
1368 }
1369
1370#if ENABLE(JIT_OPTIMIZE_CALL)
1371 unlinkCallers();
1372#endif
1373
1374#endif // !ENABLE(JIT)
1375
1376#if DUMP_CODE_BLOCK_STATISTICS
1377 liveCodeBlockSet.remove(this);
1378#endif
1379}
1380
1381#if ENABLE(JIT_OPTIMIZE_CALL)
1382void CodeBlock::unlinkCallers()
1383{
1384 size_t size = m_linkedCallerList.size();
1385 for (size_t i = 0; i < size; ++i) {
1386 CallLinkInfo* currentCaller = m_linkedCallerList[i];
1387 JIT::unlinkCall(currentCaller);
1388 currentCaller->setUnlinked();
1389 }
1390 m_linkedCallerList.clear();
1391}
1392#endif
1393
1394void CodeBlock::derefStructures(Instruction* vPC) const
1395{
1396 Interpreter* interpreter = m_globalData->interpreter;
1397
1398 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
1399 vPC[4].u.structure->deref();
1400 return;
1401 }
1402 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) {
1403 vPC[4].u.structure->deref();
1404 vPC[5].u.structure->deref();
1405 return;
1406 }
1407 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) {
1408 vPC[4].u.structure->deref();
1409 vPC[5].u.structureChain->deref();
1410 return;
1411 }
1412 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1413 vPC[4].u.structure->deref();
1414 vPC[5].u.structure->deref();
1415 vPC[6].u.structureChain->deref();
1416 return;
1417 }
1418 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1419 vPC[4].u.structure->deref();
1420 return;
1421 }
1422 if (vPC[0].u.opcode == interpreter->getOpcode(op_resolve_global)) {
1423 if(vPC[4].u.structure)
1424 vPC[4].u.structure->deref();
1425 return;
1426 }
1427 if ((vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto_list))
1428 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self_list))
1429 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto_list))
1430 || (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self_list))) {
1431 PolymorphicAccessStructureList* polymorphicStructures = vPC[4].u.polymorphicStructures;
1432 polymorphicStructures->derefStructures(vPC[5].u.operand);
1433 delete polymorphicStructures;
1434 return;
1435 }
1436
1437 // These instructions don't ref their Structures.
1438 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));
1439}
1440
1441void CodeBlock::refStructures(Instruction* vPC) const
1442{
1443 Interpreter* interpreter = m_globalData->interpreter;
1444
1445 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_self) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_custom_self)) {
1446 vPC[4].u.structure->ref();
1447 return;
1448 }
1449 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_proto) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_proto)) {
1450 vPC[4].u.structure->ref();
1451 vPC[5].u.structure->ref();
1452 return;
1453 }
1454 if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_chain) || vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_getter_chain)) {
1455 vPC[4].u.structure->ref();
1456 vPC[5].u.structureChain->ref();
1457 return;
1458 }
1459 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_transition)) {
1460 vPC[4].u.structure->ref();
1461 vPC[5].u.structure->ref();
1462 vPC[6].u.structureChain->ref();
1463 return;
1464 }
1465 if (vPC[0].u.opcode == interpreter->getOpcode(op_put_by_id_replace)) {
1466 vPC[4].u.structure->ref();
1467 return;
1468 }
1469
1470 // These instructions don't ref their Structures.
1471 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));
1472}
1473
1474void CodeBlock::markAggregate(MarkStack& markStack)
1475{
1476 for (size_t i = 0; i < m_constantRegisters.size(); ++i)
1477 markStack.append(m_constantRegisters[i].jsValue());
1478 for (size_t i = 0; i < m_functionExprs.size(); ++i)
1479 m_functionExprs[i]->markAggregate(markStack);
1480 for (size_t i = 0; i < m_functionDecls.size(); ++i)
1481 m_functionDecls[i]->markAggregate(markStack);
1482}
1483
1484void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame)
1485{
1486 if (m_exceptionInfo)
1487 return;
1488
1489 ScopeChainNode* scopeChain = callFrame->scopeChain();
1490 if (m_needsFullScopeChain) {
1491 ScopeChain sc(scopeChain);
1492 int scopeDelta = sc.localDepth();
1493 if (m_codeType == EvalCode)
1494 scopeDelta -= static_cast<EvalCodeBlock*>(this)->baseScopeDepth();
1495 else if (m_codeType == FunctionCode)
1496 scopeDelta++; // Compilation of function code assumes activation is not on the scope chain yet.
1497 ASSERT(scopeDelta >= 0);
1498 while (scopeDelta--)
1499 scopeChain = scopeChain->next;
1500 }
1501
1502 m_exceptionInfo.set(m_ownerExecutable->reparseExceptionInfo(m_globalData, scopeChain, this));
1503}
1504
1505HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
1506{
1507 ASSERT(bytecodeOffset < m_instructionCount);
1508
1509 if (!m_rareData)
1510 return 0;
1511
1512 Vector<HandlerInfo>& exceptionHandlers = m_rareData->m_exceptionHandlers;
1513 for (size_t i = 0; i < exceptionHandlers.size(); ++i) {
1514 // Handlers are ordered innermost first, so the first handler we encounter
1515 // that contains the source address is the correct handler to use.
1516 if (exceptionHandlers[i].start <= bytecodeOffset && exceptionHandlers[i].end >= bytecodeOffset)
1517 return &exceptionHandlers[i];
1518 }
1519
1520 return 0;
1521}
1522
1523int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset)
1524{
1525 ASSERT(bytecodeOffset < m_instructionCount);
1526
1527 reparseForExceptionInfoIfNecessary(callFrame);
1528 ASSERT(m_exceptionInfo);
1529
1530 if (!m_exceptionInfo->m_lineInfo.size())
1531 return m_ownerExecutable->source().firstLine(); // Empty function
1532
1533 int low = 0;
1534 int high = m_exceptionInfo->m_lineInfo.size();
1535 while (low < high) {
1536 int mid = low + (high - low) / 2;
1537 if (m_exceptionInfo->m_lineInfo[mid].instructionOffset <= bytecodeOffset)
1538 low = mid + 1;
1539 else
1540 high = mid;
1541 }
1542
1543 if (!low)
1544 return m_ownerExecutable->source().firstLine();
1545 return m_exceptionInfo->m_lineInfo[low - 1].lineNumber;
1546}
1547
1548int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
1549{
1550 ASSERT(bytecodeOffset < m_instructionCount);
1551
1552 reparseForExceptionInfoIfNecessary(callFrame);
1553 ASSERT(m_exceptionInfo);
1554
1555 if (!m_exceptionInfo->m_expressionInfo.size()) {
1556 // We didn't think anything could throw. Apparently we were wrong.
1557 startOffset = 0;
1558 endOffset = 0;
1559 divot = 0;
1560 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1561 }
1562
1563 int low = 0;
1564 int high = m_exceptionInfo->m_expressionInfo.size();
1565 while (low < high) {
1566 int mid = low + (high - low) / 2;
1567 if (m_exceptionInfo->m_expressionInfo[mid].instructionOffset <= bytecodeOffset)
1568 low = mid + 1;
1569 else
1570 high = mid;
1571 }
1572
1573 ASSERT(low);
1574 if (!low) {
1575 startOffset = 0;
1576 endOffset = 0;
1577 divot = 0;
1578 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1579 }
1580
1581 startOffset = m_exceptionInfo->m_expressionInfo[low - 1].startOffset;
1582 endOffset = m_exceptionInfo->m_expressionInfo[low - 1].endOffset;
1583 divot = m_exceptionInfo->m_expressionInfo[low - 1].divotPoint + m_sourceOffset;
1584 return lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
1585}
1586
1587bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID)
1588{
1589 ASSERT(bytecodeOffset < m_instructionCount);
1590
1591 reparseForExceptionInfoIfNecessary(callFrame);
1592 ASSERT(m_exceptionInfo);
1593
1594 if (!m_exceptionInfo->m_getByIdExceptionInfo.size())
1595 return false;
1596
1597 int low = 0;
1598 int high = m_exceptionInfo->m_getByIdExceptionInfo.size();
1599 while (low < high) {
1600 int mid = low + (high - low) / 2;
1601 if (m_exceptionInfo->m_getByIdExceptionInfo[mid].bytecodeOffset <= bytecodeOffset)
1602 low = mid + 1;
1603 else
1604 high = mid;
1605 }
1606
1607 if (!low || m_exceptionInfo->m_getByIdExceptionInfo[low - 1].bytecodeOffset != bytecodeOffset)
1608 return false;
1609
1610 opcodeID = m_exceptionInfo->m_getByIdExceptionInfo[low - 1].isOpConstruct ? op_construct : op_instanceof;
1611 return true;
1612}
1613
1614#if ENABLE(JIT)
1615bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex)
1616{
1617 ASSERT(bytecodeOffset < m_instructionCount);
1618
1619 if (!m_rareData || !m_rareData->m_functionRegisterInfos.size())
1620 return false;
1621
1622 int low = 0;
1623 int high = m_rareData->m_functionRegisterInfos.size();
1624 while (low < high) {
1625 int mid = low + (high - low) / 2;
1626 if (m_rareData->m_functionRegisterInfos[mid].bytecodeOffset <= bytecodeOffset)
1627 low = mid + 1;
1628 else
1629 high = mid;
1630 }
1631
1632 if (!low || m_rareData->m_functionRegisterInfos[low - 1].bytecodeOffset != bytecodeOffset)
1633 return false;
1634
1635 functionRegisterIndex = m_rareData->m_functionRegisterInfos[low - 1].functionRegisterIndex;
1636 return true;
1637}
1638#endif
1639
1640#if !ENABLE(JIT)
1641bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset)
1642{
1643 if (m_globalResolveInstructions.isEmpty())
1644 return false;
1645
1646 int low = 0;
1647 int high = m_globalResolveInstructions.size();
1648 while (low < high) {
1649 int mid = low + (high - low) / 2;
1650 if (m_globalResolveInstructions[mid] <= bytecodeOffset)
1651 low = mid + 1;
1652 else
1653 high = mid;
1654 }
1655
1656 if (!low || m_globalResolveInstructions[low - 1] != bytecodeOffset)
1657 return false;
1658 return true;
1659}
1660#else
1661bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
1662{
1663 if (m_globalResolveInfos.isEmpty())
1664 return false;
1665
1666 int low = 0;
1667 int high = m_globalResolveInfos.size();
1668 while (low < high) {
1669 int mid = low + (high - low) / 2;
1670 if (m_globalResolveInfos[mid].bytecodeOffset <= bytecodeOffset)
1671 low = mid + 1;
1672 else
1673 high = mid;
1674 }
1675
1676 if (!low || m_globalResolveInfos[low - 1].bytecodeOffset != bytecodeOffset)
1677 return false;
1678 return true;
1679}
1680#endif
1681
1682void CodeBlock::shrinkToFit()
1683{
1684 m_instructions.shrinkToFit();
1685
1686#if !ENABLE(JIT)
1687 m_propertyAccessInstructions.shrinkToFit();
1688 m_globalResolveInstructions.shrinkToFit();
1689#else
1690 m_structureStubInfos.shrinkToFit();
1691 m_globalResolveInfos.shrinkToFit();
1692 m_callLinkInfos.shrinkToFit();
1693 m_linkedCallerList.shrinkToFit();
1694#endif
1695
1696 m_identifiers.shrinkToFit();
1697 m_functionDecls.shrinkToFit();
1698 m_functionExprs.shrinkToFit();
1699 m_constantRegisters.shrinkToFit();
1700
1701 if (m_exceptionInfo) {
1702 m_exceptionInfo->m_expressionInfo.shrinkToFit();
1703 m_exceptionInfo->m_lineInfo.shrinkToFit();
1704 m_exceptionInfo->m_getByIdExceptionInfo.shrinkToFit();
1705 }
1706
1707 if (m_rareData) {
1708 m_rareData->m_exceptionHandlers.shrinkToFit();
1709 m_rareData->m_regexps.shrinkToFit();
1710 m_rareData->m_immediateSwitchJumpTables.shrinkToFit();
1711 m_rareData->m_characterSwitchJumpTables.shrinkToFit();
1712 m_rareData->m_stringSwitchJumpTables.shrinkToFit();
1713#if ENABLE(JIT)
1714 m_rareData->m_functionRegisterInfos.shrinkToFit();
1715#endif
1716 }
1717}
1718
1719} // namespace JSC
Note: See TracBrowser for help on using the repository browser.