X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..217a6308cd6a1dc049a0bb69263bd4c91f91c4d0:/runtime/Executable.cpp?ds=sidebyside diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index 3690c2c..9185376 100644 --- a/runtime/Executable.cpp +++ b/runtime/Executable.cpp @@ -26,15 +26,17 @@ #include "config.h" #include "Executable.h" +#include "BatchedTransitionOptimizer.h" #include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" #include "ExecutionHarness.h" #include "JIT.h" #include "JITDriver.h" +#include "Operations.h" #include "Parser.h" -#include "UStringBuilder.h" #include +#include namespace JSC { @@ -43,11 +45,11 @@ const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_ #if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { - jsCast(cell)->ExecutableBase::~ExecutableBase(); + static_cast(cell)->ExecutableBase::~ExecutableBase(); } #endif -inline void ExecutableBase::clearCode() +void ExecutableBase::clearCode() { #if ENABLE(JIT) m_jitCodeForCall.clear(); @@ -66,6 +68,11 @@ Intrinsic ExecutableBase::intrinsic() const return nativeExecutable->intrinsic(); return NoIntrinsic; } +#else +Intrinsic ExecutableBase::intrinsic() const +{ + return NoIntrinsic; +} #endif const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; @@ -73,7 +80,7 @@ const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase #if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { - jsCast(cell)->NativeExecutable::~NativeExecutable(); + static_cast(cell)->NativeExecutable::~NativeExecutable(); } #endif @@ -87,103 +94,84 @@ Intrinsic NativeExecutable::intrinsic() const #if ENABLE(JIT) // Utility method used for jettisoning code blocks. template -static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr& codeBlock) +static void jettisonCodeBlock(VM& vm, OwnPtr& codeBlock) { ASSERT(JITCode::isOptimizingJIT(codeBlock->getJITType())); ASSERT(codeBlock->alternative()); OwnPtr codeBlockToJettison = codeBlock.release(); codeBlock = static_pointer_cast(codeBlockToJettison->releaseAlternative()); codeBlockToJettison->unlinkIncomingCalls(); - globalData.heap.jettisonDFGCodeBlock(static_pointer_cast(codeBlockToJettison.release())); + vm.heap.jettisonDFGCodeBlock(static_pointer_cast(codeBlockToJettison.release())); } #endif -void NativeExecutable::finalize(JSCell* cell) -{ - jsCast(cell)->clearCode(); -} - const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; #if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { - jsCast(cell)->ScriptExecutable::~ScriptExecutable(); + static_cast(cell)->ScriptExecutable::~ScriptExecutable(); } #endif const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext) +EvalExecutable::EvalExecutable(ExecState* exec, PassRefPtr codeCache, const SourceCode& source, bool inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) + , m_codeCache(codeCache) { } void EvalExecutable::destroy(JSCell* cell) { - jsCast(cell)->EvalExecutable::~EvalExecutable(); + static_cast(cell)->EvalExecutable::~EvalExecutable(); } const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) { } void ProgramExecutable::destroy(JSCell* cell) { - jsCast(cell)->ProgramExecutable::~ProgramExecutable(); + static_cast(cell)->ProgramExecutable::~ProgramExecutable(); } const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) - : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, inStrictContext) - , m_numCapturedVariables(0) - , m_forceUsesArguments(forceUsesArguments) - , m_parameters(parameters) - , m_name(name) - , m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName) - , m_symbolTable(0) - , m_next(0) - , m_prev(0) -{ -} - -FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const Identifier& inferredName, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext) - : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext) - , m_numCapturedVariables(0) - , m_forceUsesArguments(forceUsesArguments) - , m_parameters(parameters) - , m_name(name) - , m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName) - , m_symbolTable(0) - , m_next(0) - , m_prev(0) +FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn) + : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) + , m_unlinkedExecutable(vm, this, unlinkedExecutable) { + RELEASE_ASSERT(!source.isNull()); + ASSERT(source.length()); + m_firstLine = firstLine; + m_lastLine = lastLine; + m_startColumn = startColumn; } void FunctionExecutable::destroy(JSCell* cell) { - jsCast(cell)->FunctionExecutable::~FunctionExecutable(); + static_cast(cell)->FunctionExecutable::~FunctionExecutable(); } -JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* EvalExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_evalCodeBlock); JSObject* error = 0; if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT()) - error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_evalCodeBlock->getJITType())); + error = compileInternal(exec, scope, JITCode::nextTierJIT(m_evalCodeBlock->getJITType()), bytecodeIndex); ASSERT(!!m_evalCodeBlock); return error; } #if ENABLE(JIT) -bool EvalExecutable::jitCompile(JSGlobalData& globalData) +bool EvalExecutable::jitCompile(ExecState* exec) { - return jitCompileIfAppropriate(globalData, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileIfAppropriate(exec, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif @@ -197,20 +185,20 @@ inline const char* samplingDescription(JITCode::JITType jitType) case JITCode::DFGJIT: return "DFG Compilation (TOTAL)"; default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return 0; } } -JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); #endif - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); + VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); if (!!m_evalCodeBlock) { @@ -218,42 +206,30 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope newCodeBlock->setAlternative(static_pointer_cast(m_evalCodeBlock.release())); m_evalCodeBlock = newCodeBlock.release(); } else { + UNUSED_PARAM(scope); + UNUSED_PARAM(vm); + UNUSED_PARAM(lexicalGlobalObject); if (!lexicalGlobalObject->evalEnabled()) - return throwError(exec, createEvalError(exec, "Eval is disabled")); - RefPtr evalNode = parse(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); - if (!evalNode) { - ASSERT(exception); + return throwError(exec, createEvalError(exec, lexicalGlobalObject->evalDisabledErrorMessage())); + + JSObject* exception = 0; + UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(m_codeCache.get(), exec, scope, this, &exception); + if (!unlinkedEvalCode) return exception; - } - recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); - - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - + OwnPtr previousCodeBlock = m_evalCodeBlock.release(); ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); - m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth(), previousCodeBlock.release())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation))); - if ((exception = generator->generate())) { - m_evalCodeBlock = static_pointer_cast(m_evalCodeBlock->releaseAlternative()); - evalNode->destroyData(); - return exception; - } - - evalNode->destroyData(); + m_unlinkedEvalCodeBlock.set(*vm, this, unlinkedEvalCode); + m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, unlinkedEvalCode, lexicalGlobalObject, source().provider(), scope->localDepth(), previousCodeBlock.release())); m_evalCodeBlock->copyPostParseDataFromAlternative(); } #if ENABLE(JIT) - if (!prepareForExecution(*globalData, m_evalCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(exec, m_evalCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(CLASSIC_INTERPRETER) - if (!m_jitCodeForCall) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); - else -#endif Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); @@ -263,9 +239,9 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope } #if ENABLE(JIT) -void EvalExecutable::jettisonOptimizedCode(JSGlobalData& globalData) +void EvalExecutable::jettisonOptimizedCode(VM& vm) { - jettisonCodeBlock(globalData, m_evalCodeBlock); + jettisonCodeBlock(vm, m_evalCodeBlock); m_jitCodeForCall = m_evalCodeBlock->getJITCode(); ASSERT(!m_jitCodeForCallWithArityCheck); } @@ -280,6 +256,7 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_evalCodeBlock) thisObject->m_evalCodeBlock->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedEvalCodeBlock); } void EvalExecutable::unlinkCalls() @@ -287,106 +264,74 @@ void EvalExecutable::unlinkCalls() #if ENABLE(JIT) if (!m_jitCodeForCall) return; - ASSERT(m_evalCodeBlock); + RELEASE_ASSERT(m_evalCodeBlock); m_evalCodeBlock->unlinkCalls(); #endif } -void EvalExecutable::finalize(JSCell* cell) +void EvalExecutable::clearCode() { - jsCast(cell)->clearCode(); -} - -inline void EvalExecutable::clearCode() -{ - if (m_evalCodeBlock) { - m_evalCodeBlock->clearEvalCache(); - m_evalCodeBlock.clear(); - } + m_evalCodeBlock.clear(); + m_unlinkedEvalCodeBlock.clear(); Base::clearCode(); } JSObject* ProgramExecutable::checkSyntax(ExecState* exec) { - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); + ParserError error; + VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr programNode = parse(globalData, lexicalGlobalObject, m_source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); + RefPtr programNode = parse(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); if (programNode) return 0; - ASSERT(exception); - return exception; + ASSERT(error.m_type != ParserError::ErrorNone); + return error.toErrorObject(lexicalGlobalObject, m_source); } -JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* ProgramExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_programCodeBlock); JSObject* error = 0; if (m_programCodeBlock->getJITType() != JITCode::topTierJIT()) - error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_programCodeBlock->getJITType())); + error = compileInternal(exec, scope, JITCode::nextTierJIT(m_programCodeBlock->getJITType()), bytecodeIndex); ASSERT(!!m_programCodeBlock); return error; } #if ENABLE(JIT) -bool ProgramExecutable::jitCompile(JSGlobalData& globalData) +bool ProgramExecutable::jitCompile(ExecState* exec) { - return jitCompileIfAppropriate(globalData, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileIfAppropriate(exec, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif -JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) + UNUSED_PARAM(exec); UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); #endif - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - if (!!m_programCodeBlock) { OwnPtr newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock)); newCodeBlock->setAlternative(static_pointer_cast(m_programCodeBlock.release())); m_programCodeBlock = newCodeBlock.release(); } else { - RefPtr programNode = parse(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); - if (!programNode) { - ASSERT(exception); - return exception; - } - recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); - - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - - OwnPtr previousCodeBlock = m_programCodeBlock.release(); - ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); - m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation))); - if ((exception = generator->generate())) { - m_programCodeBlock = static_pointer_cast(m_programCodeBlock->releaseAlternative()); - programNode->destroyData(); - return exception; - } - - programNode->destroyData(); + JSGlobalObject* globalObject = scope->globalObject(); + m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), source().startColumn(), m_programCodeBlock.release())); m_programCodeBlock->copyPostParseDataFromAlternative(); } #if ENABLE(JIT) - if (!prepareForExecution(*globalData, m_programCodeBlock, m_jitCodeForCall, jitType)) + if (!prepareForExecution(exec, m_programCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(CLASSIC_INTERPRETER) - if (!m_jitCodeForCall) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); - else -#endif - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size()); + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); #endif @@ -395,9 +340,9 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc } #if ENABLE(JIT) -void ProgramExecutable::jettisonOptimizedCode(JSGlobalData& globalData) +void ProgramExecutable::jettisonOptimizedCode(VM& vm) { - jettisonCodeBlock(globalData, m_programCodeBlock); + jettisonCodeBlock(vm, m_programCodeBlock); m_jitCodeForCall = m_programCodeBlock->getJITCode(); ASSERT(!m_jitCodeForCallWithArityCheck); } @@ -408,11 +353,72 @@ void ProgramExecutable::unlinkCalls() #if ENABLE(JIT) if (!m_jitCodeForCall) return; - ASSERT(m_programCodeBlock); + RELEASE_ASSERT(m_programCodeBlock); m_programCodeBlock->unlinkCalls(); #endif } +int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) +{ + // Try to share the symbolTable if possible + SharedSymbolTable* symbolTable = globalObject->symbolTable(); + UNUSED_PARAM(functionMode); + int index = symbolTable->size(); + SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0); + if (functionMode == IsFunctionToSpecialize) + newEntry.attemptToWatch(); + SymbolTable::AddResult result = symbolTable->add(ident.impl(), newEntry); + if (!result.isNewEntry) { + result.iterator->value.notifyWrite(); + index = result.iterator->value.getIndex(); + } + return index; +} + +JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) +{ + RELEASE_ASSERT(scope); + JSGlobalObject* globalObject = scope->globalObject(); + RELEASE_ASSERT(globalObject); + ASSERT(&globalObject->vm() == &vm); + + JSObject* exception = 0; + UnlinkedProgramCodeBlock* unlinkedCode = globalObject->createProgramCodeBlock(callFrame, this, &exception); + if (exception) + return exception; + + m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCode); + + BatchedTransitionOptimizer optimizer(vm, globalObject); + + const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCode->variableDeclarations(); + const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCode->functionDeclarations(); + + size_t newGlobals = variableDeclarations.size() + functionDeclarations.size(); + if (!newGlobals) + return 0; + globalObject->addRegisters(newGlobals); + CallFrame* globalExec = globalObject->globalExec(); + + for (size_t i = 0; i < functionDeclarations.size(); ++i) { + bool propertyDidExist = globalObject->removeDirect(vm, functionDeclarations[i].first); // Newly declared functions overwrite existing properties. + UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); + JSValue value = JSFunction::create(globalExec, unlinkedFunctionExecutable->link(vm, m_source, lineNo(), 0), scope); + int index = addGlobalVar(globalObject, functionDeclarations[i].first, IsVariable, + !propertyDidExist ? IsFunctionToSpecialize : NotFunctionOrNotSpecializable); + globalObject->registerAt(index).set(vm, globalObject, value); + } + + for (size_t i = 0; i < variableDeclarations.size(); ++i) { + if (globalObject->hasProperty(globalExec, variableDeclarations[i].first)) + continue; + addGlobalVar(globalObject, variableDeclarations[i].first, + (variableDeclarations[i].second & DeclarationStacks::IsConstant) ? IsConstant : IsVariable, + NotFunctionOrNotSpecializable); + } + return 0; +} + void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { ProgramExecutable* thisObject = jsCast(cell); @@ -420,21 +426,15 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_unlinkedProgramCodeBlock); if (thisObject->m_programCodeBlock) thisObject->m_programCodeBlock->visitAggregate(visitor); } -void ProgramExecutable::finalize(JSCell* cell) -{ - jsCast(cell)->clearCode(); -} - -inline void ProgramExecutable::clearCode() +void ProgramExecutable::clearCode() { - if (m_programCodeBlock) { - m_programCodeBlock->clearEvalCache(); - m_programCodeBlock.clear(); - } + m_programCodeBlock.clear(); + m_unlinkedProgramCodeBlock.clear(); Base::clearCode(); } @@ -444,90 +444,81 @@ FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKi if (kind == CodeForCall) result = m_codeBlockForCall.get(); else { - ASSERT(kind == CodeForConstruct); + RELEASE_ASSERT(kind == CodeForConstruct); result = m_codeBlockForConstruct.get(); } if (!result) return 0; while (result->alternative()) result = static_cast(result->alternative()); - ASSERT(result); + RELEASE_ASSERT(result); ASSERT(JITCode::isBaselineCode(result->getJITType())); return result; } -JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_codeBlockForCall); JSObject* error = 0; if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT()) - error = compileForCallInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForCall->getJITType())); + error = compileForCallInternal(exec, scope, JITCode::nextTierJIT(m_codeBlockForCall->getJITType()), bytecodeIndex); ASSERT(!!m_codeBlockForCall); return error; } -JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(exec->globalData().dynamicGlobalObject); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); ASSERT(!!m_codeBlockForConstruct); JSObject* error = 0; if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT()) - error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType())); + error = compileForConstructInternal(exec, scope, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()), bytecodeIndex); ASSERT(!!m_codeBlockForConstruct); return error; } #if ENABLE(JIT) -bool FunctionExecutable::jitCompileForCall(JSGlobalData& globalData) +bool FunctionExecutable::jitCompileForCall(ExecState* exec) { - return jitCompileFunctionIfAppropriate(globalData, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } -bool FunctionExecutable::jitCompileForConstruct(JSGlobalData& globalData) +bool FunctionExecutable::jitCompileForConstruct(ExecState* exec) { - return jitCompileFunctionIfAppropriate(globalData, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); } #endif -FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind) -{ - return baselineCodeBlockFor(kind); -} - -PassOwnPtr FunctionExecutable::produceCodeBlockFor(ScopeChainNode* scopeChainNode, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception) +PassOwnPtr FunctionExecutable::produceCodeBlockFor(JSScope* scope, CodeSpecializationKind specializationKind, JSObject*& exception) { if (!!codeBlockFor(specializationKind)) return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind))); - - exception = 0; - JSGlobalData* globalData = scopeChainNode->globalData; - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - RefPtr body = parse(globalData, globalObject, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, 0, 0, &exception); - if (!body) { - ASSERT(exception); + VM* vm = scope->vm(); + JSGlobalObject* globalObject = scope->globalObject(); + ParserError error; + DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; + ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; + UnlinkedFunctionCodeBlock* unlinkedCodeBlock = m_unlinkedExecutable->codeBlockFor(*vm, scope, m_source, specializationKind, debuggerMode, profilerMode, error); + recordParse(m_unlinkedExecutable->features(), m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn()); + + if (!unlinkedCodeBlock) { + exception = error.toErrorObject(globalObject, m_source); return nullptr; } - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name); - recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - - OwnPtr result; - ASSERT((compilationKind == FirstCompilation) == !codeBlockFor(specializationKind)); - result = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), specializationKind == CodeForConstruct)); - OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, result->symbolTable(), result.get(), compilationKind))); - exception = generator->generate(); - body->destroyData(); - if (exception) - return nullptr; + SourceProvider* provider = source().provider(); + unsigned sourceOffset = source().startOffset(); + unsigned startColumn = source().startColumn(); + + OwnPtr result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, provider, sourceOffset, startColumn)); result->copyPostParseDataFrom(codeBlockFor(specializationKind).get()); return result.release(); } -JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) + +JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); @@ -535,10 +526,11 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain UNUSED_PARAM(exec); UNUSED_PARAM(jitType); UNUSED_PARAM(exec); + UNUSED_PARAM(bytecodeIndex); #endif ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall); - JSObject* exception; - OwnPtr newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForCall ? OptimizingCompilation : FirstCompilation, CodeForCall, exception); + JSObject* exception = 0; + OwnPtr newCodeBlock = produceCodeBlockFor(scope, CodeForCall, exception); if (!newCodeBlock) return exception; @@ -546,22 +538,15 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain m_codeBlockForCall = newCodeBlock.release(); m_numParametersForCall = m_codeBlockForCall->numParameters(); - ASSERT(m_numParametersForCall); - m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; - m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); + RELEASE_ASSERT(m_numParametersForCall); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, CodeForCall)) + if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(CLASSIC_INTERPRETER) - if (!m_jitCodeForCall) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); - else -#endif - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); #endif @@ -569,18 +554,19 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain return 0; } -JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { SamplingRegion samplingRegion(samplingDescription(jitType)); #if !ENABLE(JIT) UNUSED_PARAM(jitType); UNUSED_PARAM(exec); + UNUSED_PARAM(bytecodeIndex); #endif ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct); - JSObject* exception; - OwnPtr newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForConstruct ? OptimizingCompilation : FirstCompilation, CodeForConstruct, exception); + JSObject* exception = 0; + OwnPtr newCodeBlock = produceCodeBlockFor(scope, CodeForConstruct, exception); if (!newCodeBlock) return exception; @@ -588,21 +574,14 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope m_codeBlockForConstruct = newCodeBlock.release(); m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); - ASSERT(m_numParametersForConstruct); - m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; - m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); + RELEASE_ASSERT(m_numParametersForConstruct); #if ENABLE(JIT) - if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, CodeForConstruct)) + if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct)) return 0; #endif #if ENABLE(JIT) -#if ENABLE(CLASSIC_INTERPRETER) - if (!m_jitCodeForConstruct) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); - else -#endif Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); @@ -612,16 +591,16 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope } #if ENABLE(JIT) -void FunctionExecutable::jettisonOptimizedCodeForCall(JSGlobalData& globalData) +void FunctionExecutable::jettisonOptimizedCodeForCall(VM& vm) { - jettisonCodeBlock(globalData, m_codeBlockForCall); + jettisonCodeBlock(vm, m_codeBlockForCall); m_jitCodeForCall = m_codeBlockForCall->getJITCode(); m_jitCodeForCallWithArityCheck = m_codeBlockForCall->getJITCodeWithArityCheck(); } -void FunctionExecutable::jettisonOptimizedCodeForConstruct(JSGlobalData& globalData) +void FunctionExecutable::jettisonOptimizedCodeForConstruct(VM& vm) { - jettisonCodeBlock(globalData, m_codeBlockForConstruct); + jettisonCodeBlock(vm, m_codeBlockForConstruct); m_jitCodeForConstruct = m_codeBlockForConstruct->getJITCode(); m_jitCodeForConstructWithArityCheck = m_codeBlockForConstruct->getJITCodeWithArityCheck(); } @@ -634,45 +613,31 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); - if (thisObject->m_nameValue) - visitor.append(&thisObject->m_nameValue); if (thisObject->m_codeBlockForCall) thisObject->m_codeBlockForCall->visitAggregate(visitor); if (thisObject->m_codeBlockForConstruct) thisObject->m_codeBlockForConstruct->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedExecutable); } -void FunctionExecutable::discardCode() +void FunctionExecutable::clearCodeIfNotCompiling() { -#if ENABLE(JIT) - // These first two checks are to handle the rare case where - // we are trying to evict code for a function during its - // codegen. - if (!m_jitCodeForCall && m_codeBlockForCall) - return; - if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + if (isCompiling()) return; -#endif clearCode(); } -void FunctionExecutable::finalize(JSCell* cell) +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() { - FunctionExecutable* executable = jsCast(cell); - Heap::heap(executable)->removeFunctionExecutable(executable); - executable->clearCode(); + if (isCompiling()) + return; + m_unlinkedExecutable->clearCodeForRecompilation(); } -inline void FunctionExecutable::clearCode() +void FunctionExecutable::clearCode() { - if (m_codeBlockForCall) { - m_codeBlockForCall->clearEvalCache(); - m_codeBlockForCall.clear(); - } - if (m_codeBlockForConstruct) { - m_codeBlockForConstruct->clearEvalCache(); - m_codeBlockForConstruct.clear(); - } + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); Base::clearCode(); } @@ -680,48 +645,54 @@ void FunctionExecutable::unlinkCalls() { #if ENABLE(JIT) if (!!m_jitCodeForCall) { - ASSERT(m_codeBlockForCall); + RELEASE_ASSERT(m_codeBlockForCall); m_codeBlockForCall->unlinkCalls(); } if (!!m_jitCodeForConstruct) { - ASSERT(m_codeBlockForConstruct); + RELEASE_ASSERT(m_codeBlockForConstruct); m_codeBlockForConstruct->unlinkCalls(); } #endif } -FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr program = parse(&exec->globalData(), lexicalGlobalObject, source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception); - if (!program) { - ASSERT(*exception); + UnlinkedFunctionExecutable* unlinkedFunction = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); + if (!unlinkedFunction) return 0; - } + unsigned firstLine = source.firstLine() + unlinkedFunction->firstLineOffset(); + unsigned startOffset = source.startOffset() + unlinkedFunction->startOffset(); + unsigned startColumn = source.startColumn(); + unsigned sourceLength = unlinkedFunction->sourceLength(); + SourceCode functionSource(source.provider(), startOffset, startOffset + sourceLength, firstLine, startColumn); + return FunctionExecutable::create(exec->vm(), functionSource, unlinkedFunction, firstLine, unlinkedFunction->lineCount(), startColumn); +} - // Uses of this function that would not result in a single function expression are invalid. - StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); - ASSERT(funcExpr); - ASSERT(funcExpr->isFuncExprNode()); - FunctionBodyNode* body = static_cast(funcExpr)->body(); - ASSERT(body); +String FunctionExecutable::paramString() const +{ + return m_unlinkedExecutable->paramString(); +} - return FunctionExecutable::create(exec->globalData(), functionName, functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); +CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const +{ + if (this->classInfo() == &NativeExecutable::s_info) + return jsCast(this)->hashFor(kind); + + return jsCast(this)->hashFor(kind); } -UString FunctionExecutable::paramString() const +CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const { - FunctionParameters& parameters = *m_parameters; - UStringBuilder builder; - for (size_t pos = 0; pos < parameters.size(); ++pos) { - if (!builder.isEmpty()) - builder.append(", "); - builder.append(parameters[pos].ustring()); - } - return builder.toUString(); + if (kind == CodeForCall) + return CodeBlockHash(static_cast(bitwise_cast(m_function))); + + RELEASE_ASSERT(kind == CodeForConstruct); + return CodeBlockHash(static_cast(bitwise_cast(m_constructor))); +} + +CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const +{ + return CodeBlockHash(source(), kind); } }