diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecode')
-rw-r--r-- | Source/JavaScriptCore/bytecode/ArrayProfile.cpp | 21 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/ArrayProfile.h | 8 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeBlock.cpp | 441 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeBlock.h | 203 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/DFGExitProfile.h | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/GetByIdStatus.cpp | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp | 50 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h | 83 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp | 66 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h | 87 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/Opcode.h | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/SpeculatedType.h | 5 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp | 294 | ||||
-rw-r--r-- | Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h | 700 |
14 files changed, 1343 insertions, 627 deletions
diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp index de7f67887..5a87380fd 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.cpp +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "ArrayProfile.h" +#include "CodeBlock.h" #include <wtf/StringExtras.h> namespace JSC { @@ -38,14 +39,14 @@ const char* arrayModesToString(ArrayModes arrayModes) if (arrayModes == ALL_ARRAY_MODES) return "TOP"; - bool isNonArray = !!(arrayModes & NonArray); - bool isNonArrayWithContiguous = !!(arrayModes & NonArrayWithContiguous); - bool isNonArrayWithArrayStorage = !!(arrayModes & NonArrayWithArrayStorage); - bool isNonArrayWithSlowPutArrayStorage = !!(arrayModes & NonArrayWithSlowPutArrayStorage); - bool isArray = !!(arrayModes & ArrayClass); - bool isArrayWithContiguous = !!(arrayModes & ArrayWithContiguous); - bool isArrayWithArrayStorage = !!(arrayModes & ArrayWithArrayStorage); - bool isArrayWithSlowPutArrayStorage = !!(arrayModes & ArrayWithSlowPutArrayStorage); + bool isNonArray = !!(arrayModes & asArrayModes(NonArray)); + bool isNonArrayWithContiguous = !!(arrayModes & asArrayModes(NonArrayWithContiguous)); + bool isNonArrayWithArrayStorage = !!(arrayModes & asArrayModes(NonArrayWithArrayStorage)); + bool isNonArrayWithSlowPutArrayStorage = !!(arrayModes & asArrayModes(NonArrayWithSlowPutArrayStorage)); + bool isArray = !!(arrayModes & asArrayModes(ArrayClass)); + bool isArrayWithContiguous = !!(arrayModes & asArrayModes(ArrayWithContiguous)); + bool isArrayWithArrayStorage = !!(arrayModes & asArrayModes(ArrayWithArrayStorage)); + bool isArrayWithSlowPutArrayStorage = !!(arrayModes & asArrayModes(ArrayWithSlowPutArrayStorage)); static char result[256]; snprintf( @@ -64,12 +65,14 @@ const char* arrayModesToString(ArrayModes arrayModes) return result; } -void ArrayProfile::computeUpdatedPrediction(OperationInProgress operation) +void ArrayProfile::computeUpdatedPrediction(CodeBlock* codeBlock, OperationInProgress operation) { if (m_lastSeenStructure) { m_observedArrayModes |= arrayModeFromStructure(m_lastSeenStructure); m_mayInterceptIndexedAccesses |= m_lastSeenStructure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero(); + if (!codeBlock->globalObject()->isOriginalArrayStructure(m_lastSeenStructure)) + m_usesOriginalArrayStructures = false; if (!m_structureIsPolymorphic) { if (!m_expectedStructure) m_expectedStructure = m_lastSeenStructure; diff --git a/Source/JavaScriptCore/bytecode/ArrayProfile.h b/Source/JavaScriptCore/bytecode/ArrayProfile.h index ffc136258..376684fc1 100644 --- a/Source/JavaScriptCore/bytecode/ArrayProfile.h +++ b/Source/JavaScriptCore/bytecode/ArrayProfile.h @@ -33,6 +33,7 @@ namespace JSC { +class CodeBlock; class LLIntOffsetsExtractor; // This is a bitfield where each bit represents an IndexingType that we have seen. @@ -87,6 +88,7 @@ public: , m_structureIsPolymorphic(false) , m_mayStoreToHole(false) , m_mayInterceptIndexedAccesses(false) + , m_usesOriginalArrayStructures(true) , m_observedArrayModes(0) { } @@ -98,6 +100,7 @@ public: , m_structureIsPolymorphic(false) , m_mayStoreToHole(false) , m_mayInterceptIndexedAccesses(false) + , m_usesOriginalArrayStructures(true) , m_observedArrayModes(0) { } @@ -113,7 +116,7 @@ public: m_lastSeenStructure = structure; } - void computeUpdatedPrediction(OperationInProgress operation = NoOperation); + void computeUpdatedPrediction(CodeBlock*, OperationInProgress = NoOperation); Structure* expectedStructure() const { return m_expectedStructure; } bool structureIsPolymorphic() const @@ -129,6 +132,8 @@ public: bool mayStoreToHole() const { return m_mayStoreToHole; } + bool usesOriginalArrayStructures() const { return m_usesOriginalArrayStructures; } + private: friend class LLIntOffsetsExtractor; @@ -138,6 +143,7 @@ private: bool m_structureIsPolymorphic; bool m_mayStoreToHole; // This flag may become overloaded to indicate other special cases that were encountered during array access, as it depends on indexing type. Since we currently have basically just one indexing type (two variants of ArrayStorage), this flag for now just means exactly what its name implies. bool m_mayInterceptIndexedAccesses; + bool m_usesOriginalArrayStructures; ArrayModes m_observedArrayModes; }; diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp index 7f86186a0..ceae3fcb2 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp @@ -43,7 +43,6 @@ #include "JSNameScope.h" #include "JSValue.h" #include "LowLevelInterpreter.h" -#include "MethodCallLinkStatus.h" #include "RepatchBuffer.h" #include "SlotVisitorInlineMethods.h" #include <stdio.h> @@ -283,9 +282,6 @@ void CodeBlock::printGetByIdCacheStatus(ExecState* exec, int location) { Instruction* instruction = instructions().begin() + location; - if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_method_check) - instruction++; - Identifier& ident = identifier(instruction[3].u.operand); UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations. @@ -496,8 +492,8 @@ void CodeBlock::dump(ExecState* exec) static_cast<unsigned long>(instructions().size() * sizeof(Instruction)), this, codeTypeToString(codeType()), m_numParameters, m_numCalleeRegisters, m_numVars); - if (m_symbolTable->captureCount()) - dataLog("; %d captured var(s)", m_symbolTable->captureCount()); + if (symbolTable()->captureCount()) + dataLog("; %d captured var(s)", symbolTable()->captureCount()); if (usesArguments()) { dataLog( "; uses arguments, in r%d, r%d", @@ -531,13 +527,13 @@ void CodeBlock::dump(ExecState* exec) } while (i < m_constantRegisters.size()); } - if (m_rareData && !m_rareData->m_regexps.isEmpty()) { + if (size_t count = m_unlinkedCode->numberOfRegExps()) { dataLog("\nm_regexps:\n"); size_t i = 0; do { - dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_rareData->m_regexps[i].get()).utf8().data()); + dataLog(" re%u = %s\n", static_cast<unsigned>(i), regexpToSourceString(m_unlinkedCode->regexp(i)).utf8().data()); ++i; - } while (i < m_rareData->m_regexps.size()); + } while (i < count); } #if ENABLE(JIT) @@ -671,7 +667,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - dataLog("[%4d] new_array_buffer %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); + dataLog("[%4d] new_array_buffer\t %s, %d, %d", location, registerName(exec, dst).data(), argv, argc); dumpBytecodeCommentAndNewLine(location); break; } @@ -679,7 +675,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int re0 = (++it)->u.operand; dataLog("[%4d] new_regexp\t %s, ", location, registerName(exec, r0).data()); - if (r0 >=0 && r0 < (int)numberOfRegExps()) + if (r0 >=0 && r0 < (int)m_unlinkedCode->numberOfRegExps()) dataLog("%s", regexpName(re0, regexp(re0)).data()); else dataLog("bad_regexp(%d)", re0); @@ -889,11 +885,22 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& it++; break; } + case op_init_global_const_nop: { + dataLog("[%4d] init_global_const_nop\t", location); + dumpBytecodeCommentAndNewLine(location); + it++; + it++; + it++; + it++; + break; + } case op_init_global_const: { WriteBarrier<Unknown>* registerPointer = (++it)->u.registerPointer; int r0 = (++it)->u.operand; dataLog("[%4d] init_global_const\t g%d(%p), %s", location, m_globalObject->findRegisterIndex(registerPointer), registerPointer, registerName(exec, r0).data()); dumpBytecodeCommentAndNewLine(location); + it++; + it++; break; } case op_init_global_const_check: { @@ -1017,42 +1024,6 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& dumpBytecodeCommentAndNewLine(location); break; } - case op_method_check: { - dataLog("[%4d] method_check", location); -#if ENABLE(JIT) - if (numberOfMethodCallLinkInfos()) { - MethodCallLinkInfo& methodCall = getMethodCallLinkInfo(location); - dataLog(" jit("); - if (!methodCall.seen) - dataLog("not seen"); - else { - // Use the fact that MethodCallLinkStatus already does smart things - // for decoding seen method calls. - MethodCallLinkStatus status = MethodCallLinkStatus::computeFor(this, location); - if (!status) - dataLog("not set"); - else { - dataLog("function = %p (executable = ", status.function()); - JSCell* functionAsCell = getJSFunction(status.function()); - if (functionAsCell) - dataLog("%p", jsCast<JSFunction*>(functionAsCell)->executable()); - else - dataLog("N/A"); - dataLog("), struct = %p", status.structure()); - if (status.needsPrototypeCheck()) - dataLog(", prototype = %p, struct = %p", status.prototype(), status.prototypeStructure()); - } - } - dataLog(")"); - } -#endif - dumpBytecodeCommentAndNewLine(location); - ++it; - printGetByIdOp(exec, location, it); - printGetByIdCacheStatus(exec, location); - dataLog("\n"); - break; - } case op_del_by_id: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; @@ -1431,9 +1402,10 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& dumpBytecodeCommentAndNewLine(location); break; } - case op_throw_reference_error: { + case op_throw_static_error: { int k0 = (++it)->u.operand; - dataLog("[%4d] throw_reference_error\t %s", location, constantName(exec, k0, getConstant(k0)).data()); + int k1 = (++it)->u.operand; + dataLog("[%4d] throw_static_error\t %s, %s", location, constantName(exec, k0, getConstant(k0)).data(), k1 ? "true" : "false"); dumpBytecodeCommentAndNewLine(location); break; } @@ -1531,9 +1503,9 @@ void CodeBlock::dumpStatistics() FOR_EACH_MEMBER_VECTOR(GET_STATS) #undef GET_STATS - if (!codeBlock->m_symbolTable.isEmpty()) { + if (codeBlock->symbolTable() && !codeBlock->symbolTable()->isEmpty()) { symbolTableIsNotEmpty++; - symbolTableTotalSize += (codeBlock->m_symbolTable.capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType))); + symbolTableTotalSize += (codeBlock->symbolTable()->capacity() * (sizeof(SymbolTable::KeyType) + sizeof(SymbolTable::MappedType))); } if (codeBlock->m_rareData) { @@ -1601,34 +1573,26 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) , m_numCalleeRegisters(other.m_numCalleeRegisters) , m_numVars(other.m_numVars) , m_isConstructor(other.m_isConstructor) + , m_unlinkedCode(*other.m_globalData, other.m_ownerExecutable.get(), other.m_unlinkedCode.get()) , m_ownerExecutable(*other.m_globalData, other.m_ownerExecutable.get(), other.m_ownerExecutable.get()) , m_globalData(other.m_globalData) , m_instructions(other.m_instructions) , m_thisRegister(other.m_thisRegister) , m_argumentsRegister(other.m_argumentsRegister) , m_activationRegister(other.m_activationRegister) - , m_globalObjectConstant(other.m_globalObjectConstant) - , m_needsFullScopeChain(other.m_needsFullScopeChain) - , m_usesEval(other.m_usesEval) - , m_isNumericCompareFunction(other.m_isNumericCompareFunction) , m_isStrictMode(other.m_isStrictMode) - , m_codeType(other.m_codeType) , m_source(other.m_source) , m_sourceOffset(other.m_sourceOffset) #if ENABLE(VALUE_PROFILER) , m_executionEntryCount(0) #endif - , m_jumpTargets(other.m_jumpTargets) - , m_loopTargets(other.m_loopTargets) , m_identifiers(other.m_identifiers) , m_constantRegisters(other.m_constantRegisters) , m_functionDecls(other.m_functionDecls) , m_functionExprs(other.m_functionExprs) - , m_symbolTable(*other.m_globalData, other.m_ownerExecutable.get(), other.symbolTable()) , m_osrExitCounter(0) , m_optimizationDelayCounter(0) , m_reoptimizationRetryCounter(0) - , m_lineInfo(other.m_lineInfo) , m_resolveOperations(other.m_resolveOperations) , m_putToBaseOperations(other.m_putToBaseOperations) #if ENABLE(BYTECODE_COMMENTS) @@ -1646,36 +1610,31 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other) createRareDataIfNecessary(); m_rareData->m_exceptionHandlers = other.m_rareData->m_exceptionHandlers; - m_rareData->m_regexps = other.m_rareData->m_regexps; m_rareData->m_constantBuffers = other.m_rareData->m_constantBuffers; m_rareData->m_immediateSwitchJumpTables = other.m_rareData->m_immediateSwitchJumpTables; m_rareData->m_characterSwitchJumpTables = other.m_rareData->m_characterSwitchJumpTables; m_rareData->m_stringSwitchJumpTables = other.m_rareData->m_stringSwitchJumpTables; - m_rareData->m_expressionInfo = other.m_rareData->m_expressionInfo; } } -CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, bool isConstructor, PassOwnPtr<CodeBlock> alternative) +CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSGlobalObject* globalObject, unsigned baseScopeDepth, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative) : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject) , m_heap(&m_globalObject->globalData().heap) - , m_numCalleeRegisters(0) - , m_numVars(0) - , m_isConstructor(isConstructor) - , m_numParameters(0) + , m_numCalleeRegisters(unlinkedCodeBlock->m_numCalleeRegisters) + , m_numVars(unlinkedCodeBlock->m_numVars) + , m_isConstructor(unlinkedCodeBlock->isConstructor()) + , m_unlinkedCode(globalObject->globalData(), ownerExecutable, unlinkedCodeBlock) , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable) - , m_globalData(0) - , m_argumentsRegister(-1) - , m_needsFullScopeChain(ownerExecutable->needsActivation()) - , m_usesEval(ownerExecutable->usesEval()) - , m_isNumericCompareFunction(false) - , m_isStrictMode(ownerExecutable->isStrictMode()) - , m_codeType(codeType) + , m_globalData(unlinkedCodeBlock->globalData()) + , m_thisRegister(unlinkedCodeBlock->thisRegister()) + , m_argumentsRegister(unlinkedCodeBlock->argumentsRegister()) + , m_activationRegister(unlinkedCodeBlock->activationRegister()) + , m_isStrictMode(unlinkedCodeBlock->isStrictMode()) , m_source(sourceProvider) , m_sourceOffset(sourceOffset) #if ENABLE(VALUE_PROFILER) , m_executionEntryCount(0) #endif - , m_symbolTable(globalObject->globalData(), ownerExecutable, SharedSymbolTable::create(globalObject->globalData())) , m_alternative(alternative) , m_osrExitCounter(0) , m_optimizationDelayCounter(0) @@ -1684,7 +1643,10 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo , m_bytecodeCommentIterator(0) #endif { + m_globalData->startedCompiling(this); + ASSERT(m_source); + setNumParameters(unlinkedCodeBlock->numParameters()); optimizeAfterWarmUp(); jitAfterWarmUp(); @@ -1692,9 +1654,208 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo #if DUMP_CODE_BLOCK_STATISTICS liveCodeBlockSet.add(this); #endif - // We have a stub putToBase operation to allow resolve_base to - // remain branchless - m_putToBaseOperations.append(PutToBaseOperation(isStrictMode())); + setIdentifiers(unlinkedCodeBlock->identifiers()); + setConstantRegisters(unlinkedCodeBlock->constantRegisters()); + + m_functionDecls.grow(unlinkedCodeBlock->numberOfFunctionDecls()); + for (size_t count = unlinkedCodeBlock->numberOfFunctionDecls(), i = 0; i < count; ++i) { + UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionDecl(i); + unsigned lineCount = unlinkedExecutable->lineCount(); + unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset(); + unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset(); + unsigned sourceLength = unlinkedExecutable->sourceLength(); + SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine); + FunctionExecutable* executable = FunctionExecutable::create(*m_globalData, code, unlinkedExecutable, firstLine, firstLine + lineCount); + m_functionDecls[i].set(*m_globalData, ownerExecutable, executable); + } + + m_functionExprs.grow(unlinkedCodeBlock->numberOfFunctionExprs()); + for (size_t count = unlinkedCodeBlock->numberOfFunctionExprs(), i = 0; i < count; ++i) { + UnlinkedFunctionExecutable* unlinkedExecutable = unlinkedCodeBlock->functionExpr(i); + unsigned lineCount = unlinkedExecutable->lineCount(); + unsigned firstLine = ownerExecutable->lineNo() + unlinkedExecutable->firstLineOffset(); + unsigned startOffset = sourceOffset + unlinkedExecutable->startOffset(); + unsigned sourceLength = unlinkedExecutable->sourceLength(); + SourceCode code(m_source, startOffset, startOffset + sourceLength, firstLine); + FunctionExecutable* executable = FunctionExecutable::create(*m_globalData, code, unlinkedExecutable, firstLine, firstLine + lineCount); + m_functionExprs[i].set(*m_globalData, ownerExecutable, executable); + } + + if (unlinkedCodeBlock->hasRareData()) { + createRareDataIfNecessary(); + if (size_t count = unlinkedCodeBlock->constantBufferCount()) { + m_rareData->m_constantBuffers.grow(count); + for (size_t i = 0; i < count; i++) { + const UnlinkedCodeBlock::ConstantBuffer& buffer = unlinkedCodeBlock->constantBuffer(i); + m_rareData->m_constantBuffers[i] = buffer; + } + } + if (size_t count = unlinkedCodeBlock->numberOfExceptionHandlers()) { + m_rareData->m_exceptionHandlers.grow(count); + for (size_t i = 0; i < count; i++) { + const UnlinkedHandlerInfo& handler = unlinkedCodeBlock->exceptionHandler(i); + m_rareData->m_exceptionHandlers[i].start = handler.start; + m_rareData->m_exceptionHandlers[i].end = handler.end; + m_rareData->m_exceptionHandlers[i].target = handler.target; + m_rareData->m_exceptionHandlers[i].scopeDepth = handler.scopeDepth + baseScopeDepth; +#if ENABLE(JIT) && ENABLE(LLINT) + m_rareData->m_exceptionHandlers[i].nativeCode = CodeLocationLabel(MacroAssemblerCodePtr::createFromExecutableAddress(LLInt::getCodePtr(llint_op_catch))); +#endif + } + } + + if (size_t count = unlinkedCodeBlock->numberOfStringSwitchJumpTables()) { + m_rareData->m_stringSwitchJumpTables.grow(count); + for (size_t i = 0; i < count; i++) { + UnlinkedStringJumpTable::StringOffsetTable::iterator ptr = unlinkedCodeBlock->stringSwitchJumpTable(i).offsetTable.begin(); + UnlinkedStringJumpTable::StringOffsetTable::iterator end = unlinkedCodeBlock->stringSwitchJumpTable(i).offsetTable.end(); + for (; ptr != end; ++ptr) { + OffsetLocation offset; + offset.branchOffset = ptr->value; + m_rareData->m_stringSwitchJumpTables[i].offsetTable.add(ptr->key, offset); + } + } + } + + if (size_t count = unlinkedCodeBlock->numberOfImmediateSwitchJumpTables()) { + m_rareData->m_immediateSwitchJumpTables.grow(count); + for (size_t i = 0; i < count; i++) { + UnlinkedSimpleJumpTable& sourceTable = unlinkedCodeBlock->immediateSwitchJumpTable(i); + SimpleJumpTable& destTable = m_rareData->m_immediateSwitchJumpTables[i]; + destTable.branchOffsets = sourceTable.branchOffsets; + destTable.min = sourceTable.min; + } + } + + if (size_t count = unlinkedCodeBlock->numberOfCharacterSwitchJumpTables()) { + m_rareData->m_characterSwitchJumpTables.grow(count); + for (size_t i = 0; i < count; i++) { + UnlinkedSimpleJumpTable& sourceTable = unlinkedCodeBlock->characterSwitchJumpTable(i); + SimpleJumpTable& destTable = m_rareData->m_characterSwitchJumpTables[i]; + destTable.branchOffsets = sourceTable.branchOffsets; + destTable.min = sourceTable.min; + } + } + } + + // Allocate metadata buffers for the bytecode +#if ENABLE(LLINT) + if (size_t size = unlinkedCodeBlock->numberOfLLintCallLinkInfos()) + m_llintCallLinkInfos.grow(size); +#endif +#if ENABLE(DFG_JIT) + if (size_t size = unlinkedCodeBlock->numberOfArrayProfiles()) + m_arrayProfiles.grow(size); + if (size_t size = unlinkedCodeBlock->numberOfValueProfiles()) + m_valueProfiles.grow(size); +#endif + if (size_t size = unlinkedCodeBlock->numberOfResolveOperations()) + m_resolveOperations.grow(size); + size_t putToBaseCount = unlinkedCodeBlock->numberOfPutToBaseOperations(); + m_putToBaseOperations.reserveCapacity(putToBaseCount); + for (size_t i = 0; i < putToBaseCount; ++i) + m_putToBaseOperations.append(PutToBaseOperation(isStrictMode())); + + ASSERT(m_putToBaseOperations.capacity() == putToBaseCount); + + // Copy and translate the UnlinkedInstructions + size_t instructionCount = unlinkedCodeBlock->instructions().size(); + UnlinkedInstruction* pc = unlinkedCodeBlock->instructions().data(); + Vector<Instruction> instructions(instructionCount); + for (size_t i = 0; i < unlinkedCodeBlock->instructions().size(); ) { + unsigned opLength = opcodeLength(pc[i].u.opcode); + instructions[i] = globalData()->interpreter->getOpcode(pc[i].u.opcode); + for (size_t j = 1; j < opLength; ++j) { + if (sizeof(int32_t) != sizeof(intptr_t)) + instructions[i + j].u.pointer = 0; + instructions[i + j].u.operand = pc[i + j].u.operand; + } + switch (pc[i].u.opcode) { +#if ENABLE(DFG_JIT) + case op_get_by_val: + case op_get_argument_by_val: { + int arrayProfileIndex = pc[i + opLength - 2].u.operand; + m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); + + instructions[i + opLength - 2] = &m_arrayProfiles[arrayProfileIndex]; + // fallthrough + } + case op_convert_this: + case op_resolve: + case op_resolve_base: + case op_resolve_with_base: + case op_resolve_with_this: + case op_get_by_id: + case op_call_put_result: { + ValueProfile* profile = &m_valueProfiles[pc[i + opLength - 1].u.operand]; + ASSERT(profile->m_bytecodeOffset == -1); + profile->m_bytecodeOffset = i; + instructions[i + opLength - 1] = profile; + break; + } + case op_put_by_val: { + int arrayProfileIndex = pc[i + opLength - 1].u.operand; + m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); + instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex]; + break; + } + + case op_call: + case op_call_eval: { + int arrayProfileIndex = pc[i + opLength - 1].u.operand; + m_arrayProfiles[arrayProfileIndex] = ArrayProfile(i); + instructions[i + opLength - 1] = &m_arrayProfiles[arrayProfileIndex]; + // fallthrough + } +#endif +#if ENABLE(LLINT) + case op_construct: + instructions[i + 4] = &m_llintCallLinkInfos[pc[i + 4].u.operand]; + break; +#endif + case op_get_by_id_out_of_line: + case op_get_by_id_self: + case op_get_by_id_proto: + case op_get_by_id_chain: + case op_get_by_id_getter_self: + case op_get_by_id_getter_proto: + case op_get_by_id_getter_chain: + case op_get_by_id_custom_self: + case op_get_by_id_custom_proto: + case op_get_by_id_custom_chain: + case op_get_by_id_generic: + case op_get_array_length: + case op_get_string_length: + CRASH(); + + case op_init_global_const_nop: { + ASSERT(codeType() == GlobalCode); + Identifier ident = identifier(pc[i + 4].u.operand); + SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl()); + if (entry.isNull()) + break; + + if (entry.couldBeWatched()) { + instructions[i + 0] = globalData()->interpreter->getOpcode(op_init_global_const_check); + instructions[i + 1] = &globalObject->registerAt(entry.getIndex()); + instructions[i + 3] = entry.addressOfIsWatched(); + break; + } + + instructions[i + 0] = globalData()->interpreter->getOpcode(op_init_global_const); + instructions[i + 1] = &globalObject->registerAt(entry.getIndex()); + break; + } + default: + break; + } + i += opLength; + } + m_instructions = WTF::RefCountedArray<Instruction>(instructions); + + if (BytecodeGenerator::dumpsGeneratedCode()) + dump(m_globalObject->globalExec()); + m_globalData->finishedCompiling(this); } CodeBlock::~CodeBlock() @@ -1745,15 +1906,6 @@ void CodeBlock::setNumParameters(int newValue) #endif } -void CodeBlock::addParameter() -{ - m_numParameters++; - -#if ENABLE(VALUE_PROFILER) - m_argumentValueProfiles.append(ValueProfile()); -#endif -} - void CodeBlock::visitStructures(SlotVisitor& visitor, Instruction* vPC) { Interpreter* interpreter = m_globalData->interpreter; @@ -1836,6 +1988,8 @@ void CodeBlock::visitAggregate(SlotVisitor& visitor) if (!!m_alternative) m_alternative->visitAggregate(visitor); + visitor.append(&m_unlinkedCode); + // There are three things that may use unconditional finalizers: lazy bytecode freeing, // inline cache clearing, and jettisoning. The probability of us wanting to do at // least one of those things is probably quite close to 1. So we add one no matter what @@ -1950,8 +2104,9 @@ void CodeBlock::finalizeUnconditionally() #if ENABLE(LLINT) Interpreter* interpreter = m_globalData->interpreter; if (!!numberOfInstructions()) { - for (size_t size = m_propertyAccessInstructions.size(), i = 0; i < size; ++i) { - Instruction* curInstruction = &instructions()[m_propertyAccessInstructions[i]]; + const Vector<unsigned>& propertyAccessInstructions = m_unlinkedCode->propertyAccessInstructions(); + for (size_t size = propertyAccessInstructions.size(), i = 0; i < size; ++i) { + Instruction* curInstruction = &instructions()[propertyAccessInstructions[i]]; switch (interpreter->getOpcodeID(curInstruction[0].u.opcode)) { case op_get_by_id: case op_get_by_id_out_of_line: @@ -2061,36 +2216,6 @@ void CodeBlock::finalizeUnconditionally() resetStubInternal(repatchBuffer, stubInfo); } - - for (size_t size = m_methodCallLinkInfos.size(), i = 0; i < size; ++i) { - if (!m_methodCallLinkInfos[i].cachedStructure) - continue; - - ASSERT(m_methodCallLinkInfos[i].seenOnce()); - ASSERT(!!m_methodCallLinkInfos[i].cachedPrototypeStructure); - - if (!Heap::isMarked(m_methodCallLinkInfos[i].cachedStructure.get()) - || !Heap::isMarked(m_methodCallLinkInfos[i].cachedPrototypeStructure.get()) - || !Heap::isMarked(m_methodCallLinkInfos[i].cachedFunction.get()) - || !Heap::isMarked(m_methodCallLinkInfos[i].cachedPrototype.get())) { - if (verboseUnlinking) - dataLog("Clearing method call in %p.\n", this); - m_methodCallLinkInfos[i].reset(repatchBuffer, getJITType()); - - StructureStubInfo& stubInfo = getStubInfo(m_methodCallLinkInfos[i].bytecodeIndex); - - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - if (accessType != access_unset) { - ASSERT(isGetByIdAccess(accessType)); - if (getJITCode().jitType() == JITCode::DFGJIT) - DFG::dfgResetGetByID(repatchBuffer, stubInfo); - else - JIT::resetPatchGetById(repatchBuffer, &stubInfo); - stubInfo.reset(); - } - } - } } #endif } @@ -2133,14 +2258,9 @@ void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor) { visitor.append(&m_globalObject); visitor.append(&m_ownerExecutable); - visitor.append(&m_symbolTable); - if (m_rareData) { + visitor.append(&m_unlinkedCode); + if (m_rareData) m_rareData->m_evalCodeCache.visitAggregate(visitor); - size_t regExpCount = m_rareData->m_regexps.size(); - WriteBarrier<RegExp>* regexps = m_rareData->m_regexps.data(); - for (size_t i = 0; i < regExpCount; i++) - visitor.append(regexps + i); - } visitor.appendValues(m_constantRegisters.data(), m_constantRegisters.size()); for (size_t i = 0; i < m_functionExprs.size(); ++i) visitor.append(&m_functionExprs[i]); @@ -2267,76 +2387,27 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) { ASSERT(bytecodeOffset < instructions().size()); - - Vector<LineInfo>& lineInfo = m_lineInfo; - - int low = 0; - int high = lineInfo.size(); - while (low < high) { - int mid = low + (high - low) / 2; - if (lineInfo[mid].instructionOffset <= bytecodeOffset) - low = mid + 1; - else - high = mid; - } - - if (!low) - return m_ownerExecutable->source().firstLine(); - return lineInfo[low - 1].lineNumber; + return m_ownerExecutable->lineNo() + m_unlinkedCode->lineNumberForBytecodeOffset(bytecodeOffset); } void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset) { - ASSERT(bytecodeOffset < instructions().size()); - - if (!m_rareData) { - startOffset = 0; - endOffset = 0; - divot = 0; - return; - } - - Vector<ExpressionRangeInfo>& expressionInfo = m_rareData->m_expressionInfo; - - int low = 0; - int high = expressionInfo.size(); - while (low < high) { - int mid = low + (high - low) / 2; - if (expressionInfo[mid].instructionOffset <= bytecodeOffset) - low = mid + 1; - else - high = mid; - } - - ASSERT(low); - if (!low) { - startOffset = 0; - endOffset = 0; - divot = 0; - return; - } - - startOffset = expressionInfo[low - 1].startOffset; - endOffset = expressionInfo[low - 1].endOffset; - divot = expressionInfo[low - 1].divotPoint + m_sourceOffset; - return; + m_unlinkedCode->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset); + divot += m_sourceOffset; } void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) { - m_propertyAccessInstructions.shrinkToFit(); #if ENABLE(LLINT) m_llintCallLinkInfos.shrinkToFit(); #endif #if ENABLE(JIT) m_structureStubInfos.shrinkToFit(); m_callLinkInfos.shrinkToFit(); - m_methodCallLinkInfos.shrinkToFit(); #endif #if ENABLE(VALUE_PROFILER) if (shrinkMode == EarlyShrink) m_argumentValueProfiles.shrinkToFit(); - m_valueProfiles.shrinkToFit(); m_rareCaseProfiles.shrinkToFit(); m_specialFastCaseProfiles.shrinkToFit(); #endif @@ -2348,15 +2419,11 @@ void CodeBlock::shrinkToFit(ShrinkMode shrinkMode) m_constantRegisters.shrinkToFit(); } // else don't shrink these, because we would have already pointed pointers into these tables. - m_resolveOperations.shrinkToFit(); - m_lineInfo.shrinkToFit(); if (m_rareData) { m_rareData->m_exceptionHandlers.shrinkToFit(); - m_rareData->m_regexps.shrinkToFit(); m_rareData->m_immediateSwitchJumpTables.shrinkToFit(); m_rareData->m_characterSwitchJumpTables.shrinkToFit(); m_rareData->m_stringSwitchJumpTables.shrinkToFit(); - m_rareData->m_expressionInfo.shrinkToFit(); #if ENABLE(JIT) m_rareData->m_callReturnIndexVector.shrinkToFit(); #endif @@ -2384,7 +2451,7 @@ void CodeBlock::createActivation(CallFrame* callFrame) ASSERT(codeType() == FunctionCode); ASSERT(needsFullScopeChain()); ASSERT(!callFrame->uncheckedR(activationRegister()).jsValue()); - JSActivation* activation = JSActivation::create(callFrame->globalData(), callFrame, static_cast<FunctionExecutable*>(ownerExecutable())); + JSActivation* activation = JSActivation::create(callFrame->globalData(), callFrame, this); callFrame->uncheckedR(activationRegister()) = JSValue(activation); callFrame->setScope(activation); } @@ -2410,7 +2477,7 @@ void CodeBlock::unlinkCalls() m_llintCallLinkInfos[i].unlink(); } #endif - if (!(m_callLinkInfos.size() || m_methodCallLinkInfos.size())) + if (!m_callLinkInfos.size()) return; if (!m_globalData->canUseJIT()) return; @@ -2725,7 +2792,7 @@ void CodeBlock::updateAllPredictionsAndCountLiveness( // site also has a value profile site - so we already know whether or not it's // live. for (unsigned i = m_arrayProfiles.size(); i--;) - m_arrayProfiles[i].computeUpdatedPrediction(operation); + m_arrayProfiles[i].computeUpdatedPrediction(this, operation); } void CodeBlock::updateAllPredictions(OperationInProgress operation) @@ -2879,8 +2946,8 @@ bool CodeBlock::usesOpcode(OpcodeID opcodeID) String CodeBlock::nameForRegister(int registerNumber) { - SymbolTable::iterator end = m_symbolTable->end(); - for (SymbolTable::iterator ptr = m_symbolTable->begin(); ptr != end; ++ptr) { + SymbolTable::iterator end = symbolTable()->end(); + for (SymbolTable::iterator ptr = symbolTable()->begin(); ptr != end; ++ptr) { if (ptr->value.getIndex() == registerNumber) return String(ptr->key); } diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index fe588c787..a28064940 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -50,7 +50,6 @@ #include "ExecutionCounter.h" #include "ExpressionRangeInfo.h" #include "HandlerInfo.h" -#include "MethodCallLinkInfo.h" #include "Options.h" #include "Instruction.h" #include "JITCode.h" @@ -121,7 +120,7 @@ namespace JSC { protected: CodeBlock(CopyParsedBlockTag, CodeBlock& other); - CodeBlock(ScriptExecutable* ownerExecutable, CodeType, JSGlobalObject*, PassRefPtr<SourceProvider>, unsigned sourceOffset, bool isConstructor, PassOwnPtr<CodeBlock> alternative); + CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSGlobalObject*, unsigned baseScopeDepth, PassRefPtr<SourceProvider>, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative); WriteBarrier<JSGlobalObject> m_globalObject; Heap* m_heap; @@ -131,7 +130,6 @@ namespace JSC { int numParameters() const { return m_numParameters; } void setNumParameters(int newValue); - void addParameter(); int* addressOfNumParameters() { return &m_numParameters; } static ptrdiff_t offsetOfNumParameters() { return OBJECT_OFFSETOF(CodeBlock, m_numParameters); } @@ -249,16 +247,6 @@ namespace JSC { { return *(binarySearch<CallLinkInfo, unsigned, getCallLinkInfoBytecodeIndex>(m_callLinkInfos.begin(), m_callLinkInfos.size(), bytecodeIndex)); } - - MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) - { - return *(binarySearch<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); - } - - MethodCallLinkInfo& getMethodCallLinkInfo(unsigned bytecodeIndex) - { - return *(binarySearch<MethodCallLinkInfo, unsigned, getMethodCallLinkInfoBytecodeIndex>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), bytecodeIndex)); - } #endif // ENABLE(JIT) #if ENABLE(LLINT) @@ -445,8 +433,7 @@ namespace JSC { return static_cast<Instruction*>(returnAddress) - instructions().begin(); } - void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } - bool isNumericCompareFunction() { return m_isNumericCompareFunction; } + bool isNumericCompareFunction() { return m_unlinkedCode->isNumericCompareFunction(); } unsigned numberOfInstructions() const { return m_instructions.size(); } RefCountedArray<Instruction>& instructions() { return m_instructions; } @@ -535,10 +522,8 @@ namespace JSC { void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } int thisRegister() const { return m_thisRegister; } - void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } - bool needsFullScopeChain() const { return m_needsFullScopeChain; } - void setUsesEval(bool usesEval) { m_usesEval = usesEval; } - bool usesEval() const { return m_usesEval; } + bool needsFullScopeChain() const { return m_unlinkedCode->needsFullScopeChain(); } + bool usesEval() const { return m_unlinkedCode->usesEval(); } void setArgumentsRegister(int argumentsRegister) { @@ -600,37 +585,28 @@ namespace JSC { if (usesArguments() && operand == unmodifiedArgumentsRegister(argumentsRegister())) return true; - return operand >= m_symbolTable->captureStart() - && operand < m_symbolTable->captureEnd(); + // We're in global code so there are no locals to capture + if (!symbolTable()) + return false; + + return operand >= symbolTable()->captureStart() + && operand < symbolTable()->captureEnd(); } - CodeType codeType() const { return m_codeType; } + CodeType codeType() const { return m_unlinkedCode->codeType(); } SourceProvider* source() const { return m_source.get(); } unsigned sourceOffset() const { return m_sourceOffset; } - size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } - void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } - unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } - unsigned lastJumpTarget() const { return m_jumpTargets.last(); } + size_t numberOfJumpTargets() const { return m_unlinkedCode->numberOfJumpTargets(); } + unsigned jumpTarget(int index) const { return m_unlinkedCode->jumpTarget(index); } void createActivation(CallFrame*); void clearEvalCache(); String nameForRegister(int registerNumber); - - void addPropertyAccessInstruction(unsigned propertyAccessInstruction) - { - m_propertyAccessInstructions.append(propertyAccessInstruction); - } -#if ENABLE(LLINT) - LLIntCallLinkInfo* addLLIntCallLinkInfo() - { - m_llintCallLinkInfos.append(LLIntCallLinkInfo()); - return &m_llintCallLinkInfos.last(); - } -#endif + #if ENABLE(JIT) void setNumberOfStructureStubInfos(size_t size) { m_structureStubInfos.grow(size); } size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } @@ -643,10 +619,6 @@ namespace JSC { void setNumberOfCallLinkInfos(size_t size) { m_callLinkInfos.grow(size); } size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } - - void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); } - MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } - size_t numberOfMethodCallLinkInfos() { return m_methodCallLinkInfos.size(); } #endif #if ENABLE(VALUE_PROFILER) @@ -662,14 +634,7 @@ namespace JSC { ASSERT(result->m_bytecodeOffset == -1); return result; } - - ValueProfile* addValueProfile(int bytecodeOffset) - { - ASSERT(bytecodeOffset != -1); - ASSERT(m_valueProfiles.isEmpty() || m_valueProfiles.last().m_bytecodeOffset < bytecodeOffset); - m_valueProfiles.append(ValueProfile(bytecodeOffset)); - return &m_valueProfiles.last(); - } + unsigned numberOfValueProfiles() { return m_valueProfiles.size(); } ValueProfile* valueProfile(int index) { @@ -795,25 +760,24 @@ namespace JSC { // Exception handling support size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } - void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } - HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } - - void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) + void allocateHandlers(const Vector<UnlinkedHandlerInfo>& unlinkedHandlers) { + size_t count = unlinkedHandlers.size(); + if (!count) + return; createRareDataIfNecessary(); - m_rareData->m_expressionInfo.append(expressionInfo); - } - - void addLineInfo(unsigned bytecodeOffset, int lineNo) - { - Vector<LineInfo>& lineInfo = m_lineInfo; - if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) { - LineInfo info = { bytecodeOffset, lineNo }; - lineInfo.append(info); + m_rareData->m_exceptionHandlers.resize(count); + for (size_t i = 0; i < count; ++i) { + m_rareData->m_exceptionHandlers[i].start = unlinkedHandlers[i].start; + m_rareData->m_exceptionHandlers[i].end = unlinkedHandlers[i].end; + m_rareData->m_exceptionHandlers[i].target = unlinkedHandlers[i].target; + m_rareData->m_exceptionHandlers[i].scopeDepth = unlinkedHandlers[i].scopeDepth; } + } + HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } - bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); } + bool hasExpressionInfo() { return m_unlinkedCode->hasExpressionInfo(); } #if ENABLE(JIT) Vector<CallReturnOffsetToBytecodeOffset>& callReturnIndexVector() @@ -888,6 +852,8 @@ namespace JSC { m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v); return result; } + + unsigned addOrFindConstant(JSValue); WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } @@ -911,20 +877,7 @@ namespace JSC { } FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } - unsigned addRegExp(RegExp* r) - { - createRareDataIfNecessary(); - unsigned size = m_rareData->m_regexps.size(); - m_rareData->m_regexps.append(WriteBarrier<RegExp>(*m_globalData, ownerExecutable(), r)); - return size; - } - unsigned numberOfRegExps() const - { - if (!m_rareData) - return 0; - return m_rareData->m_regexps.size(); - } - RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } + RegExp* regexp(int index) const { return m_unlinkedCode->regexp(index); } unsigned numberOfConstantBuffers() const { @@ -939,10 +892,6 @@ namespace JSC { m_rareData->m_constantBuffers.append(buffer); return size; } - unsigned addConstantBuffer(unsigned length) - { - return addConstantBuffer(Vector<JSValue>(length)); - } Vector<JSValue>& constantBufferAsVector(unsigned index) { @@ -979,7 +928,7 @@ namespace JSC { StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } - SharedSymbolTable* symbolTable() { return m_symbolTable.get(); } + SharedSymbolTable* symbolTable() const { return m_unlinkedCode->symbolTable(); } EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } @@ -1216,9 +1165,6 @@ namespace JSC { int m_numVars; bool m_isConstructor; - int globalObjectConstant() const { return m_globalObjectConstant; } - void setGlobalObjectConstant(int globalRegister) { m_globalObjectConstant = globalRegister; } - protected: #if ENABLE(JIT) virtual bool jitCompileImpl(ExecState*) = 0; @@ -1226,6 +1172,8 @@ namespace JSC { virtual void visitWeakReferences(SlotVisitor&); virtual void finalizeUnconditionally(); + UnlinkedCodeBlock* unlinkedCodeBlock() const { return m_unlinkedCode.get(); } + private: friend class DFGCodeBlocks; @@ -1237,7 +1185,21 @@ namespace JSC { #if ENABLE(VALUE_PROFILER) void updateAllPredictionsAndCountLiveness(OperationInProgress, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); #endif - + + void setIdentifiers(const Vector<Identifier>& identifiers) + { + ASSERT(m_identifiers.isEmpty()); + m_identifiers.appendVector(identifiers); + } + + void setConstantRegisters(const Vector<WriteBarrier<Unknown> >& constants) + { + size_t count = constants.size(); + m_constantRegisters.resize(count); + for (size_t i = 0; i < count; i++) + m_constantRegisters[i].set(*m_globalData, ownerExecutable(), constants[i].get()); + } + void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&); CString registerName(ExecState*, int r) const; @@ -1287,30 +1249,21 @@ namespace JSC { #if ENABLE(JIT) void resetStubInternal(RepatchBuffer&, StructureStubInfo&); #endif - + WriteBarrier<UnlinkedCodeBlock> m_unlinkedCode; int m_numParameters; - WriteBarrier<ScriptExecutable> m_ownerExecutable; JSGlobalData* m_globalData; RefCountedArray<Instruction> m_instructions; - int m_thisRegister; int m_argumentsRegister; int m_activationRegister; - int m_globalObjectConstant; - bool m_needsFullScopeChain; - bool m_usesEval; - bool m_isNumericCompareFunction; bool m_isStrictMode; - CodeType m_codeType; - RefPtr<SourceProvider> m_source; unsigned m_sourceOffset; - Vector<unsigned> m_propertyAccessInstructions; #if ENABLE(LLINT) SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos; SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo> > m_incomingLLIntCalls; @@ -1319,7 +1272,6 @@ namespace JSC { Vector<StructureStubInfo> m_structureStubInfos; Vector<ByValInfo> m_byValInfos; Vector<CallLinkInfo> m_callLinkInfos; - Vector<MethodCallLinkInfo> m_methodCallLinkInfos; JITCode m_jitCode; MacroAssemblerCodePtr m_jitCodeWithArityCheck; SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo> > m_incomingCalls; @@ -1382,18 +1334,15 @@ namespace JSC { unsigned m_executionEntryCount; #endif - Vector<unsigned> m_jumpTargets; - Vector<unsigned> m_loopTargets; - // Constant Pool Vector<Identifier> m_identifiers; COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier<Unknown>), Register_must_be_same_size_as_WriteBarrier_Unknown); + // TODO: This could just be a pointer to m_unlinkedCodeBlock's data, but the DFG mutates + // it, so we're stuck with it for now. Vector<WriteBarrier<Unknown> > m_constantRegisters; Vector<WriteBarrier<FunctionExecutable> > m_functionDecls; Vector<WriteBarrier<FunctionExecutable> > m_functionExprs; - WriteBarrier<SharedSymbolTable> m_symbolTable; - OwnPtr<CodeBlock> m_alternative; ExecutionCounter m_llintExecuteCounter; @@ -1404,22 +1353,14 @@ namespace JSC { uint16_t m_optimizationDelayCounter; uint16_t m_reoptimizationRetryCounter; - Vector<LineInfo> m_lineInfo; -#if ENABLE(BYTECODE_COMMENTS) - Vector<Comment> m_bytecodeComments; - size_t m_bytecodeCommentIterator; -#endif Vector<ResolveOperations> m_resolveOperations; - Vector<PutToBaseOperation> m_putToBaseOperations; + Vector<PutToBaseOperation, 1> m_putToBaseOperations; struct RareData { WTF_MAKE_FAST_ALLOCATED; public: Vector<HandlerInfo> m_exceptionHandlers; - // Rare Constants - Vector<WriteBarrier<RegExp> > m_regexps; - // Buffers used for large array literals Vector<Vector<JSValue> > m_constantBuffers; @@ -1430,9 +1371,6 @@ namespace JSC { EvalCodeCache m_evalCodeCache; - // Expression info - present if debugging. - Vector<ExpressionRangeInfo> m_expressionInfo; - // Line info - present if profiling or debugging. #if ENABLE(JIT) Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector; #endif @@ -1460,8 +1398,8 @@ namespace JSC { { } - GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative) - : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, false, alternative) + GlobalCodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSGlobalObject* globalObject, unsigned baseScopeDepth, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative) + : CodeBlock(ownerExecutable, unlinkedCodeBlock, globalObject, baseScopeDepth, sourceProvider, sourceOffset, alternative) { } }; @@ -1473,11 +1411,11 @@ namespace JSC { { } - ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, PassOwnPtr<CodeBlock> alternative) - : GlobalCodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, 0, alternative) + ProgramCodeBlock(ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, PassOwnPtr<CodeBlock> alternative) + : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, globalObject, 0, sourceProvider, 0, alternative) { } - + #if ENABLE(JIT) protected: virtual JSObject* compileOptimized(ExecState*, JSScope*, unsigned bytecodeIndex); @@ -1492,26 +1430,16 @@ namespace JSC { public: EvalCodeBlock(CopyParsedBlockTag, EvalCodeBlock& other) : GlobalCodeBlock(CopyParsedBlock, other) - , m_baseScopeDepth(other.m_baseScopeDepth) - , m_variables(other.m_variables) { } - EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth, PassOwnPtr<CodeBlock> alternative) - : GlobalCodeBlock(ownerExecutable, EvalCode, globalObject, sourceProvider, 0, alternative) - , m_baseScopeDepth(baseScopeDepth) + EvalCodeBlock(EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth, PassOwnPtr<CodeBlock> alternative) + : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, globalObject, baseScopeDepth, sourceProvider, 0, alternative) { } - int baseScopeDepth() const { return m_baseScopeDepth; } - - const Identifier& variable(unsigned index) { return m_variables[index]; } - unsigned numVariables() { return m_variables.size(); } - void adoptVariables(Vector<Identifier>& variables) - { - ASSERT(m_variables.isEmpty()); - m_variables.swap(variables); - } + const Identifier& variable(unsigned index) { return unlinkedEvalCodeBlock()->variable(index); } + unsigned numVariables() { return unlinkedEvalCodeBlock()->numVariables(); } #if ENABLE(JIT) protected: @@ -1523,8 +1451,7 @@ namespace JSC { #endif private: - int m_baseScopeDepth; - Vector<Identifier> m_variables; + UnlinkedEvalCodeBlock* unlinkedEvalCodeBlock() const { return jsCast<UnlinkedEvalCodeBlock*>(unlinkedCodeBlock()); } }; class FunctionCodeBlock : public CodeBlock { @@ -1534,8 +1461,8 @@ namespace JSC { { } - FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, bool isConstructor, PassOwnPtr<CodeBlock> alternative = nullptr) - : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, isConstructor, alternative) + FunctionCodeBlock(FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative = nullptr) + : CodeBlock(ownerExecutable, unlinkedCodeBlock, globalObject, 0, sourceProvider, sourceOffset, alternative) { } diff --git a/Source/JavaScriptCore/bytecode/DFGExitProfile.h b/Source/JavaScriptCore/bytecode/DFGExitProfile.h index 57fb06bda..60d313ad4 100644 --- a/Source/JavaScriptCore/bytecode/DFGExitProfile.h +++ b/Source/JavaScriptCore/bytecode/DFGExitProfile.h @@ -36,6 +36,7 @@ enum ExitKind { ExitKindUnset, BadType, // We exited because a type prediction was wrong. BadCache, // We exited because an inline cache was wrong. + BadWeakConstantCache, // We exited because a cache on a weak constant (usually a prototype) was wrong. BadIndexingType, // We exited because an indexing type was wrong. Overflow, // We exited because of overflow. NegativeZero, // We exited because we encountered negative zero. @@ -55,6 +56,8 @@ inline const char* exitKindToString(ExitKind kind) return "BadType"; case BadCache: return "BadCache"; + case BadWeakConstantCache: + return "BadWeakConstantCache"; case Overflow: return "Overflow"; case NegativeZero: diff --git a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp index e44568a26..605a81c2f 100644 --- a/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp +++ b/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp @@ -41,9 +41,6 @@ GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned #if ENABLE(LLINT) Instruction* instruction = profiledBlock->instructions().begin() + bytecodeIndex; - if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_method_check)) - instruction++; - if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_get_array_length)) return GetByIdStatus(NoInformation, false); diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp deleted file mode 100644 index 1fcf5850f..000000000 --- a/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MethodCallLinkInfo.h" - -#if ENABLE(JIT) - -#include "JITStubs.h" -#include "RepatchBuffer.h" - -namespace JSC { - -void MethodCallLinkInfo::reset(RepatchBuffer& repatchBuffer, JITCode::JITType jitType) -{ - cachedStructure.clearToMaxUnsigned(); - cachedPrototype.clear(); - cachedPrototypeStructure.clearToMaxUnsigned(); - cachedFunction.clear(); - - ASSERT_UNUSED(jitType, jitType == JITCode::BaselineJIT); - - repatchBuffer.relink(callReturnLocation, cti_op_get_by_id_method_check); -} - -} // namespace JSC - -#endif // ENABLE(JIT) diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h b/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h deleted file mode 100644 index 2243bc24e..000000000 --- a/Source/JavaScriptCore/bytecode/MethodCallLinkInfo.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MethodCallLinkInfo_h -#define MethodCallLinkInfo_h - -#include "CodeLocation.h" -#include "JITCode.h" -#include "JITWriteBarrier.h" -#include <wtf/Platform.h> - -namespace JSC { - -#if ENABLE(JIT) - -class RepatchBuffer; - -struct MethodCallLinkInfo { - MethodCallLinkInfo() - : seen(false) - { - } - - bool seenOnce() - { - return seen; - } - - void setSeen() - { - seen = true; - } - - void reset(RepatchBuffer&, JITCode::JITType); - - unsigned bytecodeIndex; - CodeLocationCall callReturnLocation; - JITWriteBarrier<Structure> cachedStructure; - JITWriteBarrier<Structure> cachedPrototypeStructure; - // We'd like this to actually be JSFunction, but InternalFunction and JSFunction - // don't have a common parent class and we allow specialisation on both - JITWriteBarrier<JSObject> cachedFunction; - JITWriteBarrier<JSObject> cachedPrototype; - bool seen; -}; - -inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) -{ - return methodCallLinkInfo->callReturnLocation.executableAddress(); -} - -inline unsigned getMethodCallLinkInfoBytecodeIndex(MethodCallLinkInfo* methodCallLinkInfo) -{ - return methodCallLinkInfo->bytecodeIndex; -} - -#endif // ENABLE(JIT) - -} // namespace JSC - -#endif // MethodCallLinkInfo_h diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp deleted file mode 100644 index 795b41b69..000000000 --- a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "MethodCallLinkStatus.h" - -#include "CodeBlock.h" - -namespace JSC { - -MethodCallLinkStatus MethodCallLinkStatus::computeFor(CodeBlock* profiledBlock, unsigned bytecodeIndex) -{ - UNUSED_PARAM(profiledBlock); - UNUSED_PARAM(bytecodeIndex); -#if ENABLE(JIT) && ENABLE(VALUE_PROFILER) - // NOTE: This does not have an LLInt fall-back because LLInt does not do any method - // call link caching. - if (!profiledBlock->numberOfMethodCallLinkInfos()) - return MethodCallLinkStatus(); - - MethodCallLinkInfo& methodCall = profiledBlock->getMethodCallLinkInfo(bytecodeIndex); - - if (!methodCall.seen || !methodCall.cachedStructure) - return MethodCallLinkStatus(); - - if (methodCall.cachedPrototype.get() == profiledBlock->globalObject()->methodCallDummy()) { - return MethodCallLinkStatus( - methodCall.cachedStructure.get(), - 0, - methodCall.cachedFunction.get(), - 0); - } - - return MethodCallLinkStatus( - methodCall.cachedStructure.get(), - methodCall.cachedPrototypeStructure.get(), - methodCall.cachedFunction.get(), - methodCall.cachedPrototype.get()); -#else // ENABLE(JIT) - return MethodCallLinkStatus(); -#endif // ENABLE(JIT) -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h b/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h deleted file mode 100644 index c3d11a1d8..000000000 --- a/Source/JavaScriptCore/bytecode/MethodCallLinkStatus.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2012 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef MethodCallLinkStatus_h -#define MethodCallLinkStatus_h - -namespace JSC { - -class CodeBlock; -class JSObject; -class Structure; - -class MethodCallLinkStatus { -public: - MethodCallLinkStatus() - : m_structure(0) - , m_prototypeStructure(0) - , m_function(0) - , m_prototype(0) - { - } - - MethodCallLinkStatus( - Structure* structure, - Structure* prototypeStructure, - JSObject* function, - JSObject* prototype) - : m_structure(structure) - , m_prototypeStructure(prototypeStructure) - , m_function(function) - , m_prototype(prototype) - { - if (!m_function) { - ASSERT(!m_structure); - ASSERT(!m_prototypeStructure); - ASSERT(!m_prototype); - } else - ASSERT(m_structure); - - ASSERT(!m_prototype == !m_prototypeStructure); - } - - static MethodCallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex); - - bool isSet() const { return !!m_function; } - bool operator!() const { return !m_function; } - - bool needsPrototypeCheck() const { return !!m_prototype; } - - Structure* structure() { return m_structure; } - Structure* prototypeStructure() { return m_prototypeStructure; } - JSObject* function() const { return m_function; } - JSObject* prototype() const { return m_prototype; } - -private: - Structure* m_structure; - Structure* m_prototypeStructure; - JSObject* m_function; - JSObject* m_prototype; -}; - -} // namespace JSC - -#endif // MethodCallLinkStatus_h - diff --git a/Source/JavaScriptCore/bytecode/Opcode.h b/Source/JavaScriptCore/bytecode/Opcode.h index 3ce56c80e..8979d0b7b 100644 --- a/Source/JavaScriptCore/bytecode/Opcode.h +++ b/Source/JavaScriptCore/bytecode/Opcode.h @@ -118,7 +118,8 @@ namespace JSC { macro(op_put_to_base, 5) \ macro(op_put_to_base_variable, 5) \ \ - macro(op_init_global_const, 3) \ + macro(op_init_global_const_nop, 5) \ + macro(op_init_global_const, 5) \ macro(op_init_global_const_check, 5) \ macro(op_get_by_id, 9) /* has value profiling */ \ macro(op_get_by_id_out_of_line, 9) /* has value profiling */ \ @@ -190,7 +191,6 @@ namespace JSC { macro(op_ret, 2) \ macro(op_call_put_result, 3) /* has value profiling */ \ macro(op_ret_object_or_this, 3) \ - macro(op_method_check, 1) \ \ macro(op_construct, 6) \ macro(op_strcat, 4) \ @@ -205,7 +205,7 @@ namespace JSC { \ macro(op_catch, 2) \ macro(op_throw, 2) \ - macro(op_throw_reference_error, 2) \ + macro(op_throw_static_error, 3) \ \ macro(op_debug, 5) \ macro(op_profile_will_call, 2) \ diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h index 9d2c61ae8..09ba9fdfa 100644 --- a/Source/JavaScriptCore/bytecode/SpeculatedType.h +++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h @@ -284,6 +284,11 @@ inline bool mergeSpeculation(T& left, SpeculatedType right) return result; } +inline bool speculationChecked(SpeculatedType actual, SpeculatedType desired) +{ + return (actual | desired) == desired; +} + SpeculatedType speculationFromClassInfo(const ClassInfo*); SpeculatedType speculationFromStructure(Structure*); SpeculatedType speculationFromCell(JSCell*); diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp new file mode 100644 index 000000000..8aa48404a --- /dev/null +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2012 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "UnlinkedCodeBlock.h" + +#include "BytecodeGenerator.h" +#include "ClassInfo.h" +#include "CodeCache.h" +#include "Executable.h" +#include "JSString.h" +#include "SourceProvider.h" +#include "Structure.h" +#include "SymbolTable.h" + +namespace JSC { + +const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutable", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionExecutable) }; +const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) }; +const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) }; +const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) }; +const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) }; +const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) }; + +unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v) +{ + unsigned numberOfConstants = numberOfConstantRegisters(); + for (unsigned i = 0; i < numberOfConstants; ++i) { + if (getConstant(FirstConstantRegisterIndex + i) == v) + return i; + } + return addConstant(v); +} + +UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(JSGlobalData* globalData, Structure* structure, const SourceCode& source, FunctionBodyNode* node) + : Base(*globalData, structure) + , m_numCapturedVariables(node->capturedVariableCount()) + , m_forceUsesArguments(node->usesArguments()) + , m_isInStrictContext(node->isStrictMode()) + , m_hasCapturedVariables(node->hasCapturedVariables()) + , m_name(node->ident()) + , m_inferredName(node->inferredName()) + , m_parameters(node->parameters()) + , m_firstLineOffset(node->firstLine() - source.firstLine()) + , m_lineCount(node->lastLine() - node->firstLine()) + , m_startOffset(node->source().startOffset() - source.startOffset()) + , m_sourceLength(node->source().length()) + , m_features(node->features()) + , m_functionNameIsInScopeToggle(node->functionNameIsInScopeToggle()) +{ +} + +void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + UnlinkedFunctionExecutable* thisObject = jsCast<UnlinkedFunctionExecutable*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_codeBlockForCall); + visitor.append(&thisObject->m_codeBlockForConstruct); + visitor.append(&thisObject->m_nameValue); + visitor.append(&thisObject->m_symbolTableForCall); + visitor.append(&thisObject->m_symbolTableForConstruct); +} + +FunctionExecutable* UnlinkedFunctionExecutable::link(JSGlobalData& globalData, const SourceCode& source, size_t lineOffset, size_t sourceOffset) +{ + unsigned firstLine = lineOffset + m_firstLineOffset; + unsigned startOffset = sourceOffset + m_startOffset; + SourceCode code(source.provider(), startOffset, startOffset + m_sourceLength, firstLine); + return FunctionExecutable::create(globalData, code, this, firstLine, firstLine + m_lineCount); +} + +UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger*, const SourceCode& source, JSObject** exception) +{ + ParserError error; + CodeCache* codeCache = exec->globalData().codeCache(); + UnlinkedFunctionExecutable* executable = codeCache->getFunctionExecutableFromGlobalCode(exec->globalData(), name, source, error); + if (error.m_type != ParserError::ErrorNone) { + *exception = error.toErrorObject(exec->lexicalGlobalObject(), source); + return 0; + } + + return executable; +} + +UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(JSGlobalData& globalData, const SourceCode& source, CodeSpecializationKind specializationKind, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +{ + switch (specializationKind) { + case CodeForCall: + if (m_codeBlockForCall) + return m_codeBlockForCall.get(); + break; + case CodeForConstruct: + if (m_codeBlockForConstruct) + return m_codeBlockForConstruct.get(); + break; + } + + UnlinkedFunctionCodeBlock* result = globalData.codeCache()->getFunctionCodeBlock(globalData, this, source, specializationKind, debuggerMode, profilerMode, error); + + if (error.m_type != ParserError::ErrorNone) + return 0; + + switch (specializationKind) { + case CodeForCall: + m_codeBlockForCall.set(globalData, this, result); + m_symbolTableForCall.set(globalData, this, result->symbolTable()); + break; + case CodeForConstruct: + m_codeBlockForConstruct.set(globalData, this, result); + m_symbolTableForConstruct.set(globalData, this, result->symbolTable()); + break; + } + return result; +} + +String UnlinkedFunctionExecutable::paramString() const +{ + FunctionParameters& parameters = *m_parameters; + StringBuilder builder; + for (size_t pos = 0; pos < parameters.size(); ++pos) { + if (!builder.isEmpty()) + builder.appendLiteral(", "); + builder.append(parameters[pos].string()); + } + return builder.toString(); +} + +UnlinkedCodeBlock::UnlinkedCodeBlock(JSGlobalData* globalData, Structure* structure, CodeType codeType, const ExecutableInfo& info) + : Base(*globalData, structure) + , m_numVars(0) + , m_numCalleeRegisters(0) + , m_numParameters(0) + , m_globalData(globalData) + , m_argumentsRegister(-1) + , m_needsFullScopeChain(info.m_needsActivation) + , m_usesEval(info.m_usesEval) + , m_isNumericCompareFunction(false) + , m_isStrictMode(info.m_isStrictMode) + , m_isConstructor(info.m_isConstructor) + , m_hasCapturedVariables(false) + , m_firstLine(0) + , m_lineCount(0) + , m_features(0) + , m_codeType(codeType) + , m_resolveOperationCount(0) + , m_putToBaseOperationCount(1) + , m_arrayProfileCount(0) + , m_valueProfileCount(0) + , m_llintCallLinkInfoCount(0) +#if ENABLE(BYTECODE_COMMENTS) + , m_bytecodeCommentIterator(0) +#endif +{ + +} + +void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_symbolTable); + for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr) + visitor.append(ptr); + for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr) + visitor.append(ptr); + visitor.appendValues(thisObject->m_constantRegisters.data(), thisObject->m_constantRegisters.size()); + if (thisObject->m_rareData) { + for (size_t i = 0, end = thisObject->m_rareData->m_regexps.size(); i != end; i++) + visitor.append(&thisObject->m_rareData->m_regexps[i]); + } +} + +int UnlinkedCodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset) +{ + ASSERT(bytecodeOffset < instructions().size()); + Vector<LineInfo>& lineInfo = m_lineInfo; + + int low = 0; + int high = lineInfo.size(); + while (low < high) { + int mid = low + (high - low) / 2; + if (lineInfo[mid].instructionOffset <= bytecodeOffset) + low = mid + 1; + else + high = mid; + } + + if (!low) + return 0; + return lineInfo[low - 1].lineNumber; +} + +void UnlinkedCodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset) +{ + ASSERT(bytecodeOffset < instructions().size()); + + if (!m_expressionInfo.size()) { + startOffset = 0; + endOffset = 0; + divot = 0; + return; + } + + Vector<ExpressionRangeInfo>& expressionInfo = m_expressionInfo; + + int low = 0; + int high = expressionInfo.size(); + while (low < high) { + int mid = low + (high - low) / 2; + if (expressionInfo[mid].instructionOffset <= bytecodeOffset) + low = mid + 1; + else + high = mid; + } + + ASSERT(low); + if (!low) { + startOffset = 0; + endOffset = 0; + divot = 0; + return; + } + + startOffset = expressionInfo[low - 1].startOffset; + endOffset = expressionInfo[low - 1].endOffset; + divot = expressionInfo[low - 1].divotPoint; +} + +void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + UnlinkedProgramCodeBlock* thisObject = jsCast<UnlinkedProgramCodeBlock*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + Base::visitChildren(thisObject, visitor); + for (size_t i = 0, end = thisObject->m_functionDeclarations.size(); i != end; i++) + visitor.append(&thisObject->m_functionDeclarations[i].second); +} + +UnlinkedCodeBlock::~UnlinkedCodeBlock() +{ +} + +void UnlinkedProgramCodeBlock::destroy(JSCell* cell) +{ + jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock(); +} + +void UnlinkedEvalCodeBlock::destroy(JSCell* cell) +{ + jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock(); +} + +void UnlinkedFunctionCodeBlock::destroy(JSCell* cell) +{ + jsCast<UnlinkedFunctionCodeBlock*>(cell)->~UnlinkedFunctionCodeBlock(); +} + +void UnlinkedFunctionExecutable::destroy(JSCell* cell) +{ + jsCast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable(); +} + +} + diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h new file mode 100644 index 000000000..bf3f5fdff --- /dev/null +++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2012 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UnlinkedCodeBlock_h +#define UnlinkedCodeBlock_h + +#include "BytecodeConventions.h" +#include "CodeSpecializationKind.h" +#include "CodeType.h" +#include "ExpressionRangeInfo.h" +#include "Identifier.h" +#include "JSCell.h" +#include "LineInfo.h" +#include "Nodes.h" +#include "RegExp.h" +#include "SpecialPointer.h" + +#include <wtf/RefCountedArray.h> +#include <wtf/Vector.h> + +namespace JSC { + +class Debugger; +class FunctionBodyNode; +class FunctionExecutable; +class FunctionParameters; +struct ParserError; +class ScriptExecutable; +class SourceCode; +class SourceProvider; +class SharedSymbolTable; +class UnlinkedCodeBlock; +class UnlinkedFunctionCodeBlock; + +typedef unsigned UnlinkedValueProfile; +typedef unsigned UnlinkedArrayProfile; +typedef unsigned UnlinkedLLIntCallLinkInfo; + +struct ExecutableInfo { + ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor) + : m_needsActivation(needsActivation) + , m_usesEval(usesEval) + , m_isStrictMode(isStrictMode) + , m_isConstructor(isConstructor) + { + } + bool m_needsActivation; + bool m_usesEval; + bool m_isStrictMode; + bool m_isConstructor; +}; + +class UnlinkedFunctionExecutable : public JSCell { +public: + friend class CodeCache; + typedef JSCell Base; + static UnlinkedFunctionExecutable* create(JSGlobalData* globalData, const SourceCode& source, FunctionBodyNode* node) + { + UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(globalData->heap)) UnlinkedFunctionExecutable(globalData, globalData->unlinkedFunctionExecutableStructure.get(), source, node); + instance->finishCreation(*globalData); + return instance; + } + + const Identifier& name() const { return m_name; } + const Identifier& inferredName() const { return m_inferredName; } + JSString* nameValue() const { return m_nameValue.get(); } + SharedSymbolTable* symbolTable(CodeSpecializationKind kind) + { + return (kind == CodeForCall) ? m_symbolTableForCall.get() : m_symbolTableForConstruct.get(); + } + size_t parameterCount() const { return m_parameters->size(); } + bool isInStrictContext() const { return m_isInStrictContext; } + FunctionNameIsInScopeToggle functionNameIsInScopeToggle() const { return m_functionNameIsInScopeToggle; } + + unsigned firstLineOffset() const { return m_firstLineOffset; } + unsigned lineCount() const { return m_lineCount; } + unsigned startOffset() const { return m_startOffset; } + unsigned sourceLength() { return m_sourceLength; } + + String paramString() const; + + UnlinkedFunctionCodeBlock* codeBlockFor(JSGlobalData&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, ParserError&); + + static UnlinkedFunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); + + FunctionExecutable* link(JSGlobalData&, const SourceCode&, size_t lineOffset, size_t sourceOffset); + + void clearCode() + { + m_symbolTableForCall.clear(); + m_symbolTableForConstruct.clear(); + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); + } + + FunctionParameters* parameters() { return m_parameters.get(); } + + void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine) + { + m_features = features; + m_hasCapturedVariables = hasCapturedVariables; + m_lineCount = lastLine - firstLine; + } + + bool forceUsesArguments() const { return m_forceUsesArguments; } + + CodeFeatures features() const { return m_features; } + bool hasCapturedVariables() const { return m_hasCapturedVariables; } + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + +private: + UnlinkedFunctionExecutable(JSGlobalData*, Structure*, const SourceCode&, FunctionBodyNode*); + WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall; + WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct; + + unsigned m_numCapturedVariables : 29; + bool m_forceUsesArguments : 1; + bool m_isInStrictContext : 1; + bool m_hasCapturedVariables : 1; + + Identifier m_name; + Identifier m_inferredName; + WriteBarrier<JSString> m_nameValue; + WriteBarrier<SharedSymbolTable> m_symbolTableForCall; + WriteBarrier<SharedSymbolTable> m_symbolTableForConstruct; + RefPtr<FunctionParameters> m_parameters; + unsigned m_firstLineOffset; + unsigned m_lineCount; + unsigned m_startOffset; + unsigned m_sourceLength; + + CodeFeatures m_features; + + FunctionNameIsInScopeToggle m_functionNameIsInScopeToggle; + +protected: + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + m_nameValue.set(globalData, this, jsString(&globalData, name().string())); + } + + static void visitChildren(JSCell*, SlotVisitor&); + +public: + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(globalData, globalObject, proto, TypeInfo(UnlinkedFunctionExecutableType, StructureFlags), &s_info); + } + + static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; + + static const ClassInfo s_info; +}; + +struct UnlinkedStringJumpTable { + typedef HashMap<RefPtr<StringImpl>, int32_t> StringOffsetTable; + StringOffsetTable offsetTable; + + inline int32_t offsetForValue(StringImpl* value, int32_t defaultOffset) + { + StringOffsetTable::const_iterator end = offsetTable.end(); + StringOffsetTable::const_iterator loc = offsetTable.find(value); + if (loc == end) + return defaultOffset; + return loc->value; + } + +}; + +struct UnlinkedSimpleJumpTable { + Vector<int32_t> branchOffsets; + int32_t min; + + int32_t offsetForValue(int32_t value, int32_t defaultOffset); + void add(int32_t key, int32_t offset) + { + if (!branchOffsets[key]) + branchOffsets[key] = offset; + } +}; + +struct UnlinkedHandlerInfo { + uint32_t start; + uint32_t end; + uint32_t target; + uint32_t scopeDepth; +}; + +struct UnlinkedInstruction { + UnlinkedInstruction() { u.operand = 0; } + UnlinkedInstruction(OpcodeID opcode) { u.opcode = opcode; } + UnlinkedInstruction(int operand) { u.operand = operand; } + union { + OpcodeID opcode; + int32_t operand; + } u; +}; + +class UnlinkedCodeBlock : public JSCell { +public: + typedef JSCell Base; + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + + enum { CallFunction, ApplyFunction }; + + bool isConstructor() const { return m_isConstructor; } + bool isStrictMode() const { return m_isStrictMode; } + bool usesEval() const { return m_usesEval; } + + bool needsFullScopeChain() const { return m_needsFullScopeChain; } + void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } + + void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) + { + m_expressionInfo.append(expressionInfo); + } + + void addLineInfo(unsigned bytecodeOffset, int lineNo) + { + Vector<LineInfo>& lineInfo = m_lineInfo; + if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) { + LineInfo info = { bytecodeOffset, lineNo }; + lineInfo.append(info); + } + } + + bool hasExpressionInfo() { return m_expressionInfo.size(); } + + // Special registers + void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } + void setActivationRegister(int activationRegister) { m_activationRegister = activationRegister; } + + void setArgumentsRegister(int argumentsRegister) { m_argumentsRegister = argumentsRegister; } + bool usesArguments() const { return m_argumentsRegister != -1; } + int argumentsRegister() const { return m_argumentsRegister; } + + // Parameter information + void setNumParameters(int newValue) { m_numParameters = newValue; } + void addParameter() { m_numParameters++; } + unsigned numParameters() const { return m_numParameters; } + + unsigned addRegExp(RegExp* r) + { + createRareDataIfNecessary(); + unsigned size = m_rareData->m_regexps.size(); + m_rareData->m_regexps.append(WriteBarrier<RegExp>(*m_globalData, this, r)); + return size; + } + unsigned numberOfRegExps() const + { + if (!m_rareData) + return 0; + return m_rareData->m_regexps.size(); + } + RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } + + // Constant Pools + + size_t numberOfIdentifiers() const { return m_identifiers.size(); } + void addIdentifier(const Identifier& i) { return m_identifiers.append(i); } + const Identifier& identifier(int index) const { return m_identifiers[index]; } + const Vector<Identifier>& identifiers() const { return m_identifiers; } + + size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } + unsigned addConstant(JSValue v) + { + unsigned result = m_constantRegisters.size(); + m_constantRegisters.append(WriteBarrier<Unknown>()); + m_constantRegisters.last().set(*m_globalData, this, v); + return result; + } + unsigned addOrFindConstant(JSValue); + const Vector<WriteBarrier<Unknown> >& constantRegisters() { return m_constantRegisters; } + const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; } + ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } + ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } + + // Jumps + size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } + void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } + unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } + unsigned lastJumpTarget() const { return m_jumpTargets.last(); } + + void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } + bool isNumericCompareFunction() const { return m_isNumericCompareFunction; } + + void shrinkToFit() + { + m_jumpTargets.shrinkToFit(); + m_identifiers.shrinkToFit(); + m_constantRegisters.shrinkToFit(); + m_functionDecls.shrinkToFit(); + m_functionExprs.shrinkToFit(); + m_lineInfo.shrinkToFit(); + m_propertyAccessInstructions.shrinkToFit(); + m_expressionInfo.shrinkToFit(); + +#if ENABLE(BYTECODE_COMMENTS) + m_bytecodeComments.shrinkToFit(); +#endif + if (m_rareData) { + m_rareData->m_exceptionHandlers.shrinkToFit(); + m_rareData->m_regexps.shrinkToFit(); + m_rareData->m_constantBuffers.shrinkToFit(); + m_rareData->m_immediateSwitchJumpTables.shrinkToFit(); + m_rareData->m_characterSwitchJumpTables.shrinkToFit(); + m_rareData->m_stringSwitchJumpTables.shrinkToFit(); + } + } + + unsigned numberOfInstructions() const { return m_unlinkedInstructions.size(); } + RefCountedArray<UnlinkedInstruction>& instructions() { return m_unlinkedInstructions; } + const RefCountedArray<UnlinkedInstruction>& instructions() const { return m_unlinkedInstructions; } + + int m_numVars; + int m_numCapturedVars; + int m_numCalleeRegisters; + + // Jump Tables + + size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; } + UnlinkedSimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(UnlinkedSimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); } + UnlinkedSimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; } + + size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; } + UnlinkedSimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(UnlinkedSimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); } + UnlinkedSimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; } + + size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; } + UnlinkedStringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(UnlinkedStringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } + UnlinkedStringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } + + unsigned addFunctionDecl(UnlinkedFunctionExecutable* n) + { + unsigned size = m_functionDecls.size(); + m_functionDecls.append(WriteBarrier<UnlinkedFunctionExecutable>()); + m_functionDecls.last().set(*m_globalData, this, n); + return size; + } + UnlinkedFunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } + size_t numberOfFunctionDecls() { return m_functionDecls.size(); } + unsigned addFunctionExpr(UnlinkedFunctionExecutable* n) + { + unsigned size = m_functionExprs.size(); + m_functionExprs.append(WriteBarrier<UnlinkedFunctionExecutable>()); + m_functionExprs.last().set(*m_globalData, this, n); + return size; + } + UnlinkedFunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } + size_t numberOfFunctionExprs() { return m_functionExprs.size(); } + + // Exception handling support + size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } + void addExceptionHandler(const UnlinkedHandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } + UnlinkedHandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } + + SharedSymbolTable* symbolTable() const { return m_symbolTable.get(); } + + JSGlobalData* globalData() const { return m_globalData; } + + unsigned addResolve() { return m_resolveOperationCount++; } + unsigned numberOfResolveOperations() const { return m_resolveOperationCount; } + unsigned addPutToBase() { return m_putToBaseOperationCount++; } + unsigned numberOfPutToBaseOperations() const { return m_putToBaseOperationCount; } + + UnlinkedArrayProfile addArrayProfile() { return m_arrayProfileCount++; } + unsigned numberOfArrayProfiles() { return m_arrayProfileCount; } + UnlinkedValueProfile addValueProfile() { return m_valueProfileCount++; } + unsigned numberOfValueProfiles() { return m_valueProfileCount; } + + UnlinkedLLIntCallLinkInfo addLLIntCallLinkInfo() { return m_llintCallLinkInfoCount++; } + unsigned numberOfLLintCallLinkInfos() { return m_llintCallLinkInfoCount; } + + CodeType codeType() const { return m_codeType; } + + int thisRegister() const { return m_thisRegister; } + int activationRegister() const { return m_activationRegister; } + + + void addPropertyAccessInstruction(unsigned propertyAccessInstruction) + { + m_propertyAccessInstructions.append(propertyAccessInstruction); + } + + size_t numberOfPropertyAccessInstructions() const { return m_propertyAccessInstructions.size(); } + const Vector<unsigned>& propertyAccessInstructions() const { return m_propertyAccessInstructions; } + + typedef Vector<JSValue> ConstantBuffer; + + size_t constantBufferCount() { ASSERT(m_rareData); return m_rareData->m_constantBuffers.size(); } + unsigned addConstantBuffer(unsigned length) + { + createRareDataIfNecessary(); + unsigned size = m_rareData->m_constantBuffers.size(); + m_rareData->m_constantBuffers.append(Vector<JSValue>(length)); + return size; + } + + const ConstantBuffer& constantBuffer(unsigned index) const + { + ASSERT(m_rareData); + return m_rareData->m_constantBuffers[index]; + } + + ConstantBuffer& constantBuffer(unsigned index) + { + ASSERT(m_rareData); + return m_rareData->m_constantBuffers[index]; + } + + bool hasRareData() const { return m_rareData; } + + int lineNumberForBytecodeOffset(unsigned bytecodeOffset); + + void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); + + void recordParse(CodeFeatures features, bool hasCapturedVariables, unsigned firstLine, unsigned lineCount) + { + m_features = features; + m_hasCapturedVariables = hasCapturedVariables; + m_firstLine = firstLine; + m_lineCount = lineCount; + } + + CodeFeatures codeFeatures() const { return m_features; } + bool hasCapturedVariables() const { return m_hasCapturedVariables; } + unsigned firstLine() const { return m_firstLine; } + unsigned lineCount() const { return m_lineCount; } + +protected: + UnlinkedCodeBlock(JSGlobalData*, Structure*, CodeType, const ExecutableInfo&); + ~UnlinkedCodeBlock(); + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + if (codeType() == GlobalCode) + return; + m_symbolTable.set(globalData, this, SharedSymbolTable::create(globalData)); + } + +private: + + void createRareDataIfNecessary() + { + if (!m_rareData) + m_rareData = adoptPtr(new RareData); + } + + RefCountedArray<UnlinkedInstruction> m_unlinkedInstructions; + + int m_numParameters; + JSGlobalData* m_globalData; + + int m_thisRegister; + int m_argumentsRegister; + int m_activationRegister; + + bool m_needsFullScopeChain : 1; + bool m_usesEval : 1; + bool m_isNumericCompareFunction : 1; + bool m_isStrictMode : 1; + bool m_isConstructor : 1; + bool m_hasCapturedVariables : 1; + unsigned m_firstLine; + unsigned m_lineCount; + + CodeFeatures m_features; + CodeType m_codeType; + + Vector<unsigned> m_jumpTargets; + + // Constant Pools + Vector<Identifier> m_identifiers; + Vector<WriteBarrier<Unknown> > m_constantRegisters; + typedef Vector<WriteBarrier<UnlinkedFunctionExecutable> > FunctionExpressionVector; + FunctionExpressionVector m_functionDecls; + FunctionExpressionVector m_functionExprs; + + WriteBarrier<SharedSymbolTable> m_symbolTable; + + Vector<LineInfo> m_lineInfo; + + Vector<unsigned> m_propertyAccessInstructions; + +#if ENABLE(BYTECODE_COMMENTS) + Vector<Comment> m_bytecodeComments; + size_t m_bytecodeCommentIterator; +#endif + + unsigned m_resolveOperationCount; + unsigned m_putToBaseOperationCount; + unsigned m_arrayProfileCount; + unsigned m_valueProfileCount; + unsigned m_llintCallLinkInfoCount; + +public: + struct RareData { + WTF_MAKE_FAST_ALLOCATED; + public: + Vector<UnlinkedHandlerInfo> m_exceptionHandlers; + + // Rare Constants + Vector<WriteBarrier<RegExp> > m_regexps; + + // Buffers used for large array literals + Vector<ConstantBuffer> m_constantBuffers; + + // Jump Tables + Vector<UnlinkedSimpleJumpTable> m_immediateSwitchJumpTables; + Vector<UnlinkedSimpleJumpTable> m_characterSwitchJumpTables; + Vector<UnlinkedStringJumpTable> m_stringSwitchJumpTables; + + // Expression info - present if debugging. + }; + +private: + OwnPtr<RareData> m_rareData; + Vector<ExpressionRangeInfo> m_expressionInfo; + +protected: + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + static void visitChildren(JSCell*, SlotVisitor&); + +public: + static const ClassInfo s_info; +}; + +class UnlinkedGlobalCodeBlock : public UnlinkedCodeBlock { +public: + typedef UnlinkedCodeBlock Base; + +protected: + UnlinkedGlobalCodeBlock(JSGlobalData* globalData, Structure* structure, CodeType codeType, const ExecutableInfo& info) + : Base(globalData, structure, codeType, info) + { + } + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + static const ClassInfo s_info; +}; + +class UnlinkedProgramCodeBlock : public UnlinkedGlobalCodeBlock { +private: + friend class CodeCache; + static UnlinkedProgramCodeBlock* create(JSGlobalData* globalData, const ExecutableInfo& info) + { + UnlinkedProgramCodeBlock* instance = new (NotNull, allocateCell<UnlinkedProgramCodeBlock>(globalData->heap)) UnlinkedProgramCodeBlock(globalData, globalData->unlinkedProgramCodeBlockStructure.get(), info); + instance->finishCreation(*globalData); + return instance; + } + +public: + typedef UnlinkedGlobalCodeBlock Base; + static void destroy(JSCell*); + + void addFunctionDeclaration(JSGlobalData& globalData, const Identifier& name, UnlinkedFunctionExecutable* functionExecutable) + { + m_functionDeclarations.append(std::make_pair(name, WriteBarrier<UnlinkedFunctionExecutable>(globalData, this, functionExecutable))); + } + + void addVariableDeclaration(const Identifier& name, bool isConstant) + { + m_varDeclarations.append(std::make_pair(name, isConstant)); + } + + typedef Vector<std::pair<Identifier, bool> > VariableDeclations; + typedef Vector<std::pair<Identifier, WriteBarrier<UnlinkedFunctionExecutable> > > FunctionDeclations; + + const VariableDeclations& variableDeclarations() const { return m_varDeclarations; } + const FunctionDeclations& functionDeclarations() const { return m_functionDeclarations; } + + static void visitChildren(JSCell*, SlotVisitor&); + +private: + UnlinkedProgramCodeBlock(JSGlobalData* globalData, Structure* structure, const ExecutableInfo& info) + : Base(globalData, structure, GlobalCode, info) + { + } + + VariableDeclations m_varDeclarations; + FunctionDeclations m_functionDeclarations; + +public: + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(globalData, globalObject, proto, TypeInfo(UnlinkedProgramCodeBlockType, StructureFlags), &s_info); + } + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + static const ClassInfo s_info; +}; + +class UnlinkedEvalCodeBlock : public UnlinkedGlobalCodeBlock { +private: + friend class CodeCache; + + static UnlinkedEvalCodeBlock* create(JSGlobalData* globalData, const ExecutableInfo& info) + { + UnlinkedEvalCodeBlock* instance = new (NotNull, allocateCell<UnlinkedEvalCodeBlock>(globalData->heap)) UnlinkedEvalCodeBlock(globalData, globalData->unlinkedEvalCodeBlockStructure.get(), info); + instance->finishCreation(*globalData); + return instance; + } + +public: + typedef UnlinkedGlobalCodeBlock Base; + static void destroy(JSCell*); + + const Identifier& variable(unsigned index) { return m_variables[index]; } + unsigned numVariables() { return m_variables.size(); } + void adoptVariables(Vector<Identifier>& variables) + { + ASSERT(m_variables.isEmpty()); + m_variables.swap(variables); + } + +private: + UnlinkedEvalCodeBlock(JSGlobalData* globalData, Structure* structure, const ExecutableInfo& info) + : Base(globalData, structure, EvalCode, info) + { + } + + Vector<Identifier> m_variables; + +public: + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(globalData, globalObject, proto, TypeInfo(UnlinkedEvalCodeBlockType, StructureFlags), &s_info); + } + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + static const ClassInfo s_info; +}; + +class UnlinkedFunctionCodeBlock : public UnlinkedCodeBlock { +private: + friend class CodeCache; + + static UnlinkedFunctionCodeBlock* create(JSGlobalData* globalData, CodeType codeType, const ExecutableInfo& info) + { + UnlinkedFunctionCodeBlock* instance = new (NotNull, allocateCell<UnlinkedFunctionCodeBlock>(globalData->heap)) UnlinkedFunctionCodeBlock(globalData, globalData->unlinkedFunctionCodeBlockStructure.get(), codeType, info); + instance->finishCreation(*globalData); + return instance; + } + +public: + typedef UnlinkedCodeBlock Base; + static void destroy(JSCell*); + +private: + UnlinkedFunctionCodeBlock(JSGlobalData* globalData, Structure* structure, CodeType codeType, const ExecutableInfo& info) + : Base(globalData, structure, codeType, info) + { + } + +public: + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(globalData, globalObject, proto, TypeInfo(UnlinkedFunctionCodeBlockType, StructureFlags), &s_info); + } + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + static const ClassInfo s_info; +}; + +} + +#endif // UnlinkedCodeBlock_h |