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

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

2009-05-21 Gavin Barraclough <[email protected]>

Reviewed by Geoff Garen.

op_method_check

Optimize method calls, by caching specific function values within the Structure.
The new opcode is used almost like an x86 opcode prefix byte to optimize op_get_by_id,
where the property access is being used to read a function to be passed to op-call (i.e.
'foo.bar();'). This patch modifies the Structure class such that when a property is
put to an object for the first time we will check if the value is a function. If it is,
we will cache the function value on the Structure. A Structure in such a state guarantees
that not only does a property with the given identifier exist on the object, but also that
its value is unchanged. Upon any further attempt to put a property with the same identifier
(but a different value) to the object, it will transition back to a normal Structure (where
it will guarantee the presence but not the value of the property).

op_method_check makes use of the new information made available by the Structure, by
augmenting the functionality of op_get_by_id. Upon generating a FunctionCallDotNode a
check will be emitted prior to the property access reading the function value, and the JIT
will generate an extra (initially unlinked but patchable) set of checks prior to the regular
JIT code for get_by_id. The new code will do inline structure and prototype structure check
(unlike a regular get_by_id, which can only handle 'self' accesses inline), and then performs
an immediate load of the function value, rather than using memory accesses to load the value
from the obejct's property storage array. If the method check fails it will revert, or if
the access is polymorphic, the op_get_by_id will continue to operate - and optimize itself -
just as any other regular op_get_by_id would.

~2.5% on v8-tests, due to a ~9% progression on richards.

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