Changeset 129453 in webkit for trunk/Source/JavaScriptCore/interpreter
- Timestamp:
- Sep 24, 2012, 9:30:20 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore/interpreter
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/interpreter/AbstractPC.cpp
r127202 r129453 46 46 } 47 47 #endif 48 49 #if ENABLE(CLASSIC_INTERPRETER)50 UNUSED_PARAM(globalData);51 m_pointer = exec->returnVPC();52 m_mode = Interpreter;53 #endif54 48 } 55 49 -
trunk/Source/JavaScriptCore/interpreter/AbstractPC.h
r108020 r129453 61 61 #endif 62 62 63 #if ENABLE(CLASSIC_INTERPRETER)64 AbstractPC(Instruction* vPC)65 : m_pointer(vPC)66 , m_mode(Interpreter)67 {68 }69 70 bool hasInterpreterReturnAddress() const { return m_mode == Interpreter; }71 Instruction* interpreterReturnAddress() const72 {73 ASSERT(hasInterpreterReturnAddress());74 return static_cast<Instruction*>(m_pointer);75 }76 #endif77 78 63 bool isSet() const { return m_mode != None; } 79 64 bool operator!() const { return !isSet(); } -
trunk/Source/JavaScriptCore/interpreter/CallFrame.h
r128832 r129453 149 149 } 150 150 #endif 151 #if ENABLE(CLASSIC_INTERPRETER)152 Instruction* returnVPC() const { return this[RegisterFile::ReturnPC].vPC(); }153 #endif154 151 #if USE(JSVALUE32_64) 155 152 Instruction* currentVPC() const -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r129432 r129453 73 73 #endif 74 74 75 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND ( (ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)) && !defined(__llvm__))75 #define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(LLINT) && !defined(__llvm__)) 76 76 77 77 using namespace std; … … 88 88 return sc->localDepth(); 89 89 } 90 91 #if ENABLE(CLASSIC_INTERPRETER)92 static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count)93 {94 return jsString(exec, strings, count);95 }96 97 #endif // ENABLE(CLASSIC_INTERPRETER)98 90 99 91 ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argumentCountIncludingThis) … … 123 115 return newCallFrame; 124 116 } 125 126 #if ENABLE(CLASSIC_INTERPRETER)127 static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData)128 {129 if (value.isObject())130 return false;131 exceptionData = createInvalidParamError(callFrame, "in" , value);132 return true;133 }134 #endif135 117 136 118 JSValue eval(CallFrame* callFrame) … … 269 251 , m_initialized(false) 270 252 #endif 271 , m_classicEnabled(false)272 253 { 273 254 } … … 275 256 Interpreter::~Interpreter() 276 257 { 277 #if ENABLE(LLINT) && ENABLE(COMPUTED_GOTO_OPCODES)278 if (m_classicEnabled)279 delete[] m_opcodeTable;280 #endif281 258 } 282 259 … … 285 262 UNUSED_PARAM(canUseJIT); 286 263 287 // If we have LLInt, then we shouldn't be building any kind of classic interpreter. 288 #if ENABLE(LLINT) && ENABLE(CLASSIC_INTERPRETER) 289 #error "Building both LLInt and the Classic Interpreter is not supported because it doesn't make sense." 290 #endif 291 292 #if ENABLE(COMPUTED_GOTO_OPCODES) 293 #if ENABLE(LLINT) 264 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) 294 265 m_opcodeTable = LLInt::opcodeMap(); 295 266 for (int i = 0; i < numOpcodeIDs; ++i) 296 267 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); 297 m_classicEnabled = false; 298 299 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) 300 if (canUseJIT) { 301 // If the JIT is present, don't use jump destinations for opcodes. 302 for (int i = 0; i < numOpcodeIDs; ++i) { 303 Opcode opcode = bitwise_cast<void*>(static_cast<uintptr_t>(i)); 304 m_opcodeTable[i] = opcode; 305 } 306 m_classicEnabled = false; 307 } else { 308 privateExecute(InitializeAndReturn, 0, 0); 309 310 for (int i = 0; i < numOpcodeIDs; ++i) 311 m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); 312 313 m_classicEnabled = true; 314 } 315 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) 316 317 #else // !ENABLE(COMPUTED_GOTO_OPCODES) 318 #if ENABLE(CLASSIC_INTERPRETER) 319 m_classicEnabled = true; 320 #else 321 m_classicEnabled = false; 322 #endif 323 #endif // !ENABLE(COMPUTED_GOTO_OPCODES) 268 #endif 324 269 325 270 #if !ASSERT_DISABLED … … 435 380 #if ENABLE(COMPUTED_GOTO_OPCODES) 436 381 #if !ENABLE(LLINT) 437 if (!m_classicEnabled) 438 return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; 439 #endif 382 return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; 383 #else 440 384 return opcode != HashTraits<Opcode>::emptyValue() 441 385 && !HashTraits<Opcode>::isDeletedValue(opcode) 442 386 && m_opcodeIDTable.contains(opcode); 387 #endif 443 388 #else 444 389 return opcode >= 0 && opcode <= op_end; … … 485 430 // information the JIT reports the bytecodeOffset for the returnPC 486 431 // to be at the beginning of the opcode that has caused the call. 487 // In the interpreter we have an actual return address, which is 488 // the beginning of next instruction to execute. To get an offset 489 // inside the call instruction that triggered the exception we 490 // have to subtract 1. 491 #if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER) 492 if (callerFrame->globalData().canUseJIT()) 493 bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); 494 else 495 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1; 496 #elif ENABLE(JIT) || ENABLE(LLINT) 432 #if ENABLE(JIT) || ENABLE(LLINT) 497 433 bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); 498 #else499 bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1;500 434 #endif 501 435 … … 563 497 if (!codeBlock) 564 498 return -1; 565 #if ENABLE(CLASSIC_INTERPRETER)566 if (!globalData->canUseJIT())567 return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode() - 1);568 #endif569 499 #if ENABLE(JIT) || ENABLE(LLINT) 570 500 #if ENABLE(DFG_JIT) … … 573 503 #endif 574 504 return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode()); 575 #else576 return -1;577 505 #endif 578 506 } … … 605 533 // Don't need to deal with inline callframes here as by definition we haven't 606 534 // inlined a call with an intervening native call frame. 607 #if ENABLE(CLASSIC_INTERPRETER)608 if (!globalData->canUseJIT()) {609 bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode();610 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);611 return callerFrame;612 }613 #endif614 535 #if ENABLE(JIT) || ENABLE(LLINT) 615 536 #if ENABLE(DFG_JIT) … … 622 543 #endif 623 544 } else { 624 #if ENABLE(CLASSIC_INTERPRETER)625 if (!globalData->canUseJIT()) {626 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());627 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);628 return callerFrame;629 }630 #endif631 545 #if ENABLE(JIT) || ENABLE(LLINT) 632 546 #if ENABLE(DFG_JIT) … … 666 580 { 667 581 ASSERT(!callFrame->hasHostCallFrameFlag()); 668 #if ENABLE(CLASSIC_INTERPRETER)669 #if ENABLE(JIT)670 if (callFrame->globalData().canUseJIT())671 return callFrame->codeBlock()->ownerExecutable()->sourceURL();672 #endif673 return callFrame->codeBlock()->source()->url();674 675 #else676 582 return callFrame->codeBlock()->ownerExecutable()->sourceURL(); 677 #endif678 583 } 679 584 … … 982 887 #if ENABLE(LLINT_C_LOOP) 983 888 result = LLInt::CLoop::execute(newCallFrame, llint_program_prologue); 984 #else // !ENABLE(LLINT_C_LOOP) 985 #if ENABLE(JIT) 986 if (!classicEnabled()) 987 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); 988 else 889 #elif ENABLE(JIT) 890 result = program->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); 989 891 #endif // ENABLE(JIT) 990 result = privateExecute(Normal, &m_registerFile, newCallFrame);991 #endif // !ENABLE(LLINT_C_LOOP)992 892 993 893 m_reentryDepth--; … … 1058 958 #if ENABLE(LLINT_C_LOOP) 1059 959 result = LLInt::CLoop::execute(newCallFrame, llint_function_for_call_prologue); 1060 #else // ENABLE(LLINT_C_LOOP) 1061 #if ENABLE(JIT) 1062 if (!classicEnabled()) 1063 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScope->globalData()); 1064 else 960 #elif ENABLE(JIT) 961 result = callData.js.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, newCallFrame, callDataScope->globalData()); 1065 962 #endif // ENABLE(JIT) 1066 result = privateExecute(Normal, &m_registerFile, newCallFrame);1067 #endif // !ENABLE(LLINT_C_LOOP)1068 963 1069 964 m_reentryDepth--; … … 1157 1052 #if ENABLE(LLINT_C_LOOP) 1158 1053 result = LLInt::CLoop::execute(newCallFrame, llint_function_for_construct_prologue); 1159 #else // !ENABLE(LLINT_C_LOOP) 1160 #if ENABLE(JIT) 1161 if (!classicEnabled()) 1162 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScope->globalData()); 1163 else 1054 #elif ENABLE(JIT) 1055 result = constructData.js.functionExecutable->generatedJITCodeForConstruct().execute(&m_registerFile, newCallFrame, constructDataScope->globalData()); 1164 1056 #endif // ENABLE(JIT) 1165 result = privateExecute(Normal, &m_registerFile, newCallFrame);1166 #endif // !ENABLE(LLINT_C_LOOP)1167 1057 m_reentryDepth--; 1168 1058 } … … 1264 1154 #if ENABLE(LLINT_C_LOOP) 1265 1155 result = LLInt::CLoop::execute(closure.newCallFrame, llint_function_for_call_prologue); 1266 #else // !ENABLE(LLINT_C_LOOP) 1267 #if ENABLE(JIT) 1268 #if ENABLE(CLASSIC_INTERPRETER) 1269 if (closure.newCallFrame->globalData().canUseJIT()) 1270 #endif 1271 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData); 1272 #if ENABLE(CLASSIC_INTERPRETER) 1273 else 1274 #endif 1156 #elif ENABLE(JIT) 1157 result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData); 1275 1158 #endif // ENABLE(JIT) 1276 #if ENABLE(CLASSIC_INTERPRETER)1277 result = privateExecute(Normal, &m_registerFile, closure.newCallFrame);1278 #endif1279 #endif // !ENABLE(LLINT_C_LOOP)1280 1281 1159 m_reentryDepth--; 1282 1160 } … … 1369 1247 #if ENABLE(LLINT_C_LOOP) 1370 1248 result = LLInt::CLoop::execute(newCallFrame, llint_eval_prologue); 1371 #else // !ENABLE(LLINT_C_LOOP) 1372 #if ENABLE(JIT) 1373 #if ENABLE(CLASSIC_INTERPRETER) 1374 if (callFrame->globalData().canUseJIT()) 1375 #endif 1376 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); 1377 #if ENABLE(CLASSIC_INTERPRETER) 1378 else 1379 #endif 1249 #elif ENABLE(JIT) 1250 result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scope->globalData()); 1380 1251 #endif // ENABLE(JIT) 1381 #if ENABLE(CLASSIC_INTERPRETER)1382 result = privateExecute(Normal, &m_registerFile, newCallFrame);1383 #endif1384 #endif // !ENABLE(LLINT_C_LOOP)1385 1252 m_reentryDepth--; 1386 1253 } … … 1421 1288 } 1422 1289 1423 #if ENABLE(CLASSIC_INTERPRETER)1424 NEVER_INLINE JSScope* Interpreter::createNameScope(CallFrame* callFrame, const Instruction* vPC)1425 {1426 CodeBlock* codeBlock = callFrame->codeBlock();1427 Identifier& property = codeBlock->identifier(vPC[1].u.operand);1428 JSValue value = callFrame->r(vPC[2].u.operand).jsValue();1429 unsigned attributes = vPC[3].u.operand;1430 JSNameScope* scope = JSNameScope::create(callFrame, property, value, attributes);1431 return scope;1432 }1433 1434 NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const PutPropertySlot& slot)1435 {1436 // Recursive invocation may already have specialized this instruction.1437 if (vPC[0].u.opcode != getOpcode(op_put_by_id))1438 return;1439 1440 if (!baseValue.isCell())1441 return;1442 1443 // Uncacheable: give up.1444 if (!slot.isCacheable()) {1445 vPC[0] = getOpcode(op_put_by_id_generic);1446 return;1447 }1448 1449 JSCell* baseCell = baseValue.asCell();1450 Structure* structure = baseCell->structure();1451 1452 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {1453 vPC[0] = getOpcode(op_put_by_id_generic);1454 return;1455 }1456 1457 // Cache miss: record Structure to compare against next time.1458 Structure* lastStructure = vPC[4].u.structure.get();1459 if (structure != lastStructure) {1460 // First miss: record Structure to compare against next time.1461 if (!lastStructure) {1462 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);1463 return;1464 }1465 1466 // Second miss: give up.1467 vPC[0] = getOpcode(op_put_by_id_generic);1468 return;1469 }1470 1471 // Cache hit: Specialize instruction and ref Structures.1472 1473 // If baseCell != slot.base(), then baseCell must be a proxy for another object.1474 if (baseCell != slot.base()) {1475 vPC[0] = getOpcode(op_put_by_id_generic);1476 return;1477 }1478 1479 // Structure transition, cache transition info1480 if (slot.type() == PutPropertySlot::NewProperty) {1481 if (structure->isDictionary()) {1482 vPC[0] = getOpcode(op_put_by_id_generic);1483 return;1484 }1485 1486 // put_by_id_transition checks the prototype chain for setters.1487 normalizePrototypeChain(callFrame, baseCell);1488 JSCell* owner = codeBlock->ownerExecutable();1489 JSGlobalData& globalData = callFrame->globalData();1490 // Get the prototype here because the call to prototypeChain could cause a1491 // GC allocation, which we don't want to happen while we're in the middle of1492 // initializing the union.1493 StructureChain* prototypeChain = structure->prototypeChain(callFrame);1494 vPC[0] = getOpcode(op_put_by_id_transition);1495 vPC[4].u.structure.set(globalData, owner, structure->previousID());1496 vPC[5].u.structure.set(globalData, owner, structure);1497 vPC[6].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);1498 ASSERT(vPC[6].u.structureChain);1499 vPC[7] = slot.cachedOffset();1500 return;1501 }1502 1503 vPC[0] = getOpcode(op_put_by_id_replace);1504 vPC[5] = slot.cachedOffset();1505 }1506 1507 NEVER_INLINE void Interpreter::uncachePutByID(CodeBlock*, Instruction* vPC)1508 {1509 vPC[0] = getOpcode(op_put_by_id);1510 vPC[4] = 0;1511 }1512 1513 NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, Instruction* vPC, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)1514 {1515 // Recursive invocation may already have specialized this instruction.1516 if (vPC[0].u.opcode != getOpcode(op_get_by_id))1517 return;1518 1519 // FIXME: Cache property access for immediates.1520 if (!baseValue.isCell()) {1521 vPC[0] = getOpcode(op_get_by_id_generic);1522 return;1523 }1524 1525 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {1526 vPC[0] = getOpcode(op_get_array_length);1527 return;1528 }1529 1530 if (isJSString(baseValue) && propertyName == callFrame->propertyNames().length) {1531 vPC[0] = getOpcode(op_get_string_length);1532 return;1533 }1534 1535 // Uncacheable: give up.1536 if (!slot.isCacheable()) {1537 vPC[0] = getOpcode(op_get_by_id_generic);1538 return;1539 }1540 1541 Structure* structure = baseValue.asCell()->structure();1542 1543 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {1544 vPC[0] = getOpcode(op_get_by_id_generic);1545 return;1546 }1547 1548 // Cache miss1549 Structure* lastStructure = vPC[4].u.structure.get();1550 if (structure != lastStructure) {1551 // First miss: record Structure to compare against next time.1552 if (!lastStructure) {1553 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);1554 return;1555 }1556 1557 // Second miss: give up.1558 vPC[0] = getOpcode(op_get_by_id_generic);1559 return;1560 }1561 1562 // Cache hit: Specialize instruction and ref Structures.1563 1564 if (slot.slotBase() == baseValue) {1565 switch (slot.cachedPropertyType()) {1566 case PropertySlot::Getter:1567 vPC[0] = getOpcode(op_get_by_id_getter_self);1568 vPC[5] = slot.cachedOffset();1569 break;1570 case PropertySlot::Custom:1571 vPC[0] = getOpcode(op_get_by_id_custom_self);1572 vPC[5] = slot.customGetter();1573 break;1574 default:1575 vPC[0] = getOpcode(op_get_by_id_self);1576 vPC[5] = slot.cachedOffset();1577 break;1578 }1579 return;1580 }1581 1582 if (structure->isDictionary()) {1583 vPC[0] = getOpcode(op_get_by_id_generic);1584 return;1585 }1586 1587 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {1588 ASSERT(slot.slotBase().isObject());1589 1590 JSObject* baseObject = asObject(slot.slotBase());1591 PropertyOffset offset = slot.cachedOffset();1592 1593 // Since we're accessing a prototype in a loop, it's a good bet that it1594 // should not be treated as a dictionary.1595 if (baseObject->structure()->isDictionary()) {1596 baseObject->flattenDictionaryObject(callFrame->globalData());1597 offset = baseObject->structure()->get(callFrame->globalData(), propertyName);1598 }1599 1600 ASSERT(!baseObject->structure()->isUncacheableDictionary());1601 1602 switch (slot.cachedPropertyType()) {1603 case PropertySlot::Getter:1604 vPC[0] = getOpcode(op_get_by_id_getter_proto);1605 vPC[6] = offset;1606 break;1607 case PropertySlot::Custom:1608 vPC[0] = getOpcode(op_get_by_id_custom_proto);1609 vPC[6] = slot.customGetter();1610 break;1611 default:1612 vPC[0] = getOpcode(op_get_by_id_proto);1613 vPC[6] = offset;1614 break;1615 }1616 vPC[5].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), baseObject->structure());1617 return;1618 }1619 1620 PropertyOffset offset = slot.cachedOffset();1621 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);1622 if (!count) {1623 vPC[0] = getOpcode(op_get_by_id_generic);1624 return;1625 }1626 1627 1628 StructureChain* prototypeChain = structure->prototypeChain(callFrame);1629 switch (slot.cachedPropertyType()) {1630 case PropertySlot::Getter:1631 vPC[0] = getOpcode(op_get_by_id_getter_chain);1632 vPC[7] = offset;1633 break;1634 case PropertySlot::Custom:1635 vPC[0] = getOpcode(op_get_by_id_custom_chain);1636 vPC[7] = slot.customGetter();1637 break;1638 default:1639 vPC[0] = getOpcode(op_get_by_id_chain);1640 vPC[7] = offset;1641 break;1642 }1643 vPC[4].u.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), structure);1644 vPC[5].u.structureChain.set(callFrame->globalData(), codeBlock->ownerExecutable(), prototypeChain);1645 vPC[6] = count;1646 }1647 1648 NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC)1649 {1650 vPC[0] = getOpcode(op_get_by_id);1651 vPC[4] = 0;1652 }1653 1654 #endif // ENABLE(CLASSIC_INTERPRETER)1655 1656 #if !ENABLE(LLINT_C_LOOP)1657 1658 JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame)1659 {1660 // One-time initialization of our address tables. We have to put this code1661 // here because our labels are only in scope inside this function.1662 if (UNLIKELY(flag == InitializeAndReturn)) {1663 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)1664 #define LIST_OPCODE_LABEL(id, length) &&id,1665 static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) };1666 for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i)1667 m_opcodeTable[i] = labels[i];1668 #undef LIST_OPCODE_LABEL1669 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)1670 return JSValue();1671 }1672 1673 ASSERT(m_initialized);1674 ASSERT(m_classicEnabled);1675 1676 #if ENABLE(JIT)1677 #if ENABLE(CLASSIC_INTERPRETER)1678 // Mixing Interpreter + JIT is not supported.1679 if (callFrame->globalData().canUseJIT())1680 #endif1681 ASSERT_NOT_REACHED();1682 #endif1683 1684 #if !ENABLE(CLASSIC_INTERPRETER)1685 UNUSED_PARAM(registerFile);1686 UNUSED_PARAM(callFrame);1687 return JSValue();1688 #else1689 1690 ASSERT(callFrame->globalData().topCallFrame == callFrame);1691 1692 JSGlobalData* globalData = &callFrame->globalData();1693 JSValue exceptionValue;1694 HandlerInfo* handler = 0;1695 CallFrame** topCallFrameSlot = &globalData->topCallFrame;1696 1697 CodeBlock* codeBlock = callFrame->codeBlock();1698 Instruction* vPC = codeBlock->instructions().begin();1699 unsigned tickCount = globalData->timeoutChecker.ticksUntilNextCheck();1700 JSValue functionReturnValue;1701 1702 #define CHECK_FOR_EXCEPTION() \1703 do { \1704 if (UNLIKELY(globalData->exception != JSValue())) { \1705 exceptionValue = globalData->exception; \1706 goto vm_throw; \1707 } \1708 } while (0)1709 1710 #if ENABLE(OPCODE_STATS)1711 OpcodeStats::resetLastInstruction();1712 #endif1713 1714 #define CHECK_FOR_TIMEOUT() \1715 if (!--tickCount) { \1716 if (globalData->terminator.shouldTerminate() || globalData->timeoutChecker.didTimeOut(callFrame)) { \1717 exceptionValue = jsNull(); \1718 goto vm_throw; \1719 } \1720 tickCount = globalData->timeoutChecker.ticksUntilNextCheck(); \1721 }1722 1723 #if ENABLE(OPCODE_SAMPLING)1724 #define SAMPLE(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)1725 #else1726 #define SAMPLE(codeBlock, vPC)1727 #endif1728 1729 #define UPDATE_BYTECODE_OFFSET() \1730 do {\1731 callFrame->setBytecodeOffsetForNonDFGCode(vPC - codeBlock->instructions().data() + 1);\1732 } while (0)1733 1734 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)1735 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode1736 #if ENABLE(OPCODE_STATS)1737 #define DEFINE_OPCODE(opcode) \1738 opcode:\1739 OpcodeStats::recordInstruction(opcode);\1740 UPDATE_BYTECODE_OFFSET();1741 #else1742 #define DEFINE_OPCODE(opcode) opcode: UPDATE_BYTECODE_OFFSET();1743 #endif // !ENABLE(OPCODE_STATS)1744 NEXT_INSTRUCTION();1745 #else // !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)1746 #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart1747 #if ENABLE(OPCODE_STATS)1748 #define DEFINE_OPCODE(opcode) \1749 case opcode:\1750 OpcodeStats::recordInstruction(opcode);\1751 UPDATE_BYTECODE_OFFSET();1752 #else1753 #define DEFINE_OPCODE(opcode) case opcode: UPDATE_BYTECODE_OFFSET();1754 #endif1755 while (1) { // iterator loop begins1756 interpreterLoopStart:;1757 switch (vPC->u.opcode)1758 #endif // !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)1759 {1760 DEFINE_OPCODE(op_new_object) {1761 /* new_object dst(r)1762 1763 Constructs a new empty Object instance using the original1764 constructor, and puts the result in register dst.1765 */1766 int dst = vPC[1].u.operand;1767 callFrame->uncheckedR(dst) = JSValue(constructEmptyObject(callFrame));1768 1769 vPC += OPCODE_LENGTH(op_new_object);1770 NEXT_INSTRUCTION();1771 }1772 DEFINE_OPCODE(op_new_array) {1773 /* new_array dst(r) firstArg(r) argCount(n)1774 1775 Constructs a new Array instance using the original1776 constructor, and puts the result in register dst.1777 The array will contain argCount elements with values1778 taken from registers starting at register firstArg.1779 */1780 int dst = vPC[1].u.operand;1781 int firstArg = vPC[2].u.operand;1782 int argCount = vPC[3].u.operand;1783 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, reinterpret_cast<JSValue*>(&callFrame->registers()[firstArg]), argCount));1784 1785 vPC += OPCODE_LENGTH(op_new_array);1786 NEXT_INSTRUCTION();1787 }1788 DEFINE_OPCODE(op_new_array_buffer) {1789 /* new_array_buffer dst(r) index(n) argCount(n)1790 1791 Constructs a new Array instance using the original1792 constructor, and puts the result in register dst.1793 The array be initialized with the values from constantBuffer[index]1794 */1795 int dst = vPC[1].u.operand;1796 int firstArg = vPC[2].u.operand;1797 int argCount = vPC[3].u.operand;1798 callFrame->uncheckedR(dst) = JSValue(constructArray(callFrame, codeBlock->constantBuffer(firstArg), argCount));1799 1800 vPC += OPCODE_LENGTH(op_new_array);1801 NEXT_INSTRUCTION();1802 }1803 DEFINE_OPCODE(op_new_regexp) {1804 /* new_regexp dst(r) regExp(re)1805 1806 Constructs a new RegExp instance using the original1807 constructor from regexp regExp, and puts the result in1808 register dst.1809 */1810 int dst = vPC[1].u.operand;1811 RegExp* regExp = codeBlock->regexp(vPC[2].u.operand);1812 if (!regExp->isValid()) {1813 exceptionValue = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");1814 goto vm_throw;1815 }1816 callFrame->uncheckedR(dst) = JSValue(RegExpObject::create(*globalData, callFrame->lexicalGlobalObject(), callFrame->scope()->globalObject()->regExpStructure(), regExp));1817 1818 vPC += OPCODE_LENGTH(op_new_regexp);1819 NEXT_INSTRUCTION();1820 }1821 DEFINE_OPCODE(op_mov) {1822 /* mov dst(r) src(r)1823 1824 Copies register src to register dst.1825 */1826 int dst = vPC[1].u.operand;1827 int src = vPC[2].u.operand;1828 1829 callFrame->uncheckedR(dst) = callFrame->r(src);1830 1831 vPC += OPCODE_LENGTH(op_mov);1832 NEXT_INSTRUCTION();1833 }1834 DEFINE_OPCODE(op_eq) {1835 /* eq dst(r) src1(r) src2(r)1836 1837 Checks whether register src1 and register src2 are equal,1838 as with the ECMAScript '==' operator, and puts the result1839 as a boolean in register dst.1840 */1841 int dst = vPC[1].u.operand;1842 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1843 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1844 if (src1.isInt32() && src2.isInt32())1845 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() == src2.asInt32());1846 else {1847 JSValue result = jsBoolean(JSValue::equalSlowCase(callFrame, src1, src2));1848 CHECK_FOR_EXCEPTION();1849 callFrame->uncheckedR(dst) = result;1850 }1851 1852 vPC += OPCODE_LENGTH(op_eq);1853 NEXT_INSTRUCTION();1854 }1855 DEFINE_OPCODE(op_eq_null) {1856 /* eq_null dst(r) src(r)1857 1858 Checks whether register src is null, as with the ECMAScript '!='1859 operator, and puts the result as a boolean in register dst.1860 */1861 int dst = vPC[1].u.operand;1862 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();1863 1864 if (src.isUndefinedOrNull()) {1865 callFrame->uncheckedR(dst) = jsBoolean(true);1866 vPC += OPCODE_LENGTH(op_eq_null);1867 NEXT_INSTRUCTION();1868 }1869 1870 callFrame->uncheckedR(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()));1871 vPC += OPCODE_LENGTH(op_eq_null);1872 NEXT_INSTRUCTION();1873 }1874 DEFINE_OPCODE(op_neq) {1875 /* neq dst(r) src1(r) src2(r)1876 1877 Checks whether register src1 and register src2 are not1878 equal, as with the ECMAScript '!=' operator, and puts the1879 result as a boolean in register dst.1880 */1881 int dst = vPC[1].u.operand;1882 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1883 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1884 if (src1.isInt32() && src2.isInt32())1885 callFrame->uncheckedR(dst) = jsBoolean(src1.asInt32() != src2.asInt32());1886 else {1887 JSValue result = jsBoolean(!JSValue::equalSlowCase(callFrame, src1, src2));1888 CHECK_FOR_EXCEPTION();1889 callFrame->uncheckedR(dst) = result;1890 }1891 1892 vPC += OPCODE_LENGTH(op_neq);1893 NEXT_INSTRUCTION();1894 }1895 DEFINE_OPCODE(op_neq_null) {1896 /* neq_null dst(r) src(r)1897 1898 Checks whether register src is not null, as with the ECMAScript '!='1899 operator, and puts the result as a boolean in register dst.1900 */1901 int dst = vPC[1].u.operand;1902 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();1903 1904 if (src.isUndefinedOrNull()) {1905 callFrame->uncheckedR(dst) = jsBoolean(false);1906 vPC += OPCODE_LENGTH(op_neq_null);1907 NEXT_INSTRUCTION();1908 }1909 1910 callFrame->uncheckedR(dst) = jsBoolean(!src.isCell() || !src.asCell()->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()));1911 vPC += OPCODE_LENGTH(op_neq_null);1912 NEXT_INSTRUCTION();1913 }1914 DEFINE_OPCODE(op_stricteq) {1915 /* stricteq dst(r) src1(r) src2(r)1916 1917 Checks whether register src1 and register src2 are strictly1918 equal, as with the ECMAScript '===' operator, and puts the1919 result as a boolean in register dst.1920 */1921 int dst = vPC[1].u.operand;1922 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1923 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1924 bool result = JSValue::strictEqual(callFrame, src1, src2);1925 CHECK_FOR_EXCEPTION();1926 callFrame->uncheckedR(dst) = jsBoolean(result);1927 1928 vPC += OPCODE_LENGTH(op_stricteq);1929 NEXT_INSTRUCTION();1930 }1931 DEFINE_OPCODE(op_nstricteq) {1932 /* nstricteq dst(r) src1(r) src2(r)1933 1934 Checks whether register src1 and register src2 are not1935 strictly equal, as with the ECMAScript '!==' operator, and1936 puts the result as a boolean in register dst.1937 */1938 int dst = vPC[1].u.operand;1939 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1940 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1941 bool result = !JSValue::strictEqual(callFrame, src1, src2);1942 CHECK_FOR_EXCEPTION();1943 callFrame->uncheckedR(dst) = jsBoolean(result);1944 1945 vPC += OPCODE_LENGTH(op_nstricteq);1946 NEXT_INSTRUCTION();1947 }1948 DEFINE_OPCODE(op_less) {1949 /* less dst(r) src1(r) src2(r)1950 1951 Checks whether register src1 is less than register src2, as1952 with the ECMAScript '<' operator, and puts the result as1953 a boolean in register dst.1954 */1955 int dst = vPC[1].u.operand;1956 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1957 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1958 JSValue result = jsBoolean(jsLess<true>(callFrame, src1, src2));1959 CHECK_FOR_EXCEPTION();1960 callFrame->uncheckedR(dst) = result;1961 1962 vPC += OPCODE_LENGTH(op_less);1963 NEXT_INSTRUCTION();1964 }1965 DEFINE_OPCODE(op_lesseq) {1966 /* lesseq dst(r) src1(r) src2(r)1967 1968 Checks whether register src1 is less than or equal to1969 register src2, as with the ECMAScript '<=' operator, and1970 puts the result as a boolean in register dst.1971 */1972 int dst = vPC[1].u.operand;1973 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1974 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1975 JSValue result = jsBoolean(jsLessEq<true>(callFrame, src1, src2));1976 CHECK_FOR_EXCEPTION();1977 callFrame->uncheckedR(dst) = result;1978 1979 vPC += OPCODE_LENGTH(op_lesseq);1980 NEXT_INSTRUCTION();1981 }1982 DEFINE_OPCODE(op_greater) {1983 /* greater dst(r) src1(r) src2(r)1984 1985 Checks whether register src1 is greater than register src2, as1986 with the ECMAScript '>' operator, and puts the result as1987 a boolean in register dst.1988 */1989 int dst = vPC[1].u.operand;1990 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();1991 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();1992 JSValue result = jsBoolean(jsLess<false>(callFrame, src2, src1));1993 CHECK_FOR_EXCEPTION();1994 callFrame->uncheckedR(dst) = result;1995 1996 vPC += OPCODE_LENGTH(op_greater);1997 NEXT_INSTRUCTION();1998 }1999 DEFINE_OPCODE(op_greatereq) {2000 /* greatereq dst(r) src1(r) src2(r)2001 2002 Checks whether register src1 is greater than or equal to2003 register src2, as with the ECMAScript '>=' operator, and2004 puts the result as a boolean in register dst.2005 */2006 int dst = vPC[1].u.operand;2007 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2008 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2009 JSValue result = jsBoolean(jsLessEq<false>(callFrame, src2, src1));2010 CHECK_FOR_EXCEPTION();2011 callFrame->uncheckedR(dst) = result;2012 2013 vPC += OPCODE_LENGTH(op_greatereq);2014 NEXT_INSTRUCTION();2015 }2016 DEFINE_OPCODE(op_pre_inc) {2017 /* pre_inc srcDst(r)2018 2019 Converts register srcDst to number, adds one, and puts the result2020 back in register srcDst.2021 */2022 int srcDst = vPC[1].u.operand;2023 JSValue v = callFrame->r(srcDst).jsValue();2024 if (v.isInt32() && v.asInt32() < INT_MAX)2025 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);2026 else {2027 JSValue result = jsNumber(v.toNumber(callFrame) + 1);2028 CHECK_FOR_EXCEPTION();2029 callFrame->uncheckedR(srcDst) = result;2030 }2031 2032 vPC += OPCODE_LENGTH(op_pre_inc);2033 NEXT_INSTRUCTION();2034 }2035 DEFINE_OPCODE(op_pre_dec) {2036 /* pre_dec srcDst(r)2037 2038 Converts register srcDst to number, subtracts one, and puts the result2039 back in register srcDst.2040 */2041 int srcDst = vPC[1].u.operand;2042 JSValue v = callFrame->r(srcDst).jsValue();2043 if (v.isInt32() && v.asInt32() > INT_MIN)2044 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);2045 else {2046 JSValue result = jsNumber(v.toNumber(callFrame) - 1);2047 CHECK_FOR_EXCEPTION();2048 callFrame->uncheckedR(srcDst) = result;2049 }2050 2051 vPC += OPCODE_LENGTH(op_pre_dec);2052 NEXT_INSTRUCTION();2053 }2054 DEFINE_OPCODE(op_post_inc) {2055 /* post_inc dst(r) srcDst(r)2056 2057 Converts register srcDst to number. The number itself is2058 written to register dst, and the number plus one is written2059 back to register srcDst.2060 */2061 int dst = vPC[1].u.operand;2062 int srcDst = vPC[2].u.operand;2063 JSValue v = callFrame->r(srcDst).jsValue();2064 if (v.isInt32() && v.asInt32() < INT_MAX) {2065 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() + 1);2066 callFrame->uncheckedR(dst) = v;2067 } else {2068 double number = callFrame->r(srcDst).jsValue().toNumber(callFrame);2069 CHECK_FOR_EXCEPTION();2070 callFrame->uncheckedR(srcDst) = jsNumber(number + 1);2071 callFrame->uncheckedR(dst) = jsNumber(number);2072 }2073 2074 vPC += OPCODE_LENGTH(op_post_inc);2075 NEXT_INSTRUCTION();2076 }2077 DEFINE_OPCODE(op_post_dec) {2078 /* post_dec dst(r) srcDst(r)2079 2080 Converts register srcDst to number. The number itself is2081 written to register dst, and the number minus one is written2082 back to register srcDst.2083 */2084 int dst = vPC[1].u.operand;2085 int srcDst = vPC[2].u.operand;2086 JSValue v = callFrame->r(srcDst).jsValue();2087 if (v.isInt32() && v.asInt32() > INT_MIN) {2088 callFrame->uncheckedR(srcDst) = jsNumber(v.asInt32() - 1);2089 callFrame->uncheckedR(dst) = v;2090 } else {2091 double number = callFrame->r(srcDst).jsValue().toNumber(callFrame);2092 CHECK_FOR_EXCEPTION();2093 callFrame->uncheckedR(srcDst) = jsNumber(number - 1);2094 callFrame->uncheckedR(dst) = jsNumber(number);2095 }2096 2097 vPC += OPCODE_LENGTH(op_post_dec);2098 NEXT_INSTRUCTION();2099 }2100 DEFINE_OPCODE(op_to_jsnumber) {2101 /* to_jsnumber dst(r) src(r)2102 2103 Converts register src to number, and puts the result2104 in register dst.2105 */2106 int dst = vPC[1].u.operand;2107 int src = vPC[2].u.operand;2108 2109 JSValue srcVal = callFrame->r(src).jsValue();2110 2111 if (LIKELY(srcVal.isNumber()))2112 callFrame->uncheckedR(dst) = callFrame->r(src);2113 else {2114 double number = srcVal.toNumber(callFrame);2115 CHECK_FOR_EXCEPTION();2116 callFrame->uncheckedR(dst) = jsNumber(number);2117 }2118 2119 vPC += OPCODE_LENGTH(op_to_jsnumber);2120 NEXT_INSTRUCTION();2121 }2122 DEFINE_OPCODE(op_negate) {2123 /* negate dst(r) src(r)2124 2125 Converts register src to number, negates it, and puts the2126 result in register dst.2127 */2128 int dst = vPC[1].u.operand;2129 JSValue src = callFrame->r(vPC[2].u.operand).jsValue();2130 if (src.isInt32() && (src.asInt32() & 0x7fffffff)) // non-zero and no overflow2131 callFrame->uncheckedR(dst) = jsNumber(-src.asInt32());2132 else {2133 JSValue result = jsNumber(-src.toNumber(callFrame));2134 CHECK_FOR_EXCEPTION();2135 callFrame->uncheckedR(dst) = result;2136 }2137 2138 vPC += OPCODE_LENGTH(op_negate);2139 NEXT_INSTRUCTION();2140 }2141 DEFINE_OPCODE(op_add) {2142 /* add dst(r) src1(r) src2(r)2143 2144 Adds register src1 and register src2, and puts the result2145 in register dst. (JS add may be string concatenation or2146 numeric add, depending on the types of the operands.)2147 */2148 int dst = vPC[1].u.operand;2149 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2150 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2151 if (src1.isInt32() && src2.isInt32() && !((src1.asInt32() | src2.asInt32()) & 0xc0000000)) // no overflow2152 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() + src2.asInt32());2153 else {2154 JSValue result = jsAdd(callFrame, src1, src2);2155 CHECK_FOR_EXCEPTION();2156 callFrame->uncheckedR(dst) = result;2157 }2158 vPC += OPCODE_LENGTH(op_add);2159 NEXT_INSTRUCTION();2160 }2161 DEFINE_OPCODE(op_mul) {2162 /* mul dst(r) src1(r) src2(r)2163 2164 Multiplies register src1 and register src2 (converted to2165 numbers), and puts the product in register dst.2166 */2167 int dst = vPC[1].u.operand;2168 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2169 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2170 if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32()) >> 15) // no overflow2171 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() * src2.asInt32());2172 else {2173 JSValue result = jsNumber(src1.toNumber(callFrame) * src2.toNumber(callFrame));2174 CHECK_FOR_EXCEPTION();2175 callFrame->uncheckedR(dst) = result;2176 }2177 2178 vPC += OPCODE_LENGTH(op_mul);2179 NEXT_INSTRUCTION();2180 }2181 DEFINE_OPCODE(op_div) {2182 /* div dst(r) dividend(r) divisor(r)2183 2184 Divides register dividend (converted to number) by the2185 register divisor (converted to number), and puts the2186 quotient in register dst.2187 */2188 int dst = vPC[1].u.operand;2189 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();2190 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();2191 2192 JSValue result = jsNumber(dividend.toNumber(callFrame) / divisor.toNumber(callFrame));2193 CHECK_FOR_EXCEPTION();2194 callFrame->uncheckedR(dst) = result;2195 2196 vPC += OPCODE_LENGTH(op_div);2197 NEXT_INSTRUCTION();2198 }2199 DEFINE_OPCODE(op_mod) {2200 /* mod dst(r) dividend(r) divisor(r)2201 2202 Divides register dividend (converted to number) by2203 register divisor (converted to number), and puts the2204 remainder in register dst.2205 */2206 int dst = vPC[1].u.operand;2207 JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue();2208 JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue();2209 2210 if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0 && divisor.asInt32() != -1) {2211 JSValue result = jsNumber(dividend.asInt32() % divisor.asInt32());2212 ASSERT(result);2213 callFrame->uncheckedR(dst) = result;2214 vPC += OPCODE_LENGTH(op_mod);2215 NEXT_INSTRUCTION();2216 }2217 2218 // Conversion to double must happen outside the call to fmod since the2219 // order of argument evaluation is not guaranteed.2220 double d1 = dividend.toNumber(callFrame);2221 double d2 = divisor.toNumber(callFrame);2222 JSValue result = jsNumber(fmod(d1, d2));2223 CHECK_FOR_EXCEPTION();2224 callFrame->uncheckedR(dst) = result;2225 vPC += OPCODE_LENGTH(op_mod);2226 NEXT_INSTRUCTION();2227 }2228 DEFINE_OPCODE(op_sub) {2229 /* sub dst(r) src1(r) src2(r)2230 2231 Subtracts register src2 (converted to number) from register2232 src1 (converted to number), and puts the difference in2233 register dst.2234 */2235 int dst = vPC[1].u.operand;2236 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2237 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2238 if (src1.isInt32() && src2.isInt32() && !((src1.asInt32() | src2.asInt32()) & 0xc0000000)) // no overflow2239 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() - src2.asInt32());2240 else {2241 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));2242 CHECK_FOR_EXCEPTION();2243 callFrame->uncheckedR(dst) = result;2244 }2245 vPC += OPCODE_LENGTH(op_sub);2246 NEXT_INSTRUCTION();2247 }2248 DEFINE_OPCODE(op_lshift) {2249 /* lshift dst(r) val(r) shift(r)2250 2251 Performs left shift of register val (converted to int32) by2252 register shift (converted to uint32), and puts the result2253 in register dst.2254 */2255 int dst = vPC[1].u.operand;2256 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();2257 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();2258 2259 if (val.isInt32() && shift.isInt32())2260 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() << (shift.asInt32() & 0x1f));2261 else {2262 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));2263 CHECK_FOR_EXCEPTION();2264 callFrame->uncheckedR(dst) = result;2265 }2266 2267 vPC += OPCODE_LENGTH(op_lshift);2268 NEXT_INSTRUCTION();2269 }2270 DEFINE_OPCODE(op_rshift) {2271 /* rshift dst(r) val(r) shift(r)2272 2273 Performs arithmetic right shift of register val (converted2274 to int32) by register shift (converted to2275 uint32), and puts the result in register dst.2276 */2277 int dst = vPC[1].u.operand;2278 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();2279 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();2280 2281 if (val.isInt32() && shift.isInt32())2282 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));2283 else {2284 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));2285 CHECK_FOR_EXCEPTION();2286 callFrame->uncheckedR(dst) = result;2287 }2288 2289 vPC += OPCODE_LENGTH(op_rshift);2290 NEXT_INSTRUCTION();2291 }2292 DEFINE_OPCODE(op_urshift) {2293 /* rshift dst(r) val(r) shift(r)2294 2295 Performs logical right shift of register val (converted2296 to uint32) by register shift (converted to2297 uint32), and puts the result in register dst.2298 */2299 int dst = vPC[1].u.operand;2300 JSValue val = callFrame->r(vPC[2].u.operand).jsValue();2301 JSValue shift = callFrame->r(vPC[3].u.operand).jsValue();2302 if (val.isUInt32() && shift.isInt32())2303 callFrame->uncheckedR(dst) = jsNumber(val.asInt32() >> (shift.asInt32() & 0x1f));2304 else {2305 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));2306 CHECK_FOR_EXCEPTION();2307 callFrame->uncheckedR(dst) = result;2308 }2309 2310 vPC += OPCODE_LENGTH(op_urshift);2311 NEXT_INSTRUCTION();2312 }2313 DEFINE_OPCODE(op_bitand) {2314 /* bitand dst(r) src1(r) src2(r)2315 2316 Computes bitwise AND of register src1 (converted to int32)2317 and register src2 (converted to int32), and puts the result2318 in register dst.2319 */2320 int dst = vPC[1].u.operand;2321 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2322 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2323 if (src1.isInt32() && src2.isInt32())2324 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() & src2.asInt32());2325 else {2326 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));2327 CHECK_FOR_EXCEPTION();2328 callFrame->uncheckedR(dst) = result;2329 }2330 2331 vPC += OPCODE_LENGTH(op_bitand);2332 NEXT_INSTRUCTION();2333 }2334 DEFINE_OPCODE(op_bitxor) {2335 /* bitxor dst(r) src1(r) src2(r)2336 2337 Computes bitwise XOR of register src1 (converted to int32)2338 and register src2 (converted to int32), and puts the result2339 in register dst.2340 */2341 int dst = vPC[1].u.operand;2342 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2343 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2344 if (src1.isInt32() && src2.isInt32())2345 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() ^ src2.asInt32());2346 else {2347 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));2348 CHECK_FOR_EXCEPTION();2349 callFrame->uncheckedR(dst) = result;2350 }2351 2352 vPC += OPCODE_LENGTH(op_bitxor);2353 NEXT_INSTRUCTION();2354 }2355 DEFINE_OPCODE(op_bitor) {2356 /* bitor dst(r) src1(r) src2(r)2357 2358 Computes bitwise OR of register src1 (converted to int32)2359 and register src2 (converted to int32), and puts the2360 result in register dst.2361 */2362 int dst = vPC[1].u.operand;2363 JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue();2364 JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue();2365 if (src1.isInt32() && src2.isInt32())2366 callFrame->uncheckedR(dst) = jsNumber(src1.asInt32() | src2.asInt32());2367 else {2368 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));2369 CHECK_FOR_EXCEPTION();2370 callFrame->uncheckedR(dst) = result;2371 }2372 2373 vPC += OPCODE_LENGTH(op_bitor);2374 NEXT_INSTRUCTION();2375 }2376 DEFINE_OPCODE(op_not) {2377 /* not dst(r) src(r)2378 2379 Computes logical NOT of register src (converted to2380 boolean), and puts the result in register dst.2381 */2382 int dst = vPC[1].u.operand;2383 int src = vPC[2].u.operand;2384 JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame));2385 CHECK_FOR_EXCEPTION();2386 callFrame->uncheckedR(dst) = result;2387 2388 vPC += OPCODE_LENGTH(op_not);2389 NEXT_INSTRUCTION();2390 }2391 DEFINE_OPCODE(op_check_has_instance) {2392 /* check_has_instance constructor(r)2393 2394 Check 'constructor' is an object with the internal property2395 [HasInstance] (i.e. is a function ... *shakes head sadly at2396 JSC API*). Raises an exception if register constructor is not2397 an valid parameter for instanceof.2398 */2399 int dst = vPC[1].u.operand;2400 int value = vPC[2].u.operand;2401 int base = vPC[3].u.operand;2402 int target = vPC[4].u.operand;2403 2404 JSValue baseVal = callFrame->r(base).jsValue();2405 2406 if (baseVal.isObject()) {2407 TypeInfo info = asObject(baseVal)->structure()->typeInfo();2408 if (info.implementsDefaultHasInstance()) {2409 vPC += OPCODE_LENGTH(op_check_has_instance);2410 NEXT_INSTRUCTION();2411 }2412 if (info.implementsHasInstance()) {2413 JSValue baseVal = callFrame->r(base).jsValue();2414 bool result = asObject(baseVal)->methodTable()->customHasInstance(asObject(baseVal), callFrame, callFrame->r(value).jsValue());2415 CHECK_FOR_EXCEPTION();2416 callFrame->uncheckedR(dst) = jsBoolean(result);2417 2418 vPC += target;2419 NEXT_INSTRUCTION();2420 }2421 }2422 2423 exceptionValue = createInvalidParamError(callFrame, "instanceof" , baseVal);2424 goto vm_throw;2425 }2426 DEFINE_OPCODE(op_instanceof) {2427 /* instanceof dst(r) value(r) constructor(r) constructorProto(r)2428 2429 Tests whether register value is an instance of register2430 constructor, and puts the boolean result in register2431 dst. Register constructorProto must contain the "prototype"2432 property (not the actual prototype) of the object in2433 register constructor. This lookup is separated so that2434 polymorphic inline caching can apply.2435 2436 Raises an exception if register constructor is not an2437 object.2438 */2439 int dst = vPC[1].u.operand;2440 int value = vPC[2].u.operand;2441 int baseProto = vPC[3].u.operand;2442 2443 bool result = JSObject::defaultHasInstance(callFrame, callFrame->r(value).jsValue(), callFrame->r(baseProto).jsValue());2444 CHECK_FOR_EXCEPTION();2445 callFrame->uncheckedR(dst) = jsBoolean(result);2446 2447 vPC += OPCODE_LENGTH(op_instanceof);2448 NEXT_INSTRUCTION();2449 }2450 DEFINE_OPCODE(op_typeof) {2451 /* typeof dst(r) src(r)2452 2453 Determines the type string for src according to ECMAScript2454 rules, and puts the result in register dst.2455 */2456 int dst = vPC[1].u.operand;2457 int src = vPC[2].u.operand;2458 callFrame->uncheckedR(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue()));2459 2460 vPC += OPCODE_LENGTH(op_typeof);2461 NEXT_INSTRUCTION();2462 }2463 DEFINE_OPCODE(op_is_undefined) {2464 /* is_undefined dst(r) src(r)2465 2466 Determines whether the type string for src according to2467 the ECMAScript rules is "undefined", and puts the result2468 in register dst.2469 */2470 int dst = vPC[1].u.operand;2471 int src = vPC[2].u.operand;2472 JSValue v = callFrame->r(src).jsValue();2473 callFrame->uncheckedR(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()) : v.isUndefined());2474 2475 vPC += OPCODE_LENGTH(op_is_undefined);2476 NEXT_INSTRUCTION();2477 }2478 DEFINE_OPCODE(op_is_boolean) {2479 /* is_boolean dst(r) src(r)2480 2481 Determines whether the type string for src according to2482 the ECMAScript rules is "boolean", and puts the result2483 in register dst.2484 */2485 int dst = vPC[1].u.operand;2486 int src = vPC[2].u.operand;2487 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean());2488 2489 vPC += OPCODE_LENGTH(op_is_boolean);2490 NEXT_INSTRUCTION();2491 }2492 DEFINE_OPCODE(op_is_number) {2493 /* is_number dst(r) src(r)2494 2495 Determines whether the type string for src according to2496 the ECMAScript rules is "number", and puts the result2497 in register dst.2498 */2499 int dst = vPC[1].u.operand;2500 int src = vPC[2].u.operand;2501 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber());2502 2503 vPC += OPCODE_LENGTH(op_is_number);2504 NEXT_INSTRUCTION();2505 }2506 DEFINE_OPCODE(op_is_string) {2507 /* is_string dst(r) src(r)2508 2509 Determines whether the type string for src according to2510 the ECMAScript rules is "string", and puts the result2511 in register dst.2512 */2513 int dst = vPC[1].u.operand;2514 int src = vPC[2].u.operand;2515 callFrame->uncheckedR(dst) = jsBoolean(callFrame->r(src).jsValue().isString());2516 2517 vPC += OPCODE_LENGTH(op_is_string);2518 NEXT_INSTRUCTION();2519 }2520 DEFINE_OPCODE(op_is_object) {2521 /* is_object dst(r) src(r)2522 2523 Determines whether the type string for src according to2524 the ECMAScript rules is "object", and puts the result2525 in register dst.2526 */2527 int dst = vPC[1].u.operand;2528 int src = vPC[2].u.operand;2529 callFrame->uncheckedR(dst) = jsBoolean(jsIsObjectType(callFrame, callFrame->r(src).jsValue()));2530 2531 vPC += OPCODE_LENGTH(op_is_object);2532 NEXT_INSTRUCTION();2533 }2534 DEFINE_OPCODE(op_is_function) {2535 /* is_function dst(r) src(r)2536 2537 Determines whether the type string for src according to2538 the ECMAScript rules is "function", and puts the result2539 in register dst.2540 */2541 int dst = vPC[1].u.operand;2542 int src = vPC[2].u.operand;2543 callFrame->uncheckedR(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue()));2544 2545 vPC += OPCODE_LENGTH(op_is_function);2546 NEXT_INSTRUCTION();2547 }2548 DEFINE_OPCODE(op_in) {2549 /* in dst(r) property(r) base(r)2550 2551 Tests whether register base has a property named register2552 property, and puts the boolean result in register dst.2553 2554 Raises an exception if register constructor is not an2555 object.2556 */2557 int dst = vPC[1].u.operand;2558 int property = vPC[2].u.operand;2559 int base = vPC[3].u.operand;2560 2561 JSValue baseVal = callFrame->r(base).jsValue();2562 if (isInvalidParamForIn(callFrame, baseVal, exceptionValue))2563 goto vm_throw;2564 2565 JSObject* baseObj = asObject(baseVal);2566 2567 JSValue propName = callFrame->r(property).jsValue();2568 2569 uint32_t i;2570 if (propName.getUInt32(i))2571 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, i));2572 else if (isName(propName))2573 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, jsCast<NameInstance*>(propName.asCell())->privateName()));2574 else {2575 Identifier property(callFrame, propName.toString(callFrame)->value(callFrame));2576 CHECK_FOR_EXCEPTION();2577 callFrame->uncheckedR(dst) = jsBoolean(baseObj->hasProperty(callFrame, property));2578 }2579 2580 vPC += OPCODE_LENGTH(op_in);2581 NEXT_INSTRUCTION();2582 }2583 DEFINE_OPCODE(op_resolve) {2584 /* resolve dst(r) property(id)2585 2586 Looks up the property named by identifier property in the2587 scope chain, and writes the resulting value to register2588 dst. If the property is not found, raises an exception.2589 */2590 int dst = vPC[1].u.operand;2591 int property = vPC[2].u.operand;2592 Identifier& ident = callFrame->codeBlock()->identifier(property);2593 2594 JSValue result = JSScope::resolve(callFrame, ident);2595 CHECK_FOR_EXCEPTION();2596 callFrame->uncheckedR(dst) = result;2597 2598 vPC += OPCODE_LENGTH(op_resolve);2599 NEXT_INSTRUCTION();2600 }2601 DEFINE_OPCODE(op_resolve_skip) {2602 /* resolve_skip dst(r) property(id) skip(n)2603 2604 Looks up the property named by identifier property in the2605 scope chain skipping the top 'skip' levels, and writes the resulting2606 value to register dst. If the property is not found, raises an exception.2607 */2608 int dst = vPC[1].u.operand;2609 int property = vPC[2].u.operand;2610 int skip = vPC[3].u.operand;2611 Identifier& ident = callFrame->codeBlock()->identifier(property);2612 2613 JSValue result = JSScope::resolveSkip(callFrame, ident, skip);2614 CHECK_FOR_EXCEPTION();2615 callFrame->uncheckedR(dst) = result;2616 2617 vPC += OPCODE_LENGTH(op_resolve_skip);2618 NEXT_INSTRUCTION();2619 }2620 DEFINE_OPCODE(op_resolve_global) {2621 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n)2622 2623 Performs a dynamic property lookup for the given property, on the provided2624 global object. If structure matches the Structure of the global then perform2625 a fast lookup using the case offset, otherwise fall back to a full resolve and2626 cache the new structure and offset2627 */2628 int dst = vPC[1].u.operand;2629 int property = vPC[2].u.operand;2630 Identifier& ident = callFrame->codeBlock()->identifier(property);2631 2632 JSValue result = JSScope::resolveGlobal(2633 callFrame,2634 ident,2635 callFrame->lexicalGlobalObject(),2636 &vPC[3].u.structure,2637 &vPC[4].u.operand2638 );2639 CHECK_FOR_EXCEPTION();2640 callFrame->uncheckedR(dst) = result;2641 2642 vPC += OPCODE_LENGTH(op_resolve_global);2643 NEXT_INSTRUCTION();2644 }2645 DEFINE_OPCODE(op_resolve_global_dynamic) {2646 /* resolve_skip dst(r) globalObject(c) property(id) structure(sID) offset(n), depth(n)2647 2648 Performs a dynamic property lookup for the given property, on the provided2649 global object. If structure matches the Structure of the global then perform2650 a fast lookup using the case offset, otherwise fall back to a full resolve and2651 cache the new structure and offset.2652 2653 This walks through n levels of the scope chain to verify that none of those levels2654 in the scope chain include dynamically added properties.2655 */2656 int dst = vPC[1].u.operand;2657 int property = vPC[2].u.operand;2658 int skip = vPC[5].u.operand;2659 Identifier& ident = callFrame->codeBlock()->identifier(property);2660 2661 JSValue result = JSScope::resolveGlobalDynamic(callFrame, ident, skip, &vPC[3].u.structure, &vPC[4].u.operand);2662 CHECK_FOR_EXCEPTION();2663 callFrame->uncheckedR(dst) = result;2664 2665 vPC += OPCODE_LENGTH(op_resolve_global_dynamic);2666 NEXT_INSTRUCTION();2667 }2668 DEFINE_OPCODE(op_get_global_var) {2669 /* get_global_var dst(r) globalObject(c) registerPointer(n)2670 2671 Gets the global var at global slot index and places it in register dst.2672 */2673 int dst = vPC[1].u.operand;2674 WriteBarrier<Unknown>* registerPointer = vPC[2].u.registerPointer;2675 2676 callFrame->uncheckedR(dst) = registerPointer->get();2677 vPC += OPCODE_LENGTH(op_get_global_var);2678 NEXT_INSTRUCTION();2679 }2680 DEFINE_OPCODE(op_get_global_var_watchable) {2681 /* get_global_var_watchable dst(r) globalObject(c) registerPointer(n)2682 2683 Gets the global var at global slot index and places it in register dst.2684 */2685 int dst = vPC[1].u.operand;2686 WriteBarrier<Unknown>* registerPointer = vPC[2].u.registerPointer;2687 2688 callFrame->uncheckedR(dst) = registerPointer->get();2689 vPC += OPCODE_LENGTH(op_get_global_var_watchable);2690 NEXT_INSTRUCTION();2691 }2692 DEFINE_OPCODE(op_init_global_const)2693 DEFINE_OPCODE(op_put_global_var) {2694 /* put_global_var globalObject(c) registerPointer(n) value(r)2695 2696 Puts value into global slot index.2697 */2698 JSGlobalObject* scope = codeBlock->globalObject();2699 ASSERT(scope->isGlobalObject());2700 WriteBarrier<Unknown>* registerPointer = vPC[1].u.registerPointer;2701 int value = vPC[2].u.operand;2702 2703 registerPointer->set(*globalData, scope, callFrame->r(value).jsValue());2704 vPC += OPCODE_LENGTH(op_put_global_var);2705 NEXT_INSTRUCTION();2706 }2707 DEFINE_OPCODE(op_init_global_const_check)2708 DEFINE_OPCODE(op_put_global_var_check) {2709 /* put_global_var_check globalObject(c) registerPointer(n) value(r)2710 2711 Puts value into global slot index. In JIT configurations this will2712 perform a watchpoint check. If we're running with the old interpreter,2713 this is not necessary; the interpreter never uses these watchpoints.2714 */2715 JSGlobalObject* scope = codeBlock->globalObject();2716 ASSERT(scope->isGlobalObject());2717 WriteBarrier<Unknown>* registerPointer = vPC[1].u.registerPointer;2718 int value = vPC[2].u.operand;2719 2720 registerPointer->set(*globalData, scope, callFrame->r(value).jsValue());2721 vPC += OPCODE_LENGTH(op_put_global_var_check);2722 NEXT_INSTRUCTION();2723 }2724 DEFINE_OPCODE(op_get_scoped_var) {2725 /* get_scoped_var dst(r) index(n) skip(n)2726 2727 Loads the contents of the index-th local from the scope skip nodes from2728 the top of the scope chain, and places it in register dst.2729 */2730 int dst = vPC[1].u.operand;2731 int index = vPC[2].u.operand;2732 int skip = vPC[3].u.operand;2733 2734 JSScope* scope = callFrame->scope();2735 ScopeChainIterator iter = scope->begin();2736 ScopeChainIterator end = scope->end();2737 ASSERT_UNUSED(end, iter != end);2738 ASSERT(codeBlock == callFrame->codeBlock());2739 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();2740 ASSERT(skip || !checkTopLevel);2741 if (checkTopLevel && skip--) {2742 if (callFrame->r(codeBlock->activationRegister()).jsValue())2743 ++iter;2744 }2745 while (skip--) {2746 ++iter;2747 ASSERT_UNUSED(end, iter != end);2748 }2749 ASSERT(iter->isVariableObject());2750 JSVariableObject* variableObject = jsCast<JSVariableObject*>(iter.get());2751 callFrame->uncheckedR(dst) = variableObject->registerAt(index).get();2752 ASSERT(callFrame->r(dst).jsValue());2753 vPC += OPCODE_LENGTH(op_get_scoped_var);2754 NEXT_INSTRUCTION();2755 }2756 DEFINE_OPCODE(op_put_scoped_var) {2757 /* put_scoped_var index(n) skip(n) value(r)2758 2759 */2760 int index = vPC[1].u.operand;2761 int skip = vPC[2].u.operand;2762 int value = vPC[3].u.operand;2763 2764 JSScope* scope = callFrame->scope();2765 ScopeChainIterator iter = scope->begin();2766 ScopeChainIterator end = scope->end();2767 ASSERT(codeBlock == callFrame->codeBlock());2768 ASSERT_UNUSED(end, iter != end);2769 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();2770 ASSERT(skip || !checkTopLevel);2771 if (checkTopLevel && skip--) {2772 if (callFrame->r(codeBlock->activationRegister()).jsValue())2773 ++iter;2774 }2775 while (skip--) {2776 ++iter;2777 ASSERT_UNUSED(end, iter != end);2778 }2779 2780 ASSERT(iter->isVariableObject());2781 JSVariableObject* variableObject = jsCast<JSVariableObject*>(iter.get());2782 ASSERT(callFrame->r(value).jsValue());2783 variableObject->registerAt(index).set(*globalData, variableObject, callFrame->r(value).jsValue());2784 vPC += OPCODE_LENGTH(op_put_scoped_var);2785 NEXT_INSTRUCTION();2786 }2787 DEFINE_OPCODE(op_resolve_base) {2788 /* resolve_base dst(r) property(id) isStrict(bool)2789 2790 Searches the scope chain for an object containing2791 identifier property, and if one is found, writes it to2792 register dst. If none is found and isStrict is false, the2793 outermost scope (which will be the global object) is2794 stored in register dst.2795 */2796 int dst = vPC[1].u.operand;2797 int property = vPC[2].u.operand;2798 bool isStrict = vPC[3].u.operand;2799 Identifier& ident = callFrame->codeBlock()->identifier(property);2800 2801 JSValue result = JSScope::resolveBase(callFrame, ident, isStrict);2802 CHECK_FOR_EXCEPTION();2803 callFrame->uncheckedR(dst) = result;2804 2805 vPC += OPCODE_LENGTH(op_resolve_base);2806 NEXT_INSTRUCTION();2807 }2808 DEFINE_OPCODE(op_ensure_property_exists) {2809 /* ensure_property_exists base(r) property(id)2810 2811 Throws an exception if property does not exist on base2812 */2813 int base = vPC[1].u.operand;2814 int property = vPC[2].u.operand;2815 Identifier& ident = codeBlock->identifier(property);2816 2817 JSValue baseVal = callFrame->r(base).jsValue();2818 JSObject* baseObject = asObject(baseVal);2819 PropertySlot slot(baseVal);2820 if (!baseObject->getPropertySlot(callFrame, ident, slot)) {2821 exceptionValue = createErrorForInvalidGlobalAssignment(callFrame, ident.string());2822 goto vm_throw;2823 }2824 2825 vPC += OPCODE_LENGTH(op_ensure_property_exists);2826 NEXT_INSTRUCTION();2827 }2828 DEFINE_OPCODE(op_resolve_with_base) {2829 /* resolve_with_base baseDst(r) propDst(r) property(id)2830 2831 Searches the scope chain for an object containing2832 identifier property, and if one is found, writes it to2833 register srcDst, and the retrieved property value to register2834 propDst. If the property is not found, raises an exception.2835 2836 This is more efficient than doing resolve_base followed by2837 resolve, or resolve_base followed by get_by_id, as it2838 avoids duplicate hash lookups.2839 */2840 int baseDst = vPC[1].u.operand;2841 int propDst = vPC[2].u.operand;2842 int property = vPC[3].u.operand;2843 Identifier& ident = codeBlock->identifier(property);2844 2845 JSValue prop = JSScope::resolveWithBase(callFrame, ident, &callFrame->uncheckedR(baseDst));2846 CHECK_FOR_EXCEPTION();2847 callFrame->uncheckedR(propDst) = prop;2848 2849 vPC += OPCODE_LENGTH(op_resolve_with_base);2850 NEXT_INSTRUCTION();2851 }2852 DEFINE_OPCODE(op_resolve_with_this) {2853 /* resolve_with_this thisDst(r) propDst(r) property(id)2854 2855 Searches the scope chain for an object containing2856 identifier property, and if one is found, writes the2857 retrieved property value to register propDst, and the2858 this object to pass in a call to thisDst.2859 2860 If the property is not found, raises an exception.2861 */2862 int thisDst = vPC[1].u.operand;2863 int propDst = vPC[2].u.operand;2864 int property = vPC[3].u.operand;2865 Identifier& ident = codeBlock->identifier(property);2866 2867 JSValue prop = JSScope::resolveWithThis(callFrame, ident, &callFrame->uncheckedR(thisDst));2868 CHECK_FOR_EXCEPTION();2869 callFrame->uncheckedR(propDst) = prop;2870 2871 vPC += OPCODE_LENGTH(op_resolve_with_this);2872 NEXT_INSTRUCTION();2873 }2874 DEFINE_OPCODE(op_get_by_id_out_of_line)2875 DEFINE_OPCODE(op_get_by_id) {2876 /* get_by_id dst(r) base(r) property(id) structure(sID) nop(n) nop(n) nop(n)2877 2878 Generic property access: Gets the property named by identifier2879 property from the value base, and puts the result in register dst.2880 */2881 int dst = vPC[1].u.operand;2882 int base = vPC[2].u.operand;2883 int property = vPC[3].u.operand;2884 2885 Identifier& ident = codeBlock->identifier(property);2886 JSValue baseValue = callFrame->r(base).jsValue();2887 PropertySlot slot(baseValue);2888 JSValue result = baseValue.get(callFrame, ident, slot);2889 CHECK_FOR_EXCEPTION();2890 2891 tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot);2892 2893 callFrame->uncheckedR(dst) = result;2894 vPC += OPCODE_LENGTH(op_get_by_id);2895 NEXT_INSTRUCTION();2896 }2897 DEFINE_OPCODE(op_get_by_id_self) {2898 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)2899 2900 Cached property access: Attempts to get a cached property from the2901 value base. If the cache misses, op_get_by_id_self reverts to2902 op_get_by_id.2903 */2904 int base = vPC[2].u.operand;2905 JSValue baseValue = callFrame->r(base).jsValue();2906 2907 if (LIKELY(baseValue.isCell())) {2908 JSCell* baseCell = baseValue.asCell();2909 Structure* structure = vPC[4].u.structure.get();2910 2911 if (LIKELY(baseCell->structure() == structure)) {2912 ASSERT(baseCell->isObject());2913 JSObject* baseObject = asObject(baseCell);2914 int dst = vPC[1].u.operand;2915 int offset = vPC[5].u.operand;2916 2917 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));2918 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));2919 2920 vPC += OPCODE_LENGTH(op_get_by_id_self);2921 NEXT_INSTRUCTION();2922 }2923 }2924 2925 uncacheGetByID(codeBlock, vPC);2926 NEXT_INSTRUCTION();2927 }2928 DEFINE_OPCODE(op_get_by_id_proto) {2929 /* op_get_by_id_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)2930 2931 Cached property access: Attempts to get a cached property from the2932 value base's prototype. If the cache misses, op_get_by_id_proto2933 reverts to op_get_by_id.2934 */2935 int base = vPC[2].u.operand;2936 JSValue baseValue = callFrame->r(base).jsValue();2937 2938 if (LIKELY(baseValue.isCell())) {2939 JSCell* baseCell = baseValue.asCell();2940 Structure* structure = vPC[4].u.structure.get();2941 2942 if (LIKELY(baseCell->structure() == structure)) {2943 ASSERT(structure->prototypeForLookup(callFrame).isObject());2944 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));2945 Structure* prototypeStructure = vPC[5].u.structure.get();2946 2947 if (LIKELY(protoObject->structure() == prototypeStructure)) {2948 int dst = vPC[1].u.operand;2949 int offset = vPC[6].u.operand;2950 2951 ASSERT(protoObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));2952 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset));2953 callFrame->uncheckedR(dst) = JSValue(protoObject->getDirectOffset(offset));2954 2955 vPC += OPCODE_LENGTH(op_get_by_id_proto);2956 NEXT_INSTRUCTION();2957 }2958 }2959 }2960 2961 uncacheGetByID(codeBlock, vPC);2962 NEXT_INSTRUCTION();2963 }2964 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)2965 goto *(&&skip_id_getter_proto);2966 #endif2967 DEFINE_OPCODE(op_get_by_id_getter_proto) {2968 /* op_get_by_id_getter_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)2969 2970 Cached property access: Attempts to get a cached getter property from the2971 value base's prototype. If the cache misses, op_get_by_id_getter_proto2972 reverts to op_get_by_id.2973 */2974 int base = vPC[2].u.operand;2975 JSValue baseValue = callFrame->r(base).jsValue();2976 2977 if (LIKELY(baseValue.isCell())) {2978 JSCell* baseCell = baseValue.asCell();2979 Structure* structure = vPC[4].u.structure.get();2980 2981 if (LIKELY(baseCell->structure() == structure)) {2982 ASSERT(structure->prototypeForLookup(callFrame).isObject());2983 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));2984 Structure* prototypeStructure = vPC[5].u.structure.get();2985 2986 if (LIKELY(protoObject->structure() == prototypeStructure)) {2987 int dst = vPC[1].u.operand;2988 int offset = vPC[6].u.operand;2989 if (GetterSetter* getterSetter = asGetterSetter(protoObject->getDirectOffset(offset).asCell())) {2990 JSObject* getter = getterSetter->getter();2991 CallData callData;2992 CallType callType = getter->methodTable()->getCallData(getter, callData);2993 JSValue result = call(callFrame, getter, callType, callData, asObject(baseCell), ArgList());2994 CHECK_FOR_EXCEPTION();2995 callFrame->uncheckedR(dst) = result;2996 } else2997 callFrame->uncheckedR(dst) = jsUndefined();2998 vPC += OPCODE_LENGTH(op_get_by_id_getter_proto);2999 NEXT_INSTRUCTION();3000 }3001 }3002 }3003 uncacheGetByID(codeBlock, vPC);3004 NEXT_INSTRUCTION();3005 }3006 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3007 skip_id_getter_proto:3008 #endif3009 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3010 goto *(&&skip_id_custom_proto);3011 #endif3012 DEFINE_OPCODE(op_get_by_id_custom_proto) {3013 /* op_get_by_id_custom_proto dst(r) base(r) property(id) structure(sID) prototypeStructure(sID) offset(n) nop(n)3014 3015 Cached property access: Attempts to use a cached named property getter3016 from the value base's prototype. If the cache misses, op_get_by_id_custom_proto3017 reverts to op_get_by_id.3018 */3019 int base = vPC[2].u.operand;3020 JSValue baseValue = callFrame->r(base).jsValue();3021 3022 if (LIKELY(baseValue.isCell())) {3023 JSCell* baseCell = baseValue.asCell();3024 Structure* structure = vPC[4].u.structure.get();3025 3026 if (LIKELY(baseCell->structure() == structure)) {3027 ASSERT(structure->prototypeForLookup(callFrame).isObject());3028 JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));3029 Structure* prototypeStructure = vPC[5].u.structure.get();3030 3031 if (LIKELY(protoObject->structure() == prototypeStructure)) {3032 int dst = vPC[1].u.operand;3033 int property = vPC[3].u.operand;3034 Identifier& ident = codeBlock->identifier(property);3035 3036 PropertySlot::GetValueFunc getter = vPC[6].u.getterFunc;3037 JSValue result = getter(callFrame, protoObject, ident);3038 CHECK_FOR_EXCEPTION();3039 callFrame->uncheckedR(dst) = result;3040 vPC += OPCODE_LENGTH(op_get_by_id_custom_proto);3041 NEXT_INSTRUCTION();3042 }3043 }3044 }3045 uncacheGetByID(codeBlock, vPC);3046 NEXT_INSTRUCTION();3047 }3048 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3049 skip_id_custom_proto:3050 #endif3051 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3052 goto *(&&skip_get_by_id_chain);3053 #endif3054 DEFINE_OPCODE(op_get_by_id_chain) {3055 /* op_get_by_id_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)3056 3057 Cached property access: Attempts to get a cached property from the3058 value base's prototype chain. If the cache misses, op_get_by_id_chain3059 reverts to op_get_by_id.3060 */3061 int base = vPC[2].u.operand;3062 JSValue baseValue = callFrame->r(base).jsValue();3063 3064 if (LIKELY(baseValue.isCell())) {3065 JSCell* baseCell = baseValue.asCell();3066 Structure* structure = vPC[4].u.structure.get();3067 3068 if (LIKELY(baseCell->structure() == structure)) {3069 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();3070 size_t count = vPC[6].u.operand;3071 WriteBarrier<Structure>* end = it + count;3072 3073 while (true) {3074 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));3075 3076 if (UNLIKELY(baseObject->structure() != (*it).get()))3077 break;3078 3079 if (++it == end) {3080 int dst = vPC[1].u.operand;3081 int offset = vPC[7].u.operand;3082 3083 ASSERT(baseObject->get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));3084 ASSERT(baseValue.get(callFrame, codeBlock->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset));3085 callFrame->uncheckedR(dst) = JSValue(baseObject->getDirectOffset(offset));3086 3087 vPC += OPCODE_LENGTH(op_get_by_id_chain);3088 NEXT_INSTRUCTION();3089 }3090 3091 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.3092 baseCell = baseObject;3093 }3094 }3095 }3096 3097 uncacheGetByID(codeBlock, vPC);3098 NEXT_INSTRUCTION();3099 }3100 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3101 skip_get_by_id_chain:3102 goto *(&&skip_id_getter_self);3103 #endif3104 DEFINE_OPCODE(op_get_by_id_getter_self) {3105 /* op_get_by_id_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)3106 3107 Cached property access: Attempts to get a cached property from the3108 value base. If the cache misses, op_get_by_id_getter_self reverts to3109 op_get_by_id.3110 */3111 int base = vPC[2].u.operand;3112 JSValue baseValue = callFrame->r(base).jsValue();3113 3114 if (LIKELY(baseValue.isCell())) {3115 JSCell* baseCell = baseValue.asCell();3116 Structure* structure = vPC[4].u.structure.get();3117 3118 if (LIKELY(baseCell->structure() == structure)) {3119 ASSERT(baseCell->isObject());3120 JSObject* baseObject = asObject(baseCell);3121 int dst = vPC[1].u.operand;3122 int offset = vPC[5].u.operand;3123 3124 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {3125 JSObject* getter = getterSetter->getter();3126 CallData callData;3127 CallType callType = getter->methodTable()->getCallData(getter, callData);3128 JSValue result = call(callFrame, getter, callType, callData, baseObject, ArgList());3129 CHECK_FOR_EXCEPTION();3130 callFrame->uncheckedR(dst) = result;3131 } else3132 callFrame->uncheckedR(dst) = jsUndefined();3133 3134 vPC += OPCODE_LENGTH(op_get_by_id_getter_self);3135 NEXT_INSTRUCTION();3136 }3137 }3138 uncacheGetByID(codeBlock, vPC);3139 NEXT_INSTRUCTION();3140 }3141 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3142 skip_id_getter_self:3143 #endif3144 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3145 goto *(&&skip_id_custom_self);3146 #endif3147 DEFINE_OPCODE(op_get_by_id_custom_self) {3148 /* op_get_by_id_custom_self dst(r) base(r) property(id) structure(sID) offset(n) nop(n) nop(n)3149 3150 Cached property access: Attempts to use a cached named property getter3151 from the value base. If the cache misses, op_get_by_id_custom_self reverts to3152 op_get_by_id.3153 */3154 int base = vPC[2].u.operand;3155 JSValue baseValue = callFrame->r(base).jsValue();3156 3157 if (LIKELY(baseValue.isCell())) {3158 JSCell* baseCell = baseValue.asCell();3159 Structure* structure = vPC[4].u.structure.get();3160 3161 if (LIKELY(baseCell->structure() == structure)) {3162 ASSERT(baseCell->isObject());3163 int dst = vPC[1].u.operand;3164 int property = vPC[3].u.operand;3165 Identifier& ident = codeBlock->identifier(property);3166 3167 PropertySlot::GetValueFunc getter = vPC[5].u.getterFunc;3168 JSValue result = getter(callFrame, baseValue, ident);3169 CHECK_FOR_EXCEPTION();3170 callFrame->uncheckedR(dst) = result;3171 vPC += OPCODE_LENGTH(op_get_by_id_custom_self);3172 NEXT_INSTRUCTION();3173 }3174 }3175 uncacheGetByID(codeBlock, vPC);3176 NEXT_INSTRUCTION();3177 }3178 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3179 skip_id_custom_self:3180 #endif3181 DEFINE_OPCODE(op_get_by_id_generic) {3182 /* op_get_by_id_generic dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)3183 3184 Generic property access: Gets the property named by identifier3185 property from the value base, and puts the result in register dst.3186 */3187 int dst = vPC[1].u.operand;3188 int base = vPC[2].u.operand;3189 int property = vPC[3].u.operand;3190 3191 Identifier& ident = codeBlock->identifier(property);3192 JSValue baseValue = callFrame->r(base).jsValue();3193 PropertySlot slot(baseValue);3194 JSValue result = baseValue.get(callFrame, ident, slot);3195 CHECK_FOR_EXCEPTION();3196 3197 callFrame->uncheckedR(dst) = result;3198 vPC += OPCODE_LENGTH(op_get_by_id_generic);3199 NEXT_INSTRUCTION();3200 }3201 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3202 goto *(&&skip_id_getter_chain);3203 #endif3204 DEFINE_OPCODE(op_get_by_id_getter_chain) {3205 /* op_get_by_id_getter_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)3206 3207 Cached property access: Attempts to get a cached property from the3208 value base's prototype chain. If the cache misses, op_get_by_id_getter_chain3209 reverts to op_get_by_id.3210 */3211 int base = vPC[2].u.operand;3212 JSValue baseValue = callFrame->r(base).jsValue();3213 3214 if (LIKELY(baseValue.isCell())) {3215 JSCell* baseCell = baseValue.asCell();3216 Structure* structure = vPC[4].u.structure.get();3217 3218 if (LIKELY(baseCell->structure() == structure)) {3219 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();3220 size_t count = vPC[6].u.operand;3221 WriteBarrier<Structure>* end = it + count;3222 3223 while (true) {3224 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));3225 3226 if (UNLIKELY(baseObject->structure() != (*it).get()))3227 break;3228 3229 if (++it == end) {3230 int dst = vPC[1].u.operand;3231 int offset = vPC[7].u.operand;3232 if (GetterSetter* getterSetter = asGetterSetter(baseObject->getDirectOffset(offset).asCell())) {3233 JSObject* getter = getterSetter->getter();3234 CallData callData;3235 CallType callType = getter->methodTable()->getCallData(getter, callData);3236 JSValue result = call(callFrame, getter, callType, callData, baseValue, ArgList());3237 CHECK_FOR_EXCEPTION();3238 callFrame->uncheckedR(dst) = result;3239 } else3240 callFrame->uncheckedR(dst) = jsUndefined();3241 vPC += OPCODE_LENGTH(op_get_by_id_getter_chain);3242 NEXT_INSTRUCTION();3243 }3244 3245 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.3246 baseCell = baseObject;3247 }3248 }3249 }3250 uncacheGetByID(codeBlock, vPC);3251 NEXT_INSTRUCTION();3252 }3253 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3254 skip_id_getter_chain:3255 #endif3256 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3257 goto *(&&skip_id_custom_chain);3258 #endif3259 DEFINE_OPCODE(op_get_by_id_custom_chain) {3260 /* op_get_by_id_custom_chain dst(r) base(r) property(id) structure(sID) structureChain(chain) count(n) offset(n)3261 3262 Cached property access: Attempts to use a cached named property getter on the3263 value base's prototype chain. If the cache misses, op_get_by_id_custom_chain3264 reverts to op_get_by_id.3265 */3266 int base = vPC[2].u.operand;3267 JSValue baseValue = callFrame->r(base).jsValue();3268 3269 if (LIKELY(baseValue.isCell())) {3270 JSCell* baseCell = baseValue.asCell();3271 Structure* structure = vPC[4].u.structure.get();3272 3273 if (LIKELY(baseCell->structure() == structure)) {3274 WriteBarrier<Structure>* it = vPC[5].u.structureChain->head();3275 size_t count = vPC[6].u.operand;3276 WriteBarrier<Structure>* end = it + count;3277 3278 while (true) {3279 JSObject* baseObject = asObject(baseCell->structure()->prototypeForLookup(callFrame));3280 3281 if (UNLIKELY(baseObject->structure() != (*it).get()))3282 break;3283 3284 if (++it == end) {3285 int dst = vPC[1].u.operand;3286 int property = vPC[3].u.operand;3287 Identifier& ident = codeBlock->identifier(property);3288 3289 PropertySlot::GetValueFunc getter = vPC[7].u.getterFunc;3290 JSValue result = getter(callFrame, baseObject, ident);3291 CHECK_FOR_EXCEPTION();3292 callFrame->uncheckedR(dst) = result;3293 vPC += OPCODE_LENGTH(op_get_by_id_custom_chain);3294 NEXT_INSTRUCTION();3295 }3296 3297 // Update baseCell, so that next time around the loop we'll pick up the prototype's prototype.3298 baseCell = baseObject;3299 }3300 }3301 }3302 uncacheGetByID(codeBlock, vPC);3303 NEXT_INSTRUCTION();3304 }3305 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3306 skip_id_custom_chain:3307 goto *(&&skip_get_array_length);3308 #endif3309 DEFINE_OPCODE(op_get_array_length) {3310 /* op_get_array_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)3311 3312 Cached property access: Gets the length of the array in register base,3313 and puts the result in register dst. If register base does not hold3314 an array, op_get_array_length reverts to op_get_by_id.3315 */3316 3317 int base = vPC[2].u.operand;3318 JSValue baseValue = callFrame->r(base).jsValue();3319 if (LIKELY(isJSArray(baseValue))) {3320 int dst = vPC[1].u.operand;3321 callFrame->uncheckedR(dst) = jsNumber(asArray(baseValue)->length());3322 vPC += OPCODE_LENGTH(op_get_array_length);3323 NEXT_INSTRUCTION();3324 }3325 3326 uncacheGetByID(codeBlock, vPC);3327 NEXT_INSTRUCTION();3328 }3329 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3330 skip_get_array_length:3331 goto *(&&skip_get_string_length);3332 #endif3333 DEFINE_OPCODE(op_get_string_length) {3334 /* op_get_string_length dst(r) base(r) property(id) nop(sID) nop(n) nop(n) nop(n)3335 3336 Cached property access: Gets the length of the string in register base,3337 and puts the result in register dst. If register base does not hold3338 a string, op_get_string_length reverts to op_get_by_id.3339 */3340 3341 int base = vPC[2].u.operand;3342 JSValue baseValue = callFrame->r(base).jsValue();3343 if (LIKELY(isJSString(baseValue))) {3344 int dst = vPC[1].u.operand;3345 callFrame->uncheckedR(dst) = jsNumber(asString(baseValue)->length());3346 vPC += OPCODE_LENGTH(op_get_string_length);3347 NEXT_INSTRUCTION();3348 }3349 3350 uncacheGetByID(codeBlock, vPC);3351 NEXT_INSTRUCTION();3352 }3353 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3354 skip_get_string_length:3355 goto *(&&skip_put_by_id);3356 #endif3357 DEFINE_OPCODE(op_put_by_id_out_of_line)3358 DEFINE_OPCODE(op_put_by_id) {3359 /* put_by_id base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)3360 3361 Generic property access: Sets the property named by identifier3362 property, belonging to register base, to register value.3363 3364 Unlike many opcodes, this one does not write any output to3365 the register file.3366 3367 The "direct" flag should only be set this put_by_id is to initialize3368 an object literal.3369 */3370 3371 int base = vPC[1].u.operand;3372 int property = vPC[2].u.operand;3373 int value = vPC[3].u.operand;3374 int direct = vPC[8].u.operand;3375 3376 JSValue baseValue = callFrame->r(base).jsValue();3377 Identifier& ident = codeBlock->identifier(property);3378 PutPropertySlot slot(codeBlock->isStrictMode());3379 if (direct) {3380 ASSERT(baseValue.isObject());3381 asObject(baseValue)->putDirect(*globalData, ident, callFrame->r(value).jsValue(), slot);3382 } else3383 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);3384 CHECK_FOR_EXCEPTION();3385 3386 tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot);3387 3388 vPC += OPCODE_LENGTH(op_put_by_id);3389 NEXT_INSTRUCTION();3390 }3391 #if USE(GCC_COMPUTED_GOTO_WORKAROUND)3392 skip_put_by_id:3393 #endif3394 DEFINE_OPCODE(op_put_by_id_transition_direct)3395 DEFINE_OPCODE(op_put_by_id_transition_normal)3396 DEFINE_OPCODE(op_put_by_id_transition_direct_out_of_line)3397 DEFINE_OPCODE(op_put_by_id_transition_normal_out_of_line)3398 DEFINE_OPCODE(op_put_by_id_transition) {3399 /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b)3400 3401 Cached property access: Attempts to set a new property with a cached transition3402 property named by identifier property, belonging to register base,3403 to register value. If the cache misses, op_put_by_id_transition3404 reverts to op_put_by_id_generic.3405 3406 Unlike many opcodes, this one does not write any output to3407 the register file.3408 */3409 int base = vPC[1].u.operand;3410 JSValue baseValue = callFrame->r(base).jsValue();3411 3412 if (LIKELY(baseValue.isCell())) {3413 JSCell* baseCell = baseValue.asCell();3414 Structure* oldStructure = vPC[4].u.structure.get();3415 Structure* newStructure = vPC[5].u.structure.get();3416 3417 if (LIKELY(baseCell->structure() == oldStructure)) {3418 ASSERT(baseCell->isObject());3419 JSObject* baseObject = asObject(baseCell);3420 int direct = vPC[8].u.operand;3421 3422 if (!direct) {3423 WriteBarrier<Structure>* it = vPC[6].u.structureChain->head();3424 3425 JSValue proto = baseObject->structure()->prototypeForLookup(callFrame);3426 while (!proto.isNull()) {3427 if (UNLIKELY(asObject(proto)->structure() != (*it).get())) {3428 uncachePutByID(codeBlock, vPC);3429 NEXT_INSTRUCTION();3430 }3431 ++it;3432 proto = asObject(proto)->structure()->prototypeForLookup(callFrame);3433 }3434 }3435 baseObject->setStructureAndReallocateStorageIfNecessary(*globalData, newStructure);3436 3437 int value = vPC[3].u.operand;3438 int offset = vPC[7].u.operand;3439 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);3440 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());3441 3442 vPC += OPCODE_LENGTH(op_put_by_id_transition);3443 NEXT_INSTRUCTION();3444 }3445 }3446 3447 uncachePutByID(codeBlock, vPC);3448 NEXT_INSTRUCTION();3449 }3450 DEFINE_OPCODE(op_put_by_id_replace) {3451 /* op_put_by_id_replace base(r) property(id) value(r) structure(sID) offset(n) nop(n) nop(n) direct(b)3452 3453 Cached property access: Attempts to set a pre-existing, cached3454 property named by identifier property, belonging to register base,3455 to register value. If the cache misses, op_put_by_id_replace3456 reverts to op_put_by_id.3457 3458 Unlike many opcodes, this one does not write any output to3459 the register file.3460 */3461 int base = vPC[1].u.operand;3462 JSValue baseValue = callFrame->r(base).jsValue();3463 3464 if (LIKELY(baseValue.isCell())) {3465 JSCell* baseCell = baseValue.asCell();3466 Structure* structure = vPC[4].u.structure.get();3467 3468 if (LIKELY(baseCell->structure() == structure)) {3469 ASSERT(baseCell->isObject());3470 JSObject* baseObject = asObject(baseCell);3471 int value = vPC[3].u.operand;3472 int offset = vPC[5].u.operand;3473 3474 ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(*globalData, codeBlock->identifier(vPC[2].u.operand))) == offset);3475 baseObject->putDirectOffset(callFrame->globalData(), offset, callFrame->r(value).jsValue());3476 3477 vPC += OPCODE_LENGTH(op_put_by_id_replace);3478 NEXT_INSTRUCTION();3479 }3480 }3481 3482 uncachePutByID(codeBlock, vPC);3483 NEXT_INSTRUCTION();3484 }3485 DEFINE_OPCODE(op_put_by_id_generic) {3486 /* op_put_by_id_generic base(r) property(id) value(r) nop(n) nop(n) nop(n) nop(n) direct(b)3487 3488 Generic property access: Sets the property named by identifier3489 property, belonging to register base, to register value.3490 3491 Unlike many opcodes, this one does not write any output to3492 the register file.3493 */3494 int base = vPC[1].u.operand;3495 int property = vPC[2].u.operand;3496 int value = vPC[3].u.operand;3497 int direct = vPC[8].u.operand;3498 3499 JSValue baseValue = callFrame->r(base).jsValue();3500 Identifier& ident = codeBlock->identifier(property);3501 PutPropertySlot slot(codeBlock->isStrictMode());3502 if (direct) {3503 ASSERT(baseValue.isObject());3504 asObject(baseValue)->putDirect(*globalData, ident, callFrame->r(value).jsValue(), slot);3505 } else3506 baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot);3507 CHECK_FOR_EXCEPTION();3508 3509 vPC += OPCODE_LENGTH(op_put_by_id_generic);3510 NEXT_INSTRUCTION();3511 }3512 DEFINE_OPCODE(op_del_by_id) {3513 /* del_by_id dst(r) base(r) property(id)3514 3515 Converts register base to Object, deletes the property3516 named by identifier property from the object, and writes a3517 boolean indicating success (if true) or failure (if false)3518 to register dst.3519 */3520 int dst = vPC[1].u.operand;3521 int base = vPC[2].u.operand;3522 int property = vPC[3].u.operand;3523 3524 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame);3525 Identifier& ident = codeBlock->identifier(property);3526 bool result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, ident);3527 if (!result && codeBlock->isStrictMode()) {3528 exceptionValue = createTypeError(callFrame, "Unable to delete property.");3529 goto vm_throw;3530 }3531 CHECK_FOR_EXCEPTION();3532 callFrame->uncheckedR(dst) = jsBoolean(result);3533 vPC += OPCODE_LENGTH(op_del_by_id);3534 NEXT_INSTRUCTION();3535 }3536 DEFINE_OPCODE(op_get_by_pname) {3537 int dst = vPC[1].u.operand;3538 int base = vPC[2].u.operand;3539 int property = vPC[3].u.operand;3540 int expected = vPC[4].u.operand;3541 int iter = vPC[5].u.operand;3542 int i = vPC[6].u.operand;3543 3544 JSValue baseValue = callFrame->r(base).jsValue();3545 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();3546 JSValue subscript = callFrame->r(property).jsValue();3547 JSValue expectedSubscript = callFrame->r(expected).jsValue();3548 int index = callFrame->r(i).i() - 1;3549 JSValue result;3550 PropertyOffset offset = 0;3551 if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) {3552 callFrame->uncheckedR(dst) = JSValue(asObject(baseValue)->getDirectOffset(offset));3553 vPC += OPCODE_LENGTH(op_get_by_pname);3554 NEXT_INSTRUCTION();3555 }3556 {3557 Identifier propertyName(callFrame, subscript.toString(callFrame)->value(callFrame));3558 result = baseValue.get(callFrame, propertyName);3559 }3560 CHECK_FOR_EXCEPTION();3561 callFrame->uncheckedR(dst) = result;3562 vPC += OPCODE_LENGTH(op_get_by_pname);3563 NEXT_INSTRUCTION();3564 }3565 DEFINE_OPCODE(op_get_arguments_length) {3566 int dst = vPC[1].u.operand;3567 int argumentsRegister = vPC[2].u.operand;3568 int property = vPC[3].u.operand;3569 JSValue arguments = callFrame->r(argumentsRegister).jsValue();3570 if (arguments) {3571 Identifier& ident = codeBlock->identifier(property);3572 PropertySlot slot(arguments);3573 JSValue result = arguments.get(callFrame, ident, slot);3574 CHECK_FOR_EXCEPTION();3575 callFrame->uncheckedR(dst) = result;3576 } else3577 callFrame->uncheckedR(dst) = jsNumber(callFrame->argumentCount());3578 3579 vPC += OPCODE_LENGTH(op_get_arguments_length);3580 NEXT_INSTRUCTION();3581 }3582 DEFINE_OPCODE(op_get_argument_by_val) {3583 int dst = vPC[1].u.operand;3584 int argumentsRegister = vPC[2].u.operand;3585 int property = vPC[3].u.operand;3586 JSValue arguments = callFrame->r(argumentsRegister).jsValue();3587 JSValue subscript = callFrame->r(property).jsValue();3588 if (!arguments && subscript.isUInt32() && subscript.asUInt32() < callFrame->argumentCount()) {3589 callFrame->uncheckedR(dst) = callFrame->argument(subscript.asUInt32());3590 vPC += OPCODE_LENGTH(op_get_argument_by_val);3591 NEXT_INSTRUCTION();3592 }3593 if (!arguments) {3594 Arguments* arguments = Arguments::create(*globalData, callFrame);3595 callFrame->uncheckedR(argumentsRegister) = JSValue(arguments);3596 callFrame->uncheckedR(unmodifiedArgumentsRegister(argumentsRegister)) = JSValue(arguments);3597 }3598 // fallthrough3599 }3600 DEFINE_OPCODE(op_get_by_val) {3601 /* get_by_val dst(r) base(r) property(r)3602 3603 Converts register base to Object, gets the property named3604 by register property from the object, and puts the result3605 in register dst. property is nominally converted to string3606 but numbers are treated more efficiently.3607 */3608 int dst = vPC[1].u.operand;3609 int base = vPC[2].u.operand;3610 int property = vPC[3].u.operand;3611 3612 JSValue baseValue = callFrame->r(base).jsValue();3613 JSValue subscript = callFrame->r(property).jsValue();3614 3615 JSValue result;3616 3617 if (LIKELY(subscript.isUInt32())) {3618 uint32_t i = subscript.asUInt32();3619 if (isJSArray(baseValue)) {3620 JSArray* jsArray = asArray(baseValue);3621 if (jsArray->canGetIndexQuickly(i))3622 result = jsArray->getIndexQuickly(i);3623 else3624 result = jsArray->JSArray::get(callFrame, i);3625 } else if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))3626 result = asString(baseValue)->getIndex(callFrame, i);3627 else3628 result = baseValue.get(callFrame, i);3629 } else if (isName(subscript))3630 result = baseValue.get(callFrame, jsCast<NameInstance*>(subscript.asCell())->privateName());3631 else {3632 Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame));3633 result = baseValue.get(callFrame, property);3634 }3635 3636 CHECK_FOR_EXCEPTION();3637 callFrame->uncheckedR(dst) = result;3638 vPC += OPCODE_LENGTH(op_get_by_val);3639 NEXT_INSTRUCTION();3640 }3641 DEFINE_OPCODE(op_put_by_val) {3642 /* put_by_val base(r) property(r) value(r)3643 3644 Sets register value on register base as the property named3645 by register property. Base is converted to object3646 first. register property is nominally converted to string3647 but numbers are treated more efficiently.3648 3649 Unlike many opcodes, this one does not write any output to3650 the register file.3651 */3652 int base = vPC[1].u.operand;3653 int property = vPC[2].u.operand;3654 int value = vPC[3].u.operand;3655 3656 JSValue baseValue = callFrame->r(base).jsValue();3657 JSValue subscript = callFrame->r(property).jsValue();3658 3659 if (LIKELY(subscript.isUInt32())) {3660 uint32_t i = subscript.asUInt32();3661 if (isJSArray(baseValue)) {3662 JSArray* jsArray = asArray(baseValue);3663 if (jsArray->canSetIndexQuickly(i))3664 jsArray->setIndexQuickly(*globalData, i, callFrame->r(value).jsValue());3665 else3666 jsArray->JSArray::putByIndex(jsArray, callFrame, i, callFrame->r(value).jsValue(), codeBlock->isStrictMode());3667 } else3668 baseValue.putByIndex(callFrame, i, callFrame->r(value).jsValue(), codeBlock->isStrictMode());3669 } else if (isName(subscript)) {3670 PutPropertySlot slot(codeBlock->isStrictMode());3671 baseValue.put(callFrame, jsCast<NameInstance*>(subscript.asCell())->privateName(), callFrame->r(value).jsValue(), slot);3672 } else {3673 Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame));3674 if (!globalData->exception) { // Don't put to an object if toString threw an exception.3675 PutPropertySlot slot(codeBlock->isStrictMode());3676 baseValue.put(callFrame, property, callFrame->r(value).jsValue(), slot);3677 }3678 }3679 3680 CHECK_FOR_EXCEPTION();3681 vPC += OPCODE_LENGTH(op_put_by_val);3682 NEXT_INSTRUCTION();3683 }3684 DEFINE_OPCODE(op_del_by_val) {3685 /* del_by_val dst(r) base(r) property(r)3686 3687 Converts register base to Object, deletes the property3688 named by register property from the object, and writes a3689 boolean indicating success (if true) or failure (if false)3690 to register dst.3691 */3692 int dst = vPC[1].u.operand;3693 int base = vPC[2].u.operand;3694 int property = vPC[3].u.operand;3695 3696 JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw3697 3698 JSValue subscript = callFrame->r(property).jsValue();3699 bool result;3700 uint32_t i;3701 if (subscript.getUInt32(i))3702 result = baseObj->methodTable()->deletePropertyByIndex(baseObj, callFrame, i);3703 else if (isName(subscript))3704 result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, jsCast<NameInstance*>(subscript.asCell())->privateName());3705 else {3706 CHECK_FOR_EXCEPTION();3707 Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame));3708 CHECK_FOR_EXCEPTION();3709 result = baseObj->methodTable()->deleteProperty(baseObj, callFrame, property);3710 }3711 if (!result && codeBlock->isStrictMode()) {3712 exceptionValue = createTypeError(callFrame, "Unable to delete property.");3713 goto vm_throw;3714 }3715 CHECK_FOR_EXCEPTION();3716 callFrame->uncheckedR(dst) = jsBoolean(result);3717 vPC += OPCODE_LENGTH(op_del_by_val);3718 NEXT_INSTRUCTION();3719 }3720 DEFINE_OPCODE(op_put_by_index) {3721 /* put_by_index base(r) property(n) value(r)3722 3723 Sets register value on register base as the property named3724 by the immediate number property. Base is converted to3725 object first.3726 3727 Unlike many opcodes, this one does not write any output to3728 the register file.3729 3730 This opcode is mainly used to initialize array literals.3731 */3732 int base = vPC[1].u.operand;3733 unsigned property = vPC[2].u.operand;3734 int value = vPC[3].u.operand;3735 3736 JSValue arrayValue = callFrame->r(base).jsValue();3737 ASSERT(isJSArray(arrayValue));3738 asArray(arrayValue)->putDirectIndex(callFrame, property, callFrame->r(value).jsValue());3739 3740 vPC += OPCODE_LENGTH(op_put_by_index);3741 NEXT_INSTRUCTION();3742 }3743 DEFINE_OPCODE(op_loop) {3744 /* loop target(offset)3745 3746 Jumps unconditionally to offset target from the current3747 instruction.3748 3749 Additionally this loop instruction may terminate JS execution is3750 the JS timeout is reached.3751 */3752 #if ENABLE(OPCODE_STATS)3753 OpcodeStats::resetLastInstruction();3754 #endif3755 int target = vPC[1].u.operand;3756 CHECK_FOR_TIMEOUT();3757 vPC += target;3758 NEXT_INSTRUCTION();3759 }3760 DEFINE_OPCODE(op_jmp) {3761 /* jmp target(offset)3762 3763 Jumps unconditionally to offset target from the current3764 instruction.3765 */3766 #if ENABLE(OPCODE_STATS)3767 OpcodeStats::resetLastInstruction();3768 #endif3769 int target = vPC[1].u.operand;3770 3771 vPC += target;3772 NEXT_INSTRUCTION();3773 }3774 DEFINE_OPCODE(op_loop_hint) {3775 // This is a no-op unless we intend on doing OSR from the interpreter.3776 vPC += OPCODE_LENGTH(op_loop_hint);3777 NEXT_INSTRUCTION();3778 }3779 DEFINE_OPCODE(op_loop_if_true) {3780 /* loop_if_true cond(r) target(offset)3781 3782 Jumps to offset target from the current instruction, if and3783 only if register cond converts to boolean as true.3784 3785 Additionally this loop instruction may terminate JS execution is3786 the JS timeout is reached.3787 */3788 int cond = vPC[1].u.operand;3789 int target = vPC[2].u.operand;3790 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {3791 vPC += target;3792 CHECK_FOR_TIMEOUT();3793 NEXT_INSTRUCTION();3794 }3795 3796 vPC += OPCODE_LENGTH(op_loop_if_true);3797 NEXT_INSTRUCTION();3798 }3799 DEFINE_OPCODE(op_loop_if_false) {3800 /* loop_if_true cond(r) target(offset)3801 3802 Jumps to offset target from the current instruction, if and3803 only if register cond converts to boolean as false.3804 3805 Additionally this loop instruction may terminate JS execution is3806 the JS timeout is reached.3807 */3808 int cond = vPC[1].u.operand;3809 int target = vPC[2].u.operand;3810 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {3811 vPC += target;3812 CHECK_FOR_TIMEOUT();3813 NEXT_INSTRUCTION();3814 }3815 3816 vPC += OPCODE_LENGTH(op_loop_if_true);3817 NEXT_INSTRUCTION();3818 }3819 DEFINE_OPCODE(op_jtrue) {3820 /* jtrue cond(r) target(offset)3821 3822 Jumps to offset target from the current instruction, if and3823 only if register cond converts to boolean as true.3824 */3825 int cond = vPC[1].u.operand;3826 int target = vPC[2].u.operand;3827 if (callFrame->r(cond).jsValue().toBoolean(callFrame)) {3828 vPC += target;3829 NEXT_INSTRUCTION();3830 }3831 3832 vPC += OPCODE_LENGTH(op_jtrue);3833 NEXT_INSTRUCTION();3834 }3835 DEFINE_OPCODE(op_jfalse) {3836 /* jfalse cond(r) target(offset)3837 3838 Jumps to offset target from the current instruction, if and3839 only if register cond converts to boolean as false.3840 */3841 int cond = vPC[1].u.operand;3842 int target = vPC[2].u.operand;3843 if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) {3844 vPC += target;3845 NEXT_INSTRUCTION();3846 }3847 3848 vPC += OPCODE_LENGTH(op_jfalse);3849 NEXT_INSTRUCTION();3850 }3851 DEFINE_OPCODE(op_jeq_null) {3852 /* jeq_null src(r) target(offset)3853 3854 Jumps to offset target from the current instruction, if and3855 only if register src is null.3856 */3857 int src = vPC[1].u.operand;3858 int target = vPC[2].u.operand;3859 JSValue srcValue = callFrame->r(src).jsValue();3860 3861 if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))) {3862 vPC += target;3863 NEXT_INSTRUCTION();3864 }3865 3866 vPC += OPCODE_LENGTH(op_jeq_null);3867 NEXT_INSTRUCTION();3868 }3869 DEFINE_OPCODE(op_jneq_null) {3870 /* jneq_null src(r) target(offset)3871 3872 Jumps to offset target from the current instruction, if and3873 only if register src is not null.3874 */3875 int src = vPC[1].u.operand;3876 int target = vPC[2].u.operand;3877 JSValue srcValue = callFrame->r(src).jsValue();3878 3879 if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !(srcValue.asCell()->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject())))) {3880 vPC += target;3881 NEXT_INSTRUCTION();3882 }3883 3884 vPC += OPCODE_LENGTH(op_jneq_null);3885 NEXT_INSTRUCTION();3886 }3887 DEFINE_OPCODE(op_jneq_ptr) {3888 /* jneq_ptr src(r) ptr(jsCell) target(offset)3889 3890 Jumps to offset target from the current instruction, if the value r is equal3891 to ptr, using pointer equality.3892 */3893 int src = vPC[1].u.operand;3894 int target = vPC[3].u.operand;3895 JSValue srcValue = callFrame->r(src).jsValue();3896 if (srcValue != vPC[2].u.jsCell.get()) {3897 vPC += target;3898 NEXT_INSTRUCTION();3899 }3900 3901 vPC += OPCODE_LENGTH(op_jneq_ptr);3902 NEXT_INSTRUCTION();3903 }3904 DEFINE_OPCODE(op_loop_if_less) {3905 /* loop_if_less src1(r) src2(r) target(offset)3906 3907 Checks whether register src1 is less than register src2, as3908 with the ECMAScript '<' operator, and then jumps to offset3909 target from the current instruction, if and only if the3910 result of the comparison is true.3911 3912 Additionally this loop instruction may terminate JS execution is3913 the JS timeout is reached.3914 */3915 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();3916 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();3917 int target = vPC[3].u.operand;3918 3919 bool result = jsLess<true>(callFrame, src1, src2);3920 CHECK_FOR_EXCEPTION();3921 3922 if (result) {3923 vPC += target;3924 CHECK_FOR_TIMEOUT();3925 NEXT_INSTRUCTION();3926 }3927 3928 vPC += OPCODE_LENGTH(op_loop_if_less);3929 NEXT_INSTRUCTION();3930 }3931 DEFINE_OPCODE(op_loop_if_lesseq) {3932 /* loop_if_lesseq src1(r) src2(r) target(offset)3933 3934 Checks whether register src1 is less than or equal to register3935 src2, as with the ECMAScript '<=' operator, and then jumps to3936 offset target from the current instruction, if and only if the3937 result of the comparison is true.3938 3939 Additionally this loop instruction may terminate JS execution is3940 the JS timeout is reached.3941 */3942 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();3943 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();3944 int target = vPC[3].u.operand;3945 3946 bool result = jsLessEq<true>(callFrame, src1, src2);3947 CHECK_FOR_EXCEPTION();3948 3949 if (result) {3950 vPC += target;3951 CHECK_FOR_TIMEOUT();3952 NEXT_INSTRUCTION();3953 }3954 3955 vPC += OPCODE_LENGTH(op_loop_if_lesseq);3956 NEXT_INSTRUCTION();3957 }3958 DEFINE_OPCODE(op_loop_if_greater) {3959 /* loop_if_greater src1(r) src2(r) target(offset)3960 3961 Checks whether register src1 is greater than register src2, as3962 with the ECMAScript '>' operator, and then jumps to offset3963 target from the current instruction, if and only if the3964 result of the comparison is true.3965 3966 Additionally this loop instruction may terminate JS execution is3967 the JS timeout is reached.3968 */3969 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();3970 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();3971 int target = vPC[3].u.operand;3972 3973 bool result = jsLess<false>(callFrame, src2, src1);3974 CHECK_FOR_EXCEPTION();3975 3976 if (result) {3977 vPC += target;3978 CHECK_FOR_TIMEOUT();3979 NEXT_INSTRUCTION();3980 }3981 3982 vPC += OPCODE_LENGTH(op_loop_if_greater);3983 NEXT_INSTRUCTION();3984 }3985 DEFINE_OPCODE(op_loop_if_greatereq) {3986 /* loop_if_greatereq src1(r) src2(r) target(offset)3987 3988 Checks whether register src1 is greater than or equal to register3989 src2, as with the ECMAScript '>=' operator, and then jumps to3990 offset target from the current instruction, if and only if the3991 result of the comparison is true.3992 3993 Additionally this loop instruction may terminate JS execution is3994 the JS timeout is reached.3995 */3996 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();3997 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();3998 int target = vPC[3].u.operand;3999 4000 bool result = jsLessEq<false>(callFrame, src2, src1);4001 CHECK_FOR_EXCEPTION();4002 4003 if (result) {4004 vPC += target;4005 CHECK_FOR_TIMEOUT();4006 NEXT_INSTRUCTION();4007 }4008 4009 vPC += OPCODE_LENGTH(op_loop_if_greatereq);4010 NEXT_INSTRUCTION();4011 }4012 DEFINE_OPCODE(op_jless) {4013 /* jless src1(r) src2(r) target(offset)4014 4015 Checks whether register src1 is less than register src2, as4016 with the ECMAScript '<' operator, and then jumps to offset4017 target from the current instruction, if and only if the4018 result of the comparison is true.4019 */4020 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4021 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4022 int target = vPC[3].u.operand;4023 4024 bool result = jsLess<true>(callFrame, src1, src2);4025 CHECK_FOR_EXCEPTION();4026 4027 if (result) {4028 vPC += target;4029 NEXT_INSTRUCTION();4030 }4031 4032 vPC += OPCODE_LENGTH(op_jless);4033 NEXT_INSTRUCTION();4034 }4035 DEFINE_OPCODE(op_jlesseq) {4036 /* jlesseq src1(r) src2(r) target(offset)4037 4038 Checks whether register src1 is less than or equal to4039 register src2, as with the ECMAScript '<=' operator,4040 and then jumps to offset target from the current instruction,4041 if and only if the result of the comparison is true.4042 */4043 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4044 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4045 int target = vPC[3].u.operand;4046 4047 bool result = jsLessEq<true>(callFrame, src1, src2);4048 CHECK_FOR_EXCEPTION();4049 4050 if (result) {4051 vPC += target;4052 NEXT_INSTRUCTION();4053 }4054 4055 vPC += OPCODE_LENGTH(op_jlesseq);4056 NEXT_INSTRUCTION();4057 }4058 DEFINE_OPCODE(op_jgreater) {4059 /* jgreater src1(r) src2(r) target(offset)4060 4061 Checks whether register src1 is greater than register src2, as4062 with the ECMAScript '>' operator, and then jumps to offset4063 target from the current instruction, if and only if the4064 result of the comparison is true.4065 */4066 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4067 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4068 int target = vPC[3].u.operand;4069 4070 bool result = jsLess<false>(callFrame, src2, src1);4071 CHECK_FOR_EXCEPTION();4072 4073 if (result) {4074 vPC += target;4075 NEXT_INSTRUCTION();4076 }4077 4078 vPC += OPCODE_LENGTH(op_jgreater);4079 NEXT_INSTRUCTION();4080 }4081 DEFINE_OPCODE(op_jgreatereq) {4082 /* jgreatereq src1(r) src2(r) target(offset)4083 4084 Checks whether register src1 is greater than or equal to4085 register src2, as with the ECMAScript '>=' operator,4086 and then jumps to offset target from the current instruction,4087 if and only if the result of the comparison is true.4088 */4089 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4090 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4091 int target = vPC[3].u.operand;4092 4093 bool result = jsLessEq<false>(callFrame, src2, src1);4094 CHECK_FOR_EXCEPTION();4095 4096 if (result) {4097 vPC += target;4098 NEXT_INSTRUCTION();4099 }4100 4101 vPC += OPCODE_LENGTH(op_jgreatereq);4102 NEXT_INSTRUCTION();4103 }4104 DEFINE_OPCODE(op_jnless) {4105 /* jnless src1(r) src2(r) target(offset)4106 4107 Checks whether register src1 is less than register src2, as4108 with the ECMAScript '<' operator, and then jumps to offset4109 target from the current instruction, if and only if the4110 result of the comparison is false.4111 */4112 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4113 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4114 int target = vPC[3].u.operand;4115 4116 bool result = jsLess<true>(callFrame, src1, src2);4117 CHECK_FOR_EXCEPTION();4118 4119 if (!result) {4120 vPC += target;4121 NEXT_INSTRUCTION();4122 }4123 4124 vPC += OPCODE_LENGTH(op_jnless);4125 NEXT_INSTRUCTION();4126 }4127 DEFINE_OPCODE(op_jnlesseq) {4128 /* jnlesseq src1(r) src2(r) target(offset)4129 4130 Checks whether register src1 is less than or equal to4131 register src2, as with the ECMAScript '<=' operator,4132 and then jumps to offset target from the current instruction,4133 if and only if theresult of the comparison is false.4134 */4135 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4136 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4137 int target = vPC[3].u.operand;4138 4139 bool result = jsLessEq<true>(callFrame, src1, src2);4140 CHECK_FOR_EXCEPTION();4141 4142 if (!result) {4143 vPC += target;4144 NEXT_INSTRUCTION();4145 }4146 4147 vPC += OPCODE_LENGTH(op_jnlesseq);4148 NEXT_INSTRUCTION();4149 }4150 DEFINE_OPCODE(op_jngreater) {4151 /* jngreater src1(r) src2(r) target(offset)4152 4153 Checks whether register src1 is greater than register src2, as4154 with the ECMAScript '>' operator, and then jumps to offset4155 target from the current instruction, if and only if the4156 result of the comparison is false.4157 */4158 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4159 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4160 int target = vPC[3].u.operand;4161 4162 bool result = jsLess<false>(callFrame, src2, src1);4163 CHECK_FOR_EXCEPTION();4164 4165 if (!result) {4166 vPC += target;4167 NEXT_INSTRUCTION();4168 }4169 4170 vPC += OPCODE_LENGTH(op_jngreater);4171 NEXT_INSTRUCTION();4172 }4173 DEFINE_OPCODE(op_jngreatereq) {4174 /* jngreatereq src1(r) src2(r) target(offset)4175 4176 Checks whether register src1 is greater than or equal to4177 register src2, as with the ECMAScript '>=' operator,4178 and then jumps to offset target from the current instruction,4179 if and only if theresult of the comparison is false.4180 */4181 JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue();4182 JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue();4183 int target = vPC[3].u.operand;4184 4185 bool result = jsLessEq<false>(callFrame, src2, src1);4186 CHECK_FOR_EXCEPTION();4187 4188 if (!result) {4189 vPC += target;4190 NEXT_INSTRUCTION();4191 }4192 4193 vPC += OPCODE_LENGTH(op_jngreatereq);4194 NEXT_INSTRUCTION();4195 }4196 DEFINE_OPCODE(op_switch_imm) {4197 /* switch_imm tableIndex(n) defaultOffset(offset) scrutinee(r)4198 4199 Performs a range checked switch on the scrutinee value, using4200 the tableIndex-th immediate switch jump table. If the scrutinee value4201 is an immediate number in the range covered by the referenced jump4202 table, and the value at jumpTable[scrutinee value] is non-zero, then4203 that value is used as the jump offset, otherwise defaultOffset is used.4204 */4205 int tableIndex = vPC[1].u.operand;4206 int defaultOffset = vPC[2].u.operand;4207 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();4208 if (scrutinee.isInt32())4209 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset);4210 else if (scrutinee.isDouble() && scrutinee.asDouble() == static_cast<int32_t>(scrutinee.asDouble()))4211 vPC += codeBlock->immediateSwitchJumpTable(tableIndex).offsetForValue(static_cast<int32_t>(scrutinee.asDouble()), defaultOffset);4212 else4213 vPC += defaultOffset;4214 NEXT_INSTRUCTION();4215 }4216 DEFINE_OPCODE(op_switch_char) {4217 /* switch_char tableIndex(n) defaultOffset(offset) scrutinee(r)4218 4219 Performs a range checked switch on the scrutinee value, using4220 the tableIndex-th character switch jump table. If the scrutinee value4221 is a single character string in the range covered by the referenced jump4222 table, and the value at jumpTable[scrutinee value] is non-zero, then4223 that value is used as the jump offset, otherwise defaultOffset is used.4224 */4225 int tableIndex = vPC[1].u.operand;4226 int defaultOffset = vPC[2].u.operand;4227 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();4228 if (!scrutinee.isString())4229 vPC += defaultOffset;4230 else {4231 StringImpl* value = asString(scrutinee)->value(callFrame).impl();4232 if (value->length() != 1)4233 vPC += defaultOffset;4234 else4235 vPC += codeBlock->characterSwitchJumpTable(tableIndex).offsetForValue((*value)[0], defaultOffset);4236 }4237 NEXT_INSTRUCTION();4238 }4239 DEFINE_OPCODE(op_switch_string) {4240 /* switch_string tableIndex(n) defaultOffset(offset) scrutinee(r)4241 4242 Performs a sparse hashmap based switch on the value in the scrutinee4243 register, using the tableIndex-th string switch jump table. If the4244 scrutinee value is a string that exists as a key in the referenced4245 jump table, then the value associated with the string is used as the4246 jump offset, otherwise defaultOffset is used.4247 */4248 int tableIndex = vPC[1].u.operand;4249 int defaultOffset = vPC[2].u.operand;4250 JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue();4251 if (!scrutinee.isString())4252 vPC += defaultOffset;4253 else4254 vPC += codeBlock->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).impl(), defaultOffset);4255 NEXT_INSTRUCTION();4256 }4257 DEFINE_OPCODE(op_new_func) {4258 /* new_func dst(r) func(f)4259 4260 Constructs a new Function instance from function func and4261 the current scope chain using the original Function4262 constructor, using the rules for function declarations, and4263 puts the result in register dst.4264 */4265 int dst = vPC[1].u.operand;4266 int func = vPC[2].u.operand;4267 int shouldCheck = vPC[3].u.operand;4268 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());4269 if (!shouldCheck || !callFrame->r(dst).jsValue())4270 callFrame->uncheckedR(dst) = JSValue(JSFunction::create(callFrame, codeBlock->functionDecl(func), callFrame->scope()));4271 4272 vPC += OPCODE_LENGTH(op_new_func);4273 NEXT_INSTRUCTION();4274 }4275 DEFINE_OPCODE(op_new_func_exp) {4276 /* new_func_exp dst(r) func(f)4277 4278 Constructs a new Function instance from function func and4279 the current scope chain using the original Function4280 constructor, using the rules for function expressions, and4281 puts the result in register dst.4282 */4283 int dst = vPC[1].u.operand;4284 int funcIndex = vPC[2].u.operand;4285 4286 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());4287 FunctionExecutable* function = codeBlock->functionExpr(funcIndex);4288 JSFunction* func = JSFunction::create(callFrame, function, callFrame->scope());4289 4290 callFrame->uncheckedR(dst) = JSValue(func);4291 4292 vPC += OPCODE_LENGTH(op_new_func_exp);4293 NEXT_INSTRUCTION();4294 }4295 DEFINE_OPCODE(op_call_eval) {4296 /* call_eval func(r) argCount(n) registerOffset(n)4297 4298 Call a function named "eval" with no explicit "this" value4299 (which may therefore be the eval operator). If register4300 thisVal is the global object, and register func contains4301 that global object's original global eval function, then4302 perform the eval operator in local scope (interpreting4303 the argument registers as for the "call"4304 opcode). Otherwise, act exactly as the "call" opcode would.4305 */4306 4307 int func = vPC[1].u.operand;4308 int argCount = vPC[2].u.operand;4309 int registerOffset = vPC[3].u.operand;4310 4311 ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());4312 JSValue funcVal = callFrame->r(func).jsValue();4313 4314 if (isHostFunction(funcVal, globalFuncEval)) {4315 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);4316 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_eval), callFrame->scope(), callFrame, argCount, jsCast<JSFunction*>(funcVal));4317 4318 JSValue result = eval(newCallFrame);4319 if ((exceptionValue = globalData->exception))4320 goto vm_throw;4321 functionReturnValue = result;4322 4323 vPC += OPCODE_LENGTH(op_call_eval);4324 NEXT_INSTRUCTION();4325 }4326 4327 // We didn't find the blessed version of eval, so process this4328 // instruction as a normal function call.4329 // fall through to op_call4330 }4331 DEFINE_OPCODE(op_call) {4332 /* call func(r) argCount(n) registerOffset(n)4333 4334 Perform a function call.4335 4336 registerOffset is the distance the callFrame pointer should move4337 before the VM initializes the new call frame's header.4338 4339 dst is where op_ret should store its result.4340 */4341 4342 int func = vPC[1].u.operand;4343 int argCount = vPC[2].u.operand;4344 int registerOffset = vPC[3].u.operand;4345 4346 JSValue v = callFrame->r(func).jsValue();4347 4348 CallData callData;4349 CallType callType = getCallData(v, callData);4350 4351 if (callType == CallTypeJS) {4352 JSScope* callDataScope = callData.js.scope;4353 4354 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScope);4355 if (UNLIKELY(!!error)) {4356 exceptionValue = error;4357 goto vm_throw;4358 }4359 4360 CallFrame* previousCallFrame = callFrame;4361 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();4362 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);4363 if (UNLIKELY(!callFrame)) {4364 callFrame = previousCallFrame;4365 exceptionValue = createStackOverflowError(callFrame);4366 goto vm_throw;4367 }4368 4369 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call), callDataScope, previousCallFrame, argCount, jsCast<JSFunction*>(v));4370 codeBlock = newCodeBlock;4371 ASSERT(codeBlock == callFrame->codeBlock());4372 *topCallFrameSlot = callFrame;4373 vPC = newCodeBlock->instructions().begin();4374 4375 #if ENABLE(OPCODE_STATS)4376 OpcodeStats::resetLastInstruction();4377 #endif4378 4379 NEXT_INSTRUCTION();4380 }4381 4382 if (callType == CallTypeHost) {4383 JSScope* scope = callFrame->scope();4384 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);4385 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call), scope, callFrame, argCount, asObject(v));4386 JSValue returnValue;4387 {4388 *topCallFrameSlot = newCallFrame;4389 SamplingTool::HostCallRecord callRecord(m_sampler.get());4390 returnValue = JSValue::decode(callData.native.function(newCallFrame));4391 *topCallFrameSlot = callFrame;4392 }4393 CHECK_FOR_EXCEPTION();4394 4395 functionReturnValue = returnValue;4396 4397 vPC += OPCODE_LENGTH(op_call);4398 NEXT_INSTRUCTION();4399 }4400 4401 ASSERT(callType == CallTypeNone);4402 4403 exceptionValue = createNotAFunctionError(callFrame, v);4404 goto vm_throw;4405 }4406 DEFINE_OPCODE(op_call_varargs) {4407 /* call_varargs callee(r) thisValue(r) arguments(r) firstFreeRegister(n)4408 4409 Perform a function call with a dynamic set of arguments.4410 4411 registerOffset is the distance the callFrame pointer should move4412 before the VM initializes the new call frame's header, excluding4413 space for arguments.4414 4415 dst is where op_ret should store its result.4416 */4417 4418 JSValue v = callFrame->r(vPC[1].u.operand).jsValue();4419 JSValue thisValue = callFrame->r(vPC[2].u.operand).jsValue();4420 JSValue arguments = callFrame->r(vPC[3].u.operand).jsValue();4421 int firstFreeRegister = vPC[4].u.operand;4422 4423 CallFrame* newCallFrame = loadVarargs(callFrame, registerFile, thisValue, arguments, firstFreeRegister);4424 if ((exceptionValue = globalData->exception))4425 goto vm_throw;4426 int argCount = newCallFrame->argumentCountIncludingThis();4427 4428 CallData callData;4429 CallType callType = getCallData(v, callData);4430 4431 if (callType == CallTypeJS) {4432 JSScope* callDataScope = callData.js.scope;4433 4434 JSObject* error = callData.js.functionExecutable->compileForCall(callFrame, callDataScope);4435 if (UNLIKELY(!!error)) {4436 exceptionValue = error;4437 goto vm_throw;4438 }4439 4440 CodeBlock* newCodeBlock = &callData.js.functionExecutable->generatedBytecodeForCall();4441 newCallFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, newCallFrame, 0, argCount);4442 if (UNLIKELY(!newCallFrame)) {4443 exceptionValue = createStackOverflowError(callFrame);4444 goto vm_throw;4445 }4446 4447 newCallFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_call_varargs), callDataScope, callFrame, argCount, jsCast<JSFunction*>(v));4448 codeBlock = newCodeBlock;4449 callFrame = newCallFrame;4450 ASSERT(codeBlock == callFrame->codeBlock());4451 *topCallFrameSlot = callFrame;4452 vPC = newCodeBlock->instructions().begin();4453 4454 #if ENABLE(OPCODE_STATS)4455 OpcodeStats::resetLastInstruction();4456 #endif4457 4458 NEXT_INSTRUCTION();4459 }4460 4461 if (callType == CallTypeHost) {4462 JSScope* scope = callFrame->scope();4463 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_call_varargs), scope, callFrame, argCount, asObject(v));4464 4465 JSValue returnValue;4466 {4467 *topCallFrameSlot = newCallFrame;4468 SamplingTool::HostCallRecord callRecord(m_sampler.get());4469 returnValue = JSValue::decode(callData.native.function(newCallFrame));4470 *topCallFrameSlot = callFrame;4471 }4472 CHECK_FOR_EXCEPTION();4473 4474 functionReturnValue = returnValue;4475 4476 vPC += OPCODE_LENGTH(op_call_varargs);4477 NEXT_INSTRUCTION();4478 }4479 4480 ASSERT(callType == CallTypeNone);4481 4482 exceptionValue = createNotAFunctionError(callFrame, v);4483 goto vm_throw;4484 }4485 DEFINE_OPCODE(op_tear_off_activation) {4486 /* tear_off_activation activation(r)4487 4488 Copy locals and named parameters from the register file to the heap.4489 Point the bindings in 'activation' to this new backing store.4490 4491 This opcode appears before op_ret in functions that require full scope chains.4492 */4493 4494 int activation = vPC[1].u.operand;4495 ASSERT(codeBlock->needsFullScopeChain());4496 JSValue activationValue = callFrame->r(activation).jsValue();4497 if (activationValue)4498 asActivation(activationValue)->tearOff(*globalData);4499 4500 vPC += OPCODE_LENGTH(op_tear_off_activation);4501 NEXT_INSTRUCTION();4502 }4503 DEFINE_OPCODE(op_tear_off_arguments) {4504 /* tear_off_arguments arguments(r) activation(r)4505 4506 Copy named parameters from the register file to the heap. Point the4507 bindings in 'arguments' to this new backing store. (If 'activation'4508 was also copied to the heap, 'arguments' will point to its storage.)4509 4510 This opcode appears before op_ret in functions that don't require full4511 scope chains, but do use 'arguments'.4512 */4513 4514 int arguments = vPC[1].u.operand;4515 int activation = vPC[2].u.operand;4516 ASSERT(codeBlock->usesArguments());4517 if (JSValue argumentsValue = callFrame->r(unmodifiedArgumentsRegister(arguments)).jsValue()) {4518 if (JSValue activationValue = callFrame->r(activation).jsValue())4519 asArguments(argumentsValue)->didTearOffActivation(callFrame, asActivation(activationValue));4520 else4521 asArguments(argumentsValue)->tearOff(callFrame);4522 }4523 4524 vPC += OPCODE_LENGTH(op_tear_off_arguments);4525 NEXT_INSTRUCTION();4526 }4527 DEFINE_OPCODE(op_ret) {4528 /* ret result(r)4529 4530 Return register result as the return value of the current4531 function call, writing it into functionReturnValue.4532 In addition, unwind one call frame and restore the scope4533 chain, code block instruction pointer and register base4534 to those of the calling function.4535 */4536 4537 int result = vPC[1].u.operand;4538 4539 JSValue returnValue = callFrame->r(result).jsValue();4540 4541 vPC = callFrame->returnVPC();4542 callFrame = callFrame->callerFrame();4543 4544 if (callFrame->hasHostCallFrameFlag())4545 return returnValue;4546 4547 *topCallFrameSlot = callFrame;4548 functionReturnValue = returnValue;4549 codeBlock = callFrame->codeBlock();4550 ASSERT(codeBlock == callFrame->codeBlock());4551 4552 NEXT_INSTRUCTION();4553 }4554 DEFINE_OPCODE(op_call_put_result) {4555 /* op_call_put_result result(r)4556 4557 Move call result from functionReturnValue to caller's4558 expected return value register.4559 */4560 4561 callFrame->uncheckedR(vPC[1].u.operand) = functionReturnValue;4562 4563 vPC += OPCODE_LENGTH(op_call_put_result);4564 NEXT_INSTRUCTION();4565 }4566 DEFINE_OPCODE(op_ret_object_or_this) {4567 /* ret result(r)4568 4569 Return register result as the return value of the current4570 function call, writing it into the caller's expected return4571 value register. In addition, unwind one call frame and4572 restore the scope chain, code block instruction pointer and4573 register base to those of the calling function.4574 */4575 4576 int result = vPC[1].u.operand;4577 4578 JSValue returnValue = callFrame->r(result).jsValue();4579 4580 if (UNLIKELY(!returnValue.isObject()))4581 returnValue = callFrame->r(vPC[2].u.operand).jsValue();4582 4583 vPC = callFrame->returnVPC();4584 callFrame = callFrame->callerFrame();4585 4586 if (callFrame->hasHostCallFrameFlag())4587 return returnValue;4588 4589 *topCallFrameSlot = callFrame;4590 functionReturnValue = returnValue;4591 codeBlock = callFrame->codeBlock();4592 ASSERT(codeBlock == callFrame->codeBlock());4593 4594 NEXT_INSTRUCTION();4595 }4596 DEFINE_OPCODE(op_enter) {4597 /* enter4598 4599 Initializes local variables to undefined. If the code block requires4600 an activation, enter_with_activation is used instead.4601 4602 This opcode appears only at the beginning of a code block.4603 */4604 4605 size_t i = 0;4606 for (size_t count = codeBlock->m_numVars; i < count; ++i)4607 callFrame->uncheckedR(i) = jsUndefined();4608 4609 vPC += OPCODE_LENGTH(op_enter);4610 NEXT_INSTRUCTION();4611 }4612 DEFINE_OPCODE(op_create_activation) {4613 /* create_activation dst(r)4614 4615 If the activation object for this callframe has not yet been created,4616 this creates it and writes it back to dst.4617 */4618 4619 int activationReg = vPC[1].u.operand;4620 if (!callFrame->r(activationReg).jsValue()) {4621 JSActivation* activation = JSActivation::create(*globalData, callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable()));4622 callFrame->r(activationReg) = JSValue(activation);4623 callFrame->setScope(activation);4624 }4625 vPC += OPCODE_LENGTH(op_create_activation);4626 NEXT_INSTRUCTION();4627 }4628 DEFINE_OPCODE(op_create_this) {4629 /* op_create_this this(r) proto(r)4630 4631 Allocate an object as 'this', fr use in construction.4632 4633 This opcode should only be used at the beginning of a code4634 block.4635 */4636 4637 int thisRegister = vPC[1].u.operand;4638 4639 JSFunction* constructor = jsCast<JSFunction*>(callFrame->callee());4640 #if !ASSERT_DISABLED4641 ConstructData constructData;4642 ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);4643 #endif4644 4645 Structure* structure = constructor->cachedInheritorID(callFrame);4646 callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);4647 4648 vPC += OPCODE_LENGTH(op_create_this);4649 NEXT_INSTRUCTION();4650 }4651 DEFINE_OPCODE(op_convert_this) {4652 /* convert_this this(r)4653 4654 Takes the value in the 'this' register, converts it to a4655 value that is suitable for use as the 'this' value, and4656 stores it in the 'this' register. This opcode is emitted4657 to avoid doing the conversion in the caller unnecessarily.4658 4659 This opcode should only be used at the beginning of a code4660 block.4661 */4662 4663 int thisRegister = vPC[1].u.operand;4664 JSValue thisVal = callFrame->r(thisRegister).jsValue();4665 if (thisVal.isPrimitive())4666 callFrame->uncheckedR(thisRegister) = JSValue(thisVal.toThisObject(callFrame));4667 4668 vPC += OPCODE_LENGTH(op_convert_this);4669 NEXT_INSTRUCTION();4670 }4671 DEFINE_OPCODE(op_init_lazy_reg) {4672 /* init_lazy_reg dst(r)4673 4674 Initialises dst(r) to JSValue().4675 4676 This opcode appears only at the beginning of a code block.4677 */4678 int dst = vPC[1].u.operand;4679 4680 callFrame->uncheckedR(dst) = JSValue();4681 vPC += OPCODE_LENGTH(op_init_lazy_reg);4682 NEXT_INSTRUCTION();4683 }4684 DEFINE_OPCODE(op_create_arguments) {4685 /* create_arguments dst(r)4686 4687 Creates the 'arguments' object and places it in both the4688 'arguments' call frame slot and the local 'arguments'4689 register, if it has not already been initialised.4690 */4691 4692 int dst = vPC[1].u.operand;4693 4694 if (!callFrame->r(dst).jsValue()) {4695 Arguments* arguments = Arguments::create(*globalData, callFrame);4696 callFrame->uncheckedR(dst) = JSValue(arguments);4697 callFrame->uncheckedR(unmodifiedArgumentsRegister(dst)) = JSValue(arguments);4698 }4699 vPC += OPCODE_LENGTH(op_create_arguments);4700 NEXT_INSTRUCTION();4701 }4702 DEFINE_OPCODE(op_construct) {4703 /* construct func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r)4704 4705 Invoke register "func" as a constructor. For JS4706 functions, the calling convention is exactly as for the4707 "call" opcode, except that the "this" value is a newly4708 created Object. For native constructors, no "this"4709 value is passed. In either case, the argCount and registerOffset4710 registers are interpreted as for the "call" opcode.4711 4712 Register proto must contain the prototype property of4713 register func. This is to enable polymorphic inline4714 caching of this lookup.4715 */4716 4717 int func = vPC[1].u.operand;4718 int argCount = vPC[2].u.operand;4719 int registerOffset = vPC[3].u.operand;4720 4721 JSValue v = callFrame->r(func).jsValue();4722 4723 ConstructData constructData;4724 ConstructType constructType = getConstructData(v, constructData);4725 4726 if (constructType == ConstructTypeJS) {4727 JSScope* callDataScope = constructData.js.scope;4728 4729 JSObject* error = constructData.js.functionExecutable->compileForConstruct(callFrame, callDataScope);4730 if (UNLIKELY(!!error)) {4731 exceptionValue = error;4732 goto vm_throw;4733 }4734 4735 CallFrame* previousCallFrame = callFrame;4736 CodeBlock* newCodeBlock = &constructData.js.functionExecutable->generatedBytecodeForConstruct();4737 callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount);4738 if (UNLIKELY(!callFrame)) {4739 callFrame = previousCallFrame;4740 exceptionValue = createStackOverflowError(callFrame);4741 goto vm_throw;4742 }4743 4744 callFrame->init(newCodeBlock, vPC + OPCODE_LENGTH(op_construct), callDataScope, previousCallFrame, argCount, jsCast<JSFunction*>(v));4745 codeBlock = newCodeBlock;4746 *topCallFrameSlot = callFrame;4747 vPC = newCodeBlock->instructions().begin();4748 #if ENABLE(OPCODE_STATS)4749 OpcodeStats::resetLastInstruction();4750 #endif4751 4752 NEXT_INSTRUCTION();4753 }4754 4755 if (constructType == ConstructTypeHost) {4756 JSScope* scope = callFrame->scope();4757 CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset);4758 newCallFrame->init(0, vPC + OPCODE_LENGTH(op_construct), scope, callFrame, argCount, asObject(v));4759 4760 JSValue returnValue;4761 {4762 *topCallFrameSlot = newCallFrame;4763 SamplingTool::HostCallRecord callRecord(m_sampler.get());4764 returnValue = JSValue::decode(constructData.native.function(newCallFrame));4765 *topCallFrameSlot = callFrame;4766 }4767 CHECK_FOR_EXCEPTION();4768 functionReturnValue = returnValue;4769 4770 vPC += OPCODE_LENGTH(op_construct);4771 NEXT_INSTRUCTION();4772 }4773 4774 ASSERT(constructType == ConstructTypeNone);4775 4776 exceptionValue = createNotAConstructorError(callFrame, v);4777 goto vm_throw;4778 }4779 DEFINE_OPCODE(op_strcat) {4780 /* strcat dst(r) src(r) count(n)4781 4782 Construct a new String instance using the original4783 constructor, and puts the result in register dst.4784 The string will be the result of concatenating count4785 strings with values taken from registers starting at4786 register src.4787 */4788 int dst = vPC[1].u.operand;4789 int src = vPC[2].u.operand;4790 int count = vPC[3].u.operand;4791 4792 callFrame->uncheckedR(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count);4793 CHECK_FOR_EXCEPTION();4794 vPC += OPCODE_LENGTH(op_strcat);4795 4796 NEXT_INSTRUCTION();4797 }4798 DEFINE_OPCODE(op_to_primitive) {4799 int dst = vPC[1].u.operand;4800 int src = vPC[2].u.operand;4801 4802 callFrame->uncheckedR(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame);4803 vPC += OPCODE_LENGTH(op_to_primitive);4804 4805 NEXT_INSTRUCTION();4806 }4807 DEFINE_OPCODE(op_push_with_scope) {4808 /* push_with_scope scope(r)4809 4810 Converts register scope to object, and pushes it onto the top4811 of the scope chain.4812 */4813 int scope = vPC[1].u.operand;4814 JSValue v = callFrame->r(scope).jsValue();4815 JSObject* o = v.toObject(callFrame);4816 CHECK_FOR_EXCEPTION();4817 4818 callFrame->setScope(JSWithScope::create(callFrame, o));4819 4820 vPC += OPCODE_LENGTH(op_push_with_scope);4821 NEXT_INSTRUCTION();4822 }4823 DEFINE_OPCODE(op_pop_scope) {4824 /* pop_scope4825 4826 Removes the top item from the current scope chain.4827 */4828 callFrame->setScope(callFrame->scope()->next());4829 4830 vPC += OPCODE_LENGTH(op_pop_scope);4831 NEXT_INSTRUCTION();4832 }4833 DEFINE_OPCODE(op_get_pnames) {4834 /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset)4835 4836 Creates a property name list for register base and puts it4837 in register dst, initializing i and size for iteration. If4838 base is undefined or null, jumps to breakTarget.4839 */4840 int dst = vPC[1].u.operand;4841 int base = vPC[2].u.operand;4842 int i = vPC[3].u.operand;4843 int size = vPC[4].u.operand;4844 int breakTarget = vPC[5].u.operand;4845 4846 JSValue v = callFrame->r(base).jsValue();4847 if (v.isUndefinedOrNull()) {4848 vPC += breakTarget;4849 NEXT_INSTRUCTION();4850 }4851 4852 JSObject* o = v.toObject(callFrame);4853 Structure* structure = o->structure();4854 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();4855 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))4856 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);4857 4858 callFrame->uncheckedR(dst) = jsPropertyNameIterator;4859 callFrame->uncheckedR(base) = JSValue(o);4860 callFrame->uncheckedR(i) = Register::withInt(0);4861 callFrame->uncheckedR(size) = Register::withInt(jsPropertyNameIterator->size());4862 vPC += OPCODE_LENGTH(op_get_pnames);4863 NEXT_INSTRUCTION();4864 }4865 DEFINE_OPCODE(op_next_pname) {4866 /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset)4867 4868 Copies the next name from the property name list in4869 register iter to dst, then jumps to offset target. If there are no4870 names left, invalidates the iterator and continues to the next4871 instruction.4872 */4873 int dst = vPC[1].u.operand;4874 int base = vPC[2].u.operand;4875 int i = vPC[3].u.operand;4876 int size = vPC[4].u.operand;4877 int iter = vPC[5].u.operand;4878 int target = vPC[6].u.operand;4879 4880 JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator();4881 while (callFrame->r(i).i() != callFrame->r(size).i()) {4882 JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i());4883 CHECK_FOR_EXCEPTION();4884 callFrame->uncheckedR(i) = Register::withInt(callFrame->r(i).i() + 1);4885 if (key) {4886 CHECK_FOR_TIMEOUT();4887 callFrame->uncheckedR(dst) = key;4888 vPC += target;4889 NEXT_INSTRUCTION();4890 }4891 }4892 4893 vPC += OPCODE_LENGTH(op_next_pname);4894 NEXT_INSTRUCTION();4895 }4896 DEFINE_OPCODE(op_jmp_scopes) {4897 /* jmp_scopes count(n) target(offset)4898 4899 Removes the a number of items from the current scope chain4900 specified by immediate number count, then jumps to offset4901 target.4902 */4903 int count = vPC[1].u.operand;4904 int target = vPC[2].u.operand;4905 4906 JSScope* tmp = callFrame->scope();4907 while (count--)4908 tmp = tmp->next();4909 callFrame->setScope(tmp);4910 4911 vPC += target;4912 NEXT_INSTRUCTION();4913 }4914 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)4915 // Appease GCC4916 goto *(&&skip_new_scope);4917 #endif4918 DEFINE_OPCODE(op_push_name_scope) {4919 /* new_scope property(id) value(r) attributes(unsigned)4920 4921 Constructs a name scope of the form { property<attributes>: value },4922 and pushes it onto the scope chain.4923 */4924 callFrame->setScope(createNameScope(callFrame, vPC));4925 4926 vPC += OPCODE_LENGTH(op_push_name_scope);4927 NEXT_INSTRUCTION();4928 }4929 #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)4930 skip_new_scope:4931 #endif4932 DEFINE_OPCODE(op_catch) {4933 /* catch ex(r)4934 4935 Retrieves the VM's current exception and puts it in register4936 ex. This is only valid after an exception has been raised,4937 and usually forms the beginning of an exception handler.4938 */4939 ASSERT(exceptionValue);4940 ASSERT(!globalData->exception);4941 int ex = vPC[1].u.operand;4942 callFrame->uncheckedR(ex) = exceptionValue;4943 exceptionValue = JSValue();4944 4945 vPC += OPCODE_LENGTH(op_catch);4946 NEXT_INSTRUCTION();4947 }4948 DEFINE_OPCODE(op_throw) {4949 /* throw ex(r)4950 4951 Throws register ex as an exception. This involves three4952 steps: first, it is set as the current exception in the4953 VM's internal state, then the stack is unwound until an4954 exception handler or a native code boundary is found, and4955 then control resumes at the exception handler if any or4956 else the script returns control to the nearest native caller.4957 */4958 4959 int ex = vPC[1].u.operand;4960 exceptionValue = callFrame->r(ex).jsValue();4961 4962 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());4963 if (!handler)4964 return throwError(callFrame, exceptionValue);4965 4966 codeBlock = callFrame->codeBlock();4967 vPC = codeBlock->instructions().begin() + handler->target;4968 NEXT_INSTRUCTION();4969 }4970 DEFINE_OPCODE(op_throw_reference_error) {4971 /* op_throw_reference_error message(k)4972 4973 Constructs a new reference Error instance using the4974 original constructor, using constant message as the4975 message string. The result is thrown.4976 */4977 String message = callFrame->r(vPC[1].u.operand).jsValue().toString(callFrame)->value(callFrame);4978 exceptionValue = JSValue(createReferenceError(callFrame, message));4979 goto vm_throw;4980 }4981 DEFINE_OPCODE(op_end) {4982 /* end result(r)4983 4984 Return register result as the value of a global or eval4985 program. Return control to the calling native code.4986 */4987 4988 int result = vPC[1].u.operand;4989 return callFrame->r(result).jsValue();4990 }4991 DEFINE_OPCODE(op_put_getter_setter) {4992 /* put_getter_setter base(r) property(id) getter(r) setter(r)4993 4994 Puts accessor descriptor to register base as the named4995 identifier property. Base and function may be objects4996 or undefined, this op should only be used for accessors4997 defined in object literal form.4998 4999 Unlike many opcodes, this one does not write any output to5000 the register file.5001 */5002 int base = vPC[1].u.operand;5003 int property = vPC[2].u.operand;5004 int getterReg = vPC[3].u.operand;5005 int setterReg = vPC[4].u.operand;5006 5007 ASSERT(callFrame->r(base).jsValue().isObject());5008 JSObject* baseObj = asObject(callFrame->r(base).jsValue());5009 Identifier& ident = codeBlock->identifier(property);5010 5011 GetterSetter* accessor = GetterSetter::create(callFrame);5012 5013 JSValue getter = callFrame->r(getterReg).jsValue();5014 JSValue setter = callFrame->r(setterReg).jsValue();5015 ASSERT(getter.isObject() || getter.isUndefined());5016 ASSERT(setter.isObject() || setter.isUndefined());5017 ASSERT(getter.isObject() || setter.isObject());5018 5019 if (!getter.isUndefined())5020 accessor->setGetter(callFrame->globalData(), asObject(getter));5021 if (!setter.isUndefined())5022 accessor->setSetter(callFrame->globalData(), asObject(setter));5023 baseObj->putDirectAccessor(callFrame, ident, accessor, Accessor);5024 5025 vPC += OPCODE_LENGTH(op_put_getter_setter);5026 NEXT_INSTRUCTION();5027 }5028 DEFINE_OPCODE(op_method_check) {5029 vPC++;5030 NEXT_INSTRUCTION();5031 }5032 DEFINE_OPCODE(op_debug) {5033 /* debug debugHookID(n) firstLine(n) lastLine(n) column(n)5034 5035 Notifies the debugger of the current state of execution. This opcode5036 is only generated while the debugger is attached.5037 */5038 int debugHookID = vPC[1].u.operand;5039 int firstLine = vPC[2].u.operand;5040 int lastLine = vPC[3].u.operand;5041 int column = vPC[4].u.operand;5042 5043 5044 debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, column);5045 5046 vPC += OPCODE_LENGTH(op_debug);5047 NEXT_INSTRUCTION();5048 }5049 DEFINE_OPCODE(op_profile_will_call) {5050 /* op_profile_will_call function(r)5051 5052 Notifies the profiler of the beginning of a function call. This opcode5053 is only generated if developer tools are enabled.5054 */5055 int function = vPC[1].u.operand;5056 5057 if (Profiler* profiler = globalData->enabledProfiler())5058 profiler->willExecute(callFrame, callFrame->r(function).jsValue());5059 5060 vPC += OPCODE_LENGTH(op_profile_will_call);5061 NEXT_INSTRUCTION();5062 }5063 DEFINE_OPCODE(op_profile_did_call) {5064 /* op_profile_did_call function(r)5065 5066 Notifies the profiler of the end of a function call. This opcode5067 is only generated if developer tools are enabled.5068 */5069 int function = vPC[1].u.operand;5070 5071 if (Profiler* profiler = globalData->enabledProfiler())5072 profiler->didExecute(callFrame, callFrame->r(function).jsValue());5073 5074 vPC += OPCODE_LENGTH(op_profile_did_call);5075 NEXT_INSTRUCTION();5076 }5077 vm_throw: {5078 globalData->exception = JSValue();5079 if (!tickCount) {5080 // The exceptionValue is a lie! (GCC produces bad code for reasons I5081 // cannot fathom if we don't assign to the exceptionValue before branching)5082 exceptionValue = createInterruptedExecutionException(globalData);5083 }5084 JSGlobalObject* globalObject = callFrame->lexicalGlobalObject();5085 handler = throwException(callFrame, exceptionValue, vPC - codeBlock->instructions().begin());5086 if (!handler) {5087 // Can't use the callframe at this point as the scopechain, etc have5088 // been released.5089 return throwError(globalObject->globalExec(), exceptionValue);5090 }5091 5092 codeBlock = callFrame->codeBlock();5093 vPC = codeBlock->instructions().begin() + handler->target;5094 NEXT_INSTRUCTION();5095 }5096 }5097 #if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER)5098 } // iterator loop ends5099 #endif5100 #undef NEXT_INSTRUCTION5101 #undef DEFINE_OPCODE5102 #undef CHECK_FOR_EXCEPTION5103 #undef CHECK_FOR_TIMEOUT5104 #endif // ENABLE(CLASSIC_INTERPRETER)5105 }5106 5107 #endif // !ENABLE(LLINT_C_LOOP)5108 5109 5110 1290 JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const 5111 1291 { … … 5163 1343 return; 5164 1344 unsigned bytecodeOffset = 0; 5165 #if ENABLE(CLASSIC_INTERPRETER)5166 if (!callerFrame->globalData().canUseJIT())5167 bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());5168 #if ENABLE(JIT)5169 else5170 bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC());5171 #endif5172 #else5173 1345 bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); 5174 #endif5175 1346 lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1); 5176 1347 sourceID = callerCodeBlock->ownerExecutable()->sourceID(); -
trunk/Source/JavaScriptCore/interpreter/Interpreter.h
r128014 r129453 205 205 { 206 206 ASSERT(m_initialized); 207 #if ENABLE(COMPUTED_GOTO_OPCODES) 208 #if ENABLE(LLINT) 207 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) 209 208 ASSERT(isOpcode(opcode)); 210 209 return m_opcodeIDTable.get(opcode); 211 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) 212 ASSERT(isOpcode(opcode)); 213 if (!m_classicEnabled) 214 return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)); 215 216 return m_opcodeIDTable.get(opcode); 217 #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) 218 #else // !ENABLE(COMPUTED_GOTO_OPCODES) 210 #else 219 211 return opcode; 220 #endif // !ENABLE(COMPUTED_GOTO_OPCODES) 221 } 222 223 bool classicEnabled() 224 { 225 return m_classicEnabled; 226 } 227 212 #endif 213 } 214 228 215 bool isOpcode(Opcode); 229 216 … … 261 248 JSValue execute(CallFrameClosure&); 262 249 263 #if ENABLE(CLASSIC_INTERPRETER)264 NEVER_INLINE JSScope* createNameScope(CallFrame*, const Instruction* vPC);265 266 void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const Identifier& propertyName, const PropertySlot&);267 void uncacheGetByID(CodeBlock*, Instruction* vPC);268 void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const PutPropertySlot&);269 void uncachePutByID(CodeBlock*, Instruction* vPC);270 #endif // ENABLE(CLASSIC_INTERPRETER)271 272 250 NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&); 273 251 … … 292 270 RegisterFile m_registerFile; 293 271 294 #if ENABLE(COMPUTED_GOTO_OPCODES) 295 #if ENABLE(LLINT) 272 #if ENABLE(COMPUTED_GOTO_OPCODES) && ENABLE(LLINT) 296 273 Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling 297 274 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling 298 #elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) 299 Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling 300 HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling 301 #endif 302 #endif // ENABLE(COMPUTED_GOTO_OPCODES) 275 #endif 303 276 304 277 #if !ASSERT_DISABLED 305 278 bool m_initialized; 306 279 #endif 307 bool m_classicEnabled;308 280 }; 309 281
Note:
See TracChangeset
for help on using the changeset viewer.