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

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

Restructure Executable types so that host functions do not hold a FunctionExecutable.
https://bugs.webkit.org/show_bug.cgi?id=28621

Reviewed by Oliver Hunt.

All JSFunction objects have a pointer to an Executable*. This is currently always a
FunctionExecutable, however this has a couple of drawbacks. Host functions do not
store a range of information that the FunctionExecutable provides (source, name,
CodeBlock & information presently held on the FunctionBodyNode).

[ * nearly all... see below! ]

Instead, make JSFunctions hold a pointer to an ExecutableBase, move fields specific
to JS sourced executable types (source, node) into a new subclass (ScriptExecutable),
and create a new NativeExecutable type. We now provide a new method in JSFunction
to access & downcast to FunctionExecutable, but in doing so we can make an early
check (with an ASSERT) to ensure that the Executable read from a function will only
be treated as a FunctionExecutable (and thus the JS sepcific fields will only be
accessed) if the JSFunction is not a host function.

There is one JSFunction that currently does not have an Executable, which is the
object created to allow us to read out the vtable pointer. By making this change
we can also add a new Executable type fror this object (VPtrHackExecutable).
Since this means that really all JSFunctions have an Executable we no longer have
to null-check m_executable before us it - particularly in isHostFunction().

This patch removes CacheableEvalExecutable, since all subclasses of ExecutableBase
can now be ref-counted - since both JSFunction holds (and ref-counts) an ExecutableBase
that might be a FunctionExecutable or a NativeExecutable. This does now mean that all
ProgramExecutables and EvalExecutables (unnecessarily) provide an interface to be
ref-counted, however this seems less-bad than host functions unnecessarily providing
interface to access non-host specific information.

The class hierarcy has changed from this:

  • ExecutableBase
    • ProgramExecutable
    • EvalExecutable
      • CacheableEvalExecutable (also RefCounted by multiple-inheritance)
    • FunctionExecutable (also RefCounted by multiple-inheritance, 'special' FunctionExecutable also used for host functions)

To this:

  • RefCounted
    • ExecutableBase
      • NativeExecutable
      • VPtrHackExecutable
      • ScriptExecutable
        • ProgramExecutable
        • EvalExecutable
        • FunctionExecutable

This patch speeds up sunspidey by a couple of ms (presumably due to the changes to isHostFunction()).

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::CodeBlock):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::ownerExecutable):
(JSC::GlobalCodeBlock::GlobalCodeBlock):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::get):

  • debugger/Debugger.cpp:

(JSC::Debugger::recompileAllJSFunctions):

  • interpreter/CachedCall.h:

(JSC::CachedCall::CachedCall):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::callEval):
(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • profiler/Profiler.cpp:

(JSC::createCallIdentifierFromFunctionImp):

  • runtime/Arguments.h:

(JSC::Arguments::getArgumentsData):
(JSC::Arguments::Arguments):

  • runtime/Executable.cpp:

(JSC::NativeExecutable::~NativeExecutable):
(JSC::VPtrHackExecutable::~VPtrHackExecutable):

  • runtime/Executable.h:

(JSC::ExecutableBase::ExecutableBase):
(JSC::ExecutableBase::~ExecutableBase):
(JSC::ExecutableBase::isHostFunction):
(JSC::NativeExecutable::NativeExecutable):
(JSC::VPtrHackExecutable::VPtrHackExecutable):
(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ScriptExecutable::source):
(JSC::ScriptExecutable::sourceID):
(JSC::ScriptExecutable::sourceURL):
(JSC::ScriptExecutable::lineNo):
(JSC::ScriptExecutable::lastLine):
(JSC::ScriptExecutable::usesEval):
(JSC::ScriptExecutable::usesArguments):
(JSC::ScriptExecutable::needsActivation):
(JSC::EvalExecutable::EvalExecutable):
(JSC::EvalExecutable::create):
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncToString):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::JSFunction):
(JSC::JSFunction::~JSFunction):
(JSC::JSFunction::markChildren):
(JSC::JSFunction::getCallData):
(JSC::JSFunction::call):
(JSC::JSFunction::lengthGetter):
(JSC::JSFunction::getConstructData):
(JSC::JSFunction::construct):

  • runtime/JSFunction.h:

(JSC::JSFunction::executable):
(JSC::JSFunction::jsExecutable):
(JSC::JSFunction::isHostFunction):

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