X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..93a3786624b2768d89bfa27e46598dc64e2fb70a:/runtime/Executable.cpp?ds=inline diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index 5fa560e..9185376 100644 --- a/runtime/Executable.cpp +++ b/runtime/Executable.cpp @@ -26,138 +26,210 @@ #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 "Vector.h" +#include +#include -#if ENABLE(DFG_JIT) -#include "DFGByteCodeParser.h" -#include "DFGJITCompiler.h" +namespace JSC { + +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; + +#if ENABLE(JIT) +void ExecutableBase::destroy(JSCell* cell) +{ + static_cast(cell)->ExecutableBase::~ExecutableBase(); +} #endif -namespace JSC { +void ExecutableBase::clearCode() +{ +#if ENABLE(JIT) + m_jitCodeForCall.clear(); + m_jitCodeForConstruct.clear(); + m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); + m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); +#endif + m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; + m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; +} + +#if ENABLE(DFG_JIT) +Intrinsic ExecutableBase::intrinsic() const +{ + if (const NativeExecutable* nativeExecutable = jsDynamicCast(this)) + return nativeExecutable->intrinsic(); + return NoIntrinsic; +} +#else +Intrinsic ExecutableBase::intrinsic() const +{ + return NoIntrinsic; +} +#endif -const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0 }; +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; #if ENABLE(JIT) -class ExecutableFinalizer : public WeakHandleOwner { - virtual void finalize(Handle handle, void*) - { - Weak executable(Weak::Adopt, handle); - executable->clearExecutableCode(); - } -}; +void NativeExecutable::destroy(JSCell* cell) +{ + static_cast(cell)->NativeExecutable::~NativeExecutable(); +} +#endif -WeakHandleOwner* ExecutableBase::executableFinalizer() +#if ENABLE(DFG_JIT) +Intrinsic NativeExecutable::intrinsic() const { - DEFINE_STATIC_LOCAL(ExecutableFinalizer, finalizer, ()); - return &finalizer; + return m_intrinsic; } #endif - -const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0 }; -NativeExecutable::~NativeExecutable() +#if ENABLE(JIT) +// Utility method used for jettisoning code blocks. +template +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(); + vm.heap.jettisonDFGCodeBlock(static_pointer_cast(codeBlockToJettison.release())); } +#endif + +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; -const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0 }; +#if ENABLE(JIT) +void ScriptExecutable::destroy(JSCell* cell) +{ + static_cast(cell)->ScriptExecutable::~ScriptExecutable(); +} +#endif -const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0 }; +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) { } -EvalExecutable::~EvalExecutable() +void EvalExecutable::destroy(JSCell* cell) { + static_cast(cell)->EvalExecutable::~EvalExecutable(); } -const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0 }; +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) { } -ProgramExecutable::~ProgramExecutable() +void ProgramExecutable::destroy(JSCell* cell) { + static_cast(cell)->ProgramExecutable::~ProgramExecutable(); } -const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0 }; +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; -FunctionExecutable::FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) - : ScriptExecutable(globalData->functionExecutableStructure.get(), globalData, source, inStrictContext) - , m_numCapturedVariables(0) - , m_forceUsesArguments(forceUsesArguments) - , m_parameters(parameters) - , m_name(name) - , m_symbolTable(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; } -FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext, int firstLine, int lastLine) - : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext) - , m_numCapturedVariables(0) - , m_forceUsesArguments(forceUsesArguments) - , m_parameters(parameters) - , m_name(name) - , m_symbolTable(0) +void FunctionExecutable::destroy(JSCell* cell) { - m_firstLine = firstLine; - m_lastLine = lastLine; + static_cast(cell)->FunctionExecutable::~FunctionExecutable(); } - -JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* EvalExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - if (!lexicalGlobalObject->isEvalEnabled()) - return throwError(exec, createEvalError(exec, "Eval is disabled")); - RefPtr evalNode = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception); - if (!evalNode) { - ASSERT(exception); - return exception; - } - recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine()); + ASSERT(exec->vm().dynamicGlobalObject); + ASSERT(!!m_evalCodeBlock); + JSObject* error = 0; + if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT()) + error = compileInternal(exec, scope, JITCode::nextTierJIT(m_evalCodeBlock->getJITType()), bytecodeIndex); + ASSERT(!!m_evalCodeBlock); + return error; +} - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); +#if ENABLE(JIT) +bool EvalExecutable::jitCompile(ExecState* exec) +{ + return jitCompileIfAppropriate(exec, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} +#endif - ASSERT(!m_evalCodeBlock); - m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get()))); - if ((exception = generator->generate())) { - m_evalCodeBlock.clear(); - evalNode->destroyData(); - return exception; +inline const char* samplingDescription(JITCode::JITType jitType) +{ + switch (jitType) { + case JITCode::InterpreterThunk: + return "Interpreter Compilation (TOTAL)"; + case JITCode::BaselineJIT: + return "Baseline Compilation (TOTAL)"; + case JITCode::DFGJIT: + return "DFG Compilation (TOTAL)"; + default: + RELEASE_ASSERT_NOT_REACHED(); + return 0; } +} - evalNode->destroyData(); - -#if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get()); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_evalCodeBlock->discardBytecode(); +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 + VM* vm = &exec->vm(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + + if (!!m_evalCodeBlock) { + OwnPtr newCodeBlock = adoptPtr(new EvalCodeBlock(CodeBlock::CopyParsedBlock, *m_evalCodeBlock)); + 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, lexicalGlobalObject->evalDisabledErrorMessage())); + + JSObject* exception = 0; + UnlinkedEvalCodeBlock* unlinkedEvalCode = lexicalGlobalObject->createEvalCodeBlock(m_codeCache.get(), exec, scope, this, &exception); + if (!unlinkedEvalCode) + return exception; + + OwnPtr previousCodeBlock = m_evalCodeBlock.release(); + ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock); + m_unlinkedEvalCodeBlock.set(*vm, this, unlinkedEvalCode); + m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, unlinkedEvalCode, lexicalGlobalObject, source().provider(), scope->localDepth(), previousCodeBlock.release())); + m_evalCodeBlock->copyPostParseDataFromAlternative(); } -#endif #if ENABLE(JIT) -#if ENABLE(INTERPRETER) - if (!m_jitCodeForCall) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); - else + if (!prepareForExecution(exec, m_evalCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) + return 0; #endif + +#if ENABLE(JIT) Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock)); @@ -166,14 +238,25 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope return 0; } -void EvalExecutable::visitChildren(SlotVisitor& visitor) +#if ENABLE(JIT) +void EvalExecutable::jettisonOptimizedCode(VM& vm) +{ + jettisonCodeBlock(vm, m_evalCodeBlock); + m_jitCodeForCall = m_evalCodeBlock->getJITCode(); + ASSERT(!m_jitCodeForCallWithArityCheck); +} +#endif + +void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { - ASSERT_GC_OBJECT_INHERITS(this, &s_info); + EvalExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(structure()->typeInfo().overridesVisitChildren()); - ScriptExecutable::visitChildren(visitor); - if (m_evalCodeBlock) - m_evalCodeBlock->visitAggregate(visitor); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(thisObject, visitor); + if (thisObject->m_evalCodeBlock) + thisObject->m_evalCodeBlock->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedEvalCodeBlock); } void EvalExecutable::unlinkCalls() @@ -181,66 +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::clearCode() +{ + 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 = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, JSParseNormal, &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::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* ProgramExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) { - ASSERT(!m_programCodeBlock); + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); + ASSERT(!!m_programCodeBlock); + JSObject* error = 0; + if (m_programCodeBlock->getJITType() != JITCode::topTierJIT()) + error = compileInternal(exec, scope, JITCode::nextTierJIT(m_programCodeBlock->getJITType()), bytecodeIndex); + ASSERT(!!m_programCodeBlock); + return error; +} - JSObject* exception = 0; - JSGlobalData* globalData = &exec->globalData(); - JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr programNode = globalData->parser->parse(lexicalGlobalObject, lexicalGlobalObject->debugger(), exec, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, &exception); - if (!programNode) { - ASSERT(exception); - return exception; - } - recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine()); +#if ENABLE(JIT) +bool ProgramExecutable::jitCompile(ExecState* exec) +{ + return jitCompileIfAppropriate(exec, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} +#endif - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); +JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) +{ + SamplingRegion samplingRegion(samplingDescription(jitType)); - m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); - OwnPtr generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get()))); - if ((exception = generator->generate())) { - m_programCodeBlock.clear(); - programNode->destroyData(); - return exception; +#if !ENABLE(JIT) + UNUSED_PARAM(exec); + UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); +#endif + 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 { + JSGlobalObject* globalObject = scope->globalObject(); + m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, m_unlinkedProgramCodeBlock.get(), globalObject, source().provider(), source().startColumn(), m_programCodeBlock.release())); + m_programCodeBlock->copyPostParseDataFromAlternative(); } - programNode->destroyData(); - #if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get()); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_programCodeBlock->discardBytecode(); -#endif - } + if (!prepareForExecution(exec, m_programCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) + return 0; #endif #if ENABLE(JIT) -#if ENABLE(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 @@ -248,106 +339,214 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc return 0; } +#if ENABLE(JIT) +void ProgramExecutable::jettisonOptimizedCode(VM& vm) +{ + jettisonCodeBlock(vm, m_programCodeBlock); + m_jitCodeForCall = m_programCodeBlock->getJITCode(); + ASSERT(!m_jitCodeForCallWithArityCheck); +} +#endif + void ProgramExecutable::unlinkCalls() { #if ENABLE(JIT) if (!m_jitCodeForCall) return; - ASSERT(m_programCodeBlock); + RELEASE_ASSERT(m_programCodeBlock); m_programCodeBlock->unlinkCalls(); #endif } -#if ENABLE(JIT) -static bool tryDFGCompile(JSGlobalData* globalData, CodeBlock* codeBlock, JITCode& jitCode, MacroAssemblerCodePtr& jitCodeWithArityCheck) +int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) { -#if ENABLE(DFG_JIT) -#if ENABLE(DFG_JIT_RESTRICTIONS) - // FIXME: No flow control yet supported, don't bother scanning the bytecode if there are any jump targets. - // FIXME: temporarily disable property accesses until we fix regressions. - if (codeBlock->numberOfJumpTargets() || codeBlock->numberOfStructureStubInfos()) - return false; -#endif + // 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; +} - DFG::Graph dfg(codeBlock->m_numParameters, codeBlock->m_numVars); - if (!parse(dfg, globalData, codeBlock)) - return false; +JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) +{ + RELEASE_ASSERT(scope); + JSGlobalObject* globalObject = scope->globalObject(); + RELEASE_ASSERT(globalObject); + ASSERT(&globalObject->vm() == &vm); - DFG::JITCompiler dataFlowJIT(globalData, dfg, codeBlock); - dataFlowJIT.compileFunction(jitCode, jitCodeWithArityCheck); - return true; -#else - UNUSED_PARAM(globalData); - UNUSED_PARAM(codeBlock); - UNUSED_PARAM(jitCode); - UNUSED_PARAM(jitCodeWithArityCheck); - return false; -#endif + 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; } -#endif -void ProgramExecutable::visitChildren(SlotVisitor& visitor) +void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { - ASSERT_GC_OBJECT_INHERITS(this, &s_info); + ProgramExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(structure()->typeInfo().overridesVisitChildren()); - ScriptExecutable::visitChildren(visitor); - if (m_programCodeBlock) - m_programCodeBlock->visitAggregate(visitor); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_unlinkedProgramCodeBlock); + if (thisObject->m_programCodeBlock) + thisObject->m_programCodeBlock->visitAggregate(visitor); } -JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode) +void ProgramExecutable::clearCode() { - JSObject* exception = 0; - JSGlobalData* globalData = scopeChainNode->globalData; - RefPtr body = globalData->parser->parse(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception); - if (!body) { - ASSERT(exception); - return exception; - } - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name); - recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - - ASSERT(!m_codeBlockForCall); - m_codeBlockForCall = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), false)); - OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForCall->symbolTable(), m_codeBlockForCall.get()))); - if ((exception = generator->generate())) { - m_codeBlockForCall.clear(); - body->destroyData(); - return exception; + m_programCodeBlock.clear(); + m_unlinkedProgramCodeBlock.clear(); + Base::clearCode(); +} + +FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) +{ + FunctionCodeBlock* result; + if (kind == CodeForCall) + result = m_codeBlockForCall.get(); + else { + RELEASE_ASSERT(kind == CodeForConstruct); + result = m_codeBlockForConstruct.get(); } + if (!result) + return 0; + while (result->alternative()) + result = static_cast(result->alternative()); + RELEASE_ASSERT(result); + ASSERT(JITCode::isBaselineCode(result->getJITType())); + return result; +} - m_numParametersForCall = m_codeBlockForCall->m_numParameters; - ASSERT(m_numParametersForCall); - m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; - m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); +JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) +{ + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); + ASSERT(!!m_codeBlockForCall); + JSObject* error = 0; + if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT()) + error = compileForCallInternal(exec, scope, JITCode::nextTierJIT(m_codeBlockForCall->getJITType()), bytecodeIndex); + ASSERT(!!m_codeBlockForCall); + return error; +} - body->destroyData(); +JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) +{ + RELEASE_ASSERT(exec->vm().dynamicGlobalObject); + ASSERT(!!m_codeBlockForConstruct); + JSObject* error = 0; + if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT()) + error = compileForConstructInternal(exec, scope, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()), bytecodeIndex); + ASSERT(!!m_codeBlockForConstruct); + return error; +} #if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - bool dfgCompiled = tryDFGCompile(&exec->globalData(), m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck); - if (!dfgCompiled) - m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck); - -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_codeBlockForCall->discardBytecode(); +bool FunctionExecutable::jitCompileForCall(ExecState* exec) +{ + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} + +bool FunctionExecutable::jitCompileForConstruct(ExecState* exec) +{ + return jitCompileFunctionIfAppropriate(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} #endif + +PassOwnPtr FunctionExecutable::produceCodeBlockFor(JSScope* scope, CodeSpecializationKind specializationKind, JSObject*& exception) +{ + if (!!codeBlockFor(specializationKind)) + return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind))); + + 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; } + + 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, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) +{ + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#if !ENABLE(JIT) + UNUSED_PARAM(exec); + UNUSED_PARAM(jitType); + UNUSED_PARAM(exec); + UNUSED_PARAM(bytecodeIndex); #endif + ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall); + JSObject* exception = 0; + OwnPtr newCodeBlock = produceCodeBlockFor(scope, CodeForCall, exception); + if (!newCodeBlock) + return exception; + + newCodeBlock->setAlternative(static_pointer_cast(m_codeBlockForCall.release())); + m_codeBlockForCall = newCodeBlock.release(); + + m_numParametersForCall = m_codeBlockForCall->numParameters(); + RELEASE_ASSERT(m_numParametersForCall); #if ENABLE(JIT) -#if ENABLE(INTERPRETER) - if (!m_jitCodeForCall) - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); - else + if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall)) + return 0; #endif - Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); + +#if ENABLE(JIT) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); #else Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); #endif @@ -355,54 +554,34 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain return 0; } -JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode) +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 = 0; - JSGlobalData* globalData = scopeChainNode->globalData; - RefPtr body = globalData->parser->parse(exec->lexicalGlobalObject(), 0, 0, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, &exception); - if (!body) { - ASSERT(exception); + OwnPtr newCodeBlock = produceCodeBlockFor(scope, CodeForConstruct, exception); + if (!newCodeBlock) return exception; - } - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name); - recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - - JSGlobalObject* globalObject = scopeChainNode->globalObject.get(); - - ASSERT(!m_codeBlockForConstruct); - m_codeBlockForConstruct = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), true)); - OwnPtr generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, m_codeBlockForConstruct->symbolTable(), m_codeBlockForConstruct.get()))); - if ((exception = generator->generate())) { - m_codeBlockForConstruct.clear(); - body->destroyData(); - return exception; - } - m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters; - ASSERT(m_numParametersForConstruct); - m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; - m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); - - body->destroyData(); + newCodeBlock->setAlternative(static_pointer_cast(m_codeBlockForConstruct.release())); + m_codeBlockForConstruct = newCodeBlock.release(); + + m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); + RELEASE_ASSERT(m_numParametersForConstruct); #if ENABLE(JIT) - if (exec->globalData().canUseJIT()) { - m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_codeBlockForConstruct->discardBytecode(); -#endif - } + if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct)) + return 0; #endif #if ENABLE(JIT) -#if ENABLE(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)); @@ -411,90 +590,109 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope return 0; } -void FunctionExecutable::visitChildren(SlotVisitor& visitor) +#if ENABLE(JIT) +void FunctionExecutable::jettisonOptimizedCodeForCall(VM& vm) +{ + jettisonCodeBlock(vm, m_codeBlockForCall); + m_jitCodeForCall = m_codeBlockForCall->getJITCode(); + m_jitCodeForCallWithArityCheck = m_codeBlockForCall->getJITCodeWithArityCheck(); +} + +void FunctionExecutable::jettisonOptimizedCodeForConstruct(VM& vm) +{ + jettisonCodeBlock(vm, m_codeBlockForConstruct); + m_jitCodeForConstruct = m_codeBlockForConstruct->getJITCode(); + m_jitCodeForConstructWithArityCheck = m_codeBlockForConstruct->getJITCodeWithArityCheck(); +} +#endif + +void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { - ASSERT_GC_OBJECT_INHERITS(this, &s_info); + FunctionExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(structure()->typeInfo().overridesVisitChildren()); - ScriptExecutable::visitChildren(visitor); - if (m_codeBlockForCall) - m_codeBlockForCall->visitAggregate(visitor); - if (m_codeBlockForConstruct) - m_codeBlockForConstruct->visitAggregate(visitor); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(thisObject, visitor); + 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) + if (isCompiling()) return; - if (!m_jitCodeForConstruct && m_codeBlockForConstruct) + clearCode(); +} + +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() +{ + if (isCompiling()) return; - m_jitCodeForCall = JITCode(); - m_jitCodeForConstruct = JITCode(); - m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); - m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); -#endif - if (m_codeBlockForCall) - m_codeBlockForCall->clearEvalCache(); + m_unlinkedExecutable->clearCodeForRecompilation(); +} + +void FunctionExecutable::clearCode() +{ m_codeBlockForCall.clear(); - if (m_codeBlockForConstruct) - m_codeBlockForConstruct->clearEvalCache(); m_codeBlockForConstruct.clear(); - m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED; - m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED; - + Base::clearCode(); } 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 = exec->globalData().parser->parse(lexicalGlobalObject, debugger, exec, source, 0, JSParseNormal, 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); +} + +String FunctionExecutable::paramString() const +{ + return m_unlinkedExecutable->paramString(); +} - // 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); +CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const +{ + if (this->classInfo() == &NativeExecutable::s_info) + return jsCast(this)->hashFor(kind); + + return jsCast(this)->hashFor(kind); +} - return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); +CodeBlockHash NativeExecutable::hashFor(CodeSpecializationKind kind) const +{ + if (kind == CodeForCall) + return CodeBlockHash(static_cast(bitwise_cast(m_function))); + + RELEASE_ASSERT(kind == CodeForConstruct); + return CodeBlockHash(static_cast(bitwise_cast(m_constructor))); } -UString FunctionExecutable::paramString() const +CodeBlockHash ScriptExecutable::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(); + return CodeBlockHash(source(), kind); } }