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