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

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

Rubber stamps by Darin Adler & Sam Weinig.

Bug 43867 - Some UString cleanup

Change JSC::UString data(), size(), and from(), to characters(), length(), and number() to match WTF::String.
Move string concatenation methods to a new header to simplify down UString.h. Remove is8Bit().

JavaScriptCore:

  • API/JSClassRef.cpp:

(OpaqueJSClass::~OpaqueJSClass):
(OpaqueJSClass::className):

  • API/OpaqueJSString.cpp:

(OpaqueJSString::create):

(JSC::constantName):
(JSC::idName):
(JSC::CodeBlock::registerName):
(JSC::regexpName):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::get):

  • bytecompiler/NodesCodegen.cpp:

(JSC::ResolveNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::processClauseList):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createRegex):

  • parser/ParserArena.h:

(JSC::IdentifierArena::makeNumericIdentifier):

  • parser/SourceProvider.h:

(JSC::UStringSourceProvider::data):
(JSC::UStringSourceProvider::length):

  • profiler/Profiler.cpp:
  • runtime/Arguments.cpp:

(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::getOwnPropertyNames):
(JSC::Arguments::put):
(JSC::Arguments::deleteProperty):

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncToString):

  • runtime/DatePrototype.cpp:

(JSC::formatLocaleDate):

  • runtime/ExceptionHelpers.cpp:
  • runtime/FunctionConstructor.cpp:
  • runtime/FunctionPrototype.cpp:

(JSC::insertSemicolonIfNeeded):

  • runtime/Identifier.h:

(JSC::Identifier::characters):
(JSC::Identifier::length):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::decode):
(JSC::parseInt):
(JSC::parseFloat):
(JSC::globalFuncEscape):
(JSC::globalFuncUnescape):

  • runtime/JSNumberCell.cpp:

(JSC::JSNumberCell::toString):

  • runtime/JSONObject.cpp:

(JSC::gap):
(JSC::Stringifier::appendQuotedString):
(JSC::Stringifier::appendStringifiedValue):
(JSC::Stringifier::indent):
(JSC::Stringifier::unindent):
(JSC::Walker::walk):

  • runtime/JSString.cpp:

(JSC::JSString::replaceCharacter):
(JSC::JSString::getIndexSlowCase):

  • runtime/JSString.h:

(JSC::RopeBuilder::JSString):
(JSC::RopeBuilder::appendValueInConstructAndIncrementLength):
(JSC::RopeBuilder::fiberCount):
(JSC::jsSingleCharacterSubstring):
(JSC::jsNontrivialString):
(JSC::JSString::getIndex):
(JSC::jsString):
(JSC::jsStringWithFinalizer):
(JSC::jsSubstring):
(JSC::jsOwnedString):

  • runtime/JSStringBuilder.h:

(JSC::JSStringBuilder::append):

  • runtime/LiteralParser.h:

(JSC::LiteralParser::Lexer::Lexer):

  • runtime/NumberPrototype.cpp:

(JSC::numberProtoFuncToString):
(JSC::numberProtoFuncToFixed):
(JSC::numberProtoFuncToExponential):
(JSC::numberProtoFuncToPrecision):

  • runtime/NumericStrings.h:

(JSC::NumericStrings::add):
(JSC::NumericStrings::lookupSmallString):

  • runtime/Operations.h:

(JSC::jsString):

  • runtime/RegExp.cpp:

(JSC::RegExp::match):

  • runtime/RegExpCache.cpp:

(JSC::RegExpCache::lookupOrCreate):
(JSC::RegExpCache::create):

  • runtime/RegExpConstructor.cpp:

(JSC::RegExpConstructor::getRightContext):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::match):

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncToString):

  • runtime/StringBuilder.h:

(JSC::StringBuilder::append):

  • runtime/StringConcatenate.h: Copied from JavaScriptCore/runtime/UString.h.

(JSC::):
(JSC::sumWithOverflow):
(JSC::tryMakeString):
(JSC::makeString):

  • runtime/StringObject.cpp:

(JSC::StringObject::getOwnPropertyNames):

  • runtime/StringPrototype.cpp:

(JSC::substituteBackreferencesSlow):
(JSC::localeCompare):
(JSC::jsSpliceSubstringsWithSeparators):
(JSC::stringProtoFuncReplace):
(JSC::stringProtoFuncCharAt):
(JSC::stringProtoFuncCharCodeAt):
(JSC::stringProtoFuncIndexOf):
(JSC::stringProtoFuncLastIndexOf):
(JSC::stringProtoFuncSlice):
(JSC::stringProtoFuncSplit):
(JSC::stringProtoFuncSubstr):
(JSC::stringProtoFuncSubstring):
(JSC::stringProtoFuncToLowerCase):
(JSC::stringProtoFuncToUpperCase):
(JSC::stringProtoFuncFontsize):
(JSC::stringProtoFuncLink):
(JSC::trimString):

  • runtime/UString.cpp:

(JSC::UString::number):
(JSC::UString::ascii):
(JSC::UString::operator[]):
(JSC::UString::toDouble):
(JSC::UString::find):
(JSC::UString::rfind):
(JSC::UString::substr):
(JSC::operator==):
(JSC::operator<):
(JSC::operator>):
(JSC::UString::UTF8String):

  • runtime/UString.h:

(JSC::UString::UString):
(JSC::UString::adopt):
(JSC::UString::length):
(JSC::UString::characters):
(JSC::UString::isNull):
(JSC::UString::isEmpty):
(JSC::UString::impl):
(JSC::UString::cost):
(JSC::operator==):
(JSC::operator!=):
(JSC::codePointCompare):
(JSC::UString::toArrayIndex):
(JSC::IdentifierRepHash::hash):
(WTF::):

  • yarr/RegexJIT.cpp:

(JSC::Yarr::jitCompileRegex):

  • yarr/RegexParser.h:

(JSC::Yarr::Parser::Parser):

JavaScriptGlue:

  • JSUtils.cpp:

(UStringToCFString):
(KJSValueToCFTypeInternal):

  • JavaScriptGlue.xcodeproj/project.pbxproj:

WebCore:

  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/JSCSSStyleDeclarationCustom.cpp:

(WebCore::hasCSSPropertyNamePrefix):
(WebCore::cssPropertyName):

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::setPort):

  • bindings/js/ScriptDebugServer.cpp:

(WebCore::ScriptDebugServer::dispatchDidParseSource):

  • bindings/js/ScriptString.h:

(WebCore::ScriptString::size):

  • bindings/js/ScriptValue.cpp:

(WebCore::jsToInspectorValue):

  • bindings/objc/WebScriptObject.mm:

(+[WebScriptObject _convertValueToObjcValue:originRootObject:rootObject:]):

  • bridge/jni/jni_jsobject.mm:

(JavaJSObject::convertValueToJObject):

  • bridge/jni/jsc/JNIUtilityPrivate.cpp:

(JSC::Bindings::convertArrayInstanceToJavaArray):
(JSC::Bindings::convertValueToJValue):

  • bridge/objc/objc_runtime.mm:

(JSC::Bindings::callObjCFallbackObject):

WebKit/mac:

  • WebView/WebScriptDebugger.mm:

(toNSString):

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