X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174:/runtime/Executable.cpp diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index bc18cc9..3690c2c 100644 --- a/runtime/Executable.cpp +++ b/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,253 +28,700 @@ #include "BytecodeGenerator.h" #include "CodeBlock.h" +#include "DFGDriver.h" +#include "ExecutionHarness.h" #include "JIT.h" +#include "JITDriver.h" #include "Parser.h" -#include "StringBuilder.h" -#include "Vector.h" +#include "UStringBuilder.h" +#include namespace JSC { +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; + #if ENABLE(JIT) -NativeExecutable::~NativeExecutable() +void ExecutableBase::destroy(JSCell* cell) { + jsCast(cell)->ExecutableBase::~ExecutableBase(); } #endif -VPtrHackExecutable::~VPtrHackExecutable() +inline 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; } -EvalExecutable::~EvalExecutable() +#if ENABLE(DFG_JIT) +Intrinsic ExecutableBase::intrinsic() const { - delete m_evalCodeBlock; + if (const NativeExecutable* nativeExecutable = jsDynamicCast(this)) + return nativeExecutable->intrinsic(); + return NoIntrinsic; } +#endif -ProgramExecutable::~ProgramExecutable() +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; + +#if ENABLE(JIT) +void NativeExecutable::destroy(JSCell* cell) { - delete m_programCodeBlock; + jsCast(cell)->NativeExecutable::~NativeExecutable(); } +#endif -FunctionExecutable::~FunctionExecutable() +#if ENABLE(DFG_JIT) +Intrinsic NativeExecutable::intrinsic() const { - delete m_codeBlock; + return m_intrinsic; } +#endif -JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +#if ENABLE(JIT) +// Utility method used for jettisoning code blocks. +template +static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr& codeBlock) { - int errLine; - UString errMsg; - RefPtr evalNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!evalNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine()); + 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())); +} +#endif - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +void NativeExecutable::finalize(JSCell* cell) +{ + jsCast(cell)->clearCode(); +} - ASSERT(!m_evalCodeBlock); - m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()); - OwnPtr generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)); - generator->generate(); - - evalNode->destroyData(); - return 0; +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(); +} +#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) +{ } -JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +void EvalExecutable::destroy(JSCell* cell) { - int errLine; - UString errMsg; - RefPtr programNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!programNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - return 0; + jsCast(cell)->EvalExecutable::~EvalExecutable(); } -JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +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) +{ +} + +void ProgramExecutable::destroy(JSCell* cell) +{ + jsCast(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) +{ +} + +void FunctionExecutable::destroy(JSCell* cell) +{ + jsCast(cell)->FunctionExecutable::~FunctionExecutable(); +} + +JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(!!m_evalCodeBlock); + JSObject* error = 0; + if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT()) + error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_evalCodeBlock->getJITType())); + ASSERT(!!m_evalCodeBlock); + return error; +} + +#if ENABLE(JIT) +bool EvalExecutable::jitCompile(JSGlobalData& globalData) +{ + return jitCompileIfAppropriate(globalData, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); +} +#endif + +inline const char* samplingDescription(JITCode::JITType jitType) { - int errLine; - UString errMsg; - RefPtr programNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!programNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); - recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine()); + switch (jitType) { + case JITCode::InterpreterThunk: + return "Interpreter Compilation (TOTAL)"; + case JITCode::BaselineJIT: + return "Baseline Compilation (TOTAL)"; + case JITCode::DFGJIT: + return "DFG Compilation (TOTAL)"; + default: + ASSERT_NOT_REACHED(); + return 0; + } +} - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +{ + SamplingRegion samplingRegion(samplingDescription(jitType)); - ASSERT(!m_programCodeBlock); - m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()); - OwnPtr generator(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock)); - generator->generate(); +#if !ENABLE(JIT) + UNUSED_PARAM(jitType); +#endif + JSObject* exception = 0; + JSGlobalData* globalData = &exec->globalData(); + 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 { + 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 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_evalCodeBlock->copyPostParseDataFromAlternative(); + } + +#if ENABLE(JIT) + if (!prepareForExecution(*globalData, m_evalCodeBlock, m_jitCodeForCall, jitType)) + 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)); +#endif - programNode->destroyData(); return 0; } -void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) +#if ENABLE(JIT) +void EvalExecutable::jettisonOptimizedCode(JSGlobalData& globalData) { - JSGlobalData* globalData = scopeChainNode->globalData; - RefPtr body = globalData->parser->parse(globalData, 0, 0, m_source); - if (m_forceUsesArguments) - body->setUsesArguments(); - body->finishParsing(m_parameters, m_name); - recordParse(body->features(), body->lineNo(), body->lastLine()); + jettisonCodeBlock(globalData, m_evalCodeBlock); + m_jitCodeForCall = m_evalCodeBlock->getJITCode(); + ASSERT(!m_jitCodeForCallWithArityCheck); +} +#endif - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + EvalExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(thisObject, visitor); + if (thisObject->m_evalCodeBlock) + thisObject->m_evalCodeBlock->visitAggregate(visitor); +} - ASSERT(!m_codeBlock); - m_codeBlock = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset()); - OwnPtr generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlock->symbolTable(), m_codeBlock)); - generator->generate(); - m_numParameters = m_codeBlock->m_numParameters; - ASSERT(m_numParameters); - m_numVariables = m_codeBlock->m_numVars; +void EvalExecutable::unlinkCalls() +{ +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + ASSERT(m_evalCodeBlock); + m_evalCodeBlock->unlinkCalls(); +#endif +} - body->destroyData(); +void EvalExecutable::finalize(JSCell* cell) +{ + jsCast(cell)->clearCode(); +} + +inline void EvalExecutable::clearCode() +{ + if (m_evalCodeBlock) { + m_evalCodeBlock->clearEvalCache(); + m_evalCodeBlock.clear(); + } + Base::clearCode(); +} + +JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +{ + JSObject* exception = 0; + JSGlobalData* globalData = &exec->globalData(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr programNode = parse(globalData, lexicalGlobalObject, m_source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception); + if (programNode) + return 0; + ASSERT(exception); + return exception; +} + +JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(!!m_programCodeBlock); + JSObject* error = 0; + if (m_programCodeBlock->getJITType() != JITCode::topTierJIT()) + error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_programCodeBlock->getJITType())); + ASSERT(!!m_programCodeBlock); + return error; } #if ENABLE(JIT) +bool ProgramExecutable::jitCompile(JSGlobalData& globalData) +{ + return jitCompileIfAppropriate(globalData, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), JITCompilationCanFail); +} +#endif -void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#if !ENABLE(JIT) + UNUSED_PARAM(jitType); +#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(); + m_programCodeBlock->copyPostParseDataFromAlternative(); + } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +#if ENABLE(JIT) + if (!prepareForExecution(*globalData, m_programCodeBlock, m_jitCodeForCall, jitType)) + 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()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); #endif + + return 0; } -void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +#if ENABLE(JIT) +void ProgramExecutable::jettisonOptimizedCode(JSGlobalData& globalData) { - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + jettisonCodeBlock(globalData, m_programCodeBlock); + m_jitCodeForCall = m_programCodeBlock->getJITCode(); + ASSERT(!m_jitCodeForCallWithArityCheck); +} +#endif -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +void ProgramExecutable::unlinkCalls() +{ +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + ASSERT(m_programCodeBlock); + m_programCodeBlock->unlinkCalls(); #endif } -void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + ProgramExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + ScriptExecutable::visitChildren(thisObject, visitor); + if (thisObject->m_programCodeBlock) + thisObject->m_programCodeBlock->visitAggregate(visitor); +} -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); -#endif +void ProgramExecutable::finalize(JSCell* cell) +{ + jsCast(cell)->clearCode(); +} + +inline void ProgramExecutable::clearCode() +{ + if (m_programCodeBlock) { + m_programCodeBlock->clearEvalCache(); + m_programCodeBlock.clear(); + } + Base::clearCode(); } +FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) +{ + FunctionCodeBlock* result; + if (kind == CodeForCall) + result = m_codeBlockForCall.get(); + else { + ASSERT(kind == CodeForConstruct); + result = m_codeBlockForConstruct.get(); + } + if (!result) + return 0; + while (result->alternative()) + result = static_cast(result->alternative()); + ASSERT(result); + ASSERT(JITCode::isBaselineCode(result->getJITType())); + return result; +} + +JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(!!m_codeBlockForCall); + JSObject* error = 0; + if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT()) + error = compileForCallInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForCall->getJITType())); + ASSERT(!!m_codeBlockForCall); + return error; +} + +JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + ASSERT(exec->globalData().dynamicGlobalObject); + ASSERT(!!m_codeBlockForConstruct); + JSObject* error = 0; + if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT()) + error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType())); + ASSERT(!!m_codeBlockForConstruct); + return error; +} + +#if ENABLE(JIT) +bool FunctionExecutable::jitCompileForCall(JSGlobalData& globalData) +{ + return jitCompileFunctionIfAppropriate(globalData, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); +} + +bool FunctionExecutable::jitCompileForConstruct(JSGlobalData& globalData) +{ + return jitCompileFunctionIfAppropriate(globalData, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, JITCode::bottomTierJIT(), JITCompilationCanFail); +} #endif -void FunctionExecutable::markAggregate(MarkStack& markStack) +FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind) { - if (m_codeBlock) - m_codeBlock->markAggregate(markStack); + return baselineCodeBlockFor(kind); } -ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +PassOwnPtr FunctionExecutable::produceCodeBlockFor(ScopeChainNode* scopeChainNode, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception) { - RefPtr newFunctionBody = globalData->parser->parse(globalData, 0, 0, m_source); - if (m_forceUsesArguments) - newFunctionBody->setUsesArguments(); - newFunctionBody->finishParsing(m_parameters, m_name); + 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); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + if (!body) { + ASSERT(exception); + return nullptr; + } + if (m_forceUsesArguments) + body->setUsesArguments(); + body->finishParsing(m_parameters, m_name); + recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine()); - OwnPtr newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); + 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; - OwnPtr generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); + result->copyPostParseDataFrom(codeBlockFor(specializationKind).get()); + return result.release(); +} - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); +JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) +{ + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#if !ENABLE(JIT) + UNUSED_PARAM(exec); + UNUSED_PARAM(jitType); + UNUSED_PARAM(exec); +#endif + ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall); + JSObject* exception; + OwnPtr newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForCall ? OptimizingCompilation : FirstCompilation, CodeForCall, exception); + if (!newCodeBlock) + return exception; + + newCodeBlock->setAlternative(static_pointer_cast(m_codeBlockForCall.release())); + m_codeBlockForCall = newCodeBlock.release(); + + m_numParametersForCall = m_codeBlockForCall->numParameters(); + ASSERT(m_numParametersForCall); + m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars; + m_symbolTable = m_codeBlockForCall->sharedSymbolTable(); #if ENABLE(JIT) - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); + if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, m_symbolTable, jitType, CodeForCall)) + return 0; #endif - globalData->functionCodeBlockBeingReparsed = 0; +#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()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); +#endif - return newCodeBlock->extractExceptionInfo(); + return 0; } -ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType) { - RefPtr newEvalBody = globalData->parser->parse(globalData, 0, 0, m_source); + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#if !ENABLE(JIT) + UNUSED_PARAM(jitType); + UNUSED_PARAM(exec); +#endif + + ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct); + JSObject* exception; + OwnPtr newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForConstruct ? OptimizingCompilation : FirstCompilation, CodeForConstruct, exception); + if (!newCodeBlock) + return exception; + + newCodeBlock->setAlternative(static_pointer_cast(m_codeBlockForConstruct.release())); + m_codeBlockForConstruct = newCodeBlock.release(); + + m_numParametersForConstruct = m_codeBlockForConstruct->numParameters(); + ASSERT(m_numParametersForConstruct); + m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars; + m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable(); + +#if ENABLE(JIT) + if (!prepareFunctionForExecution(exec->globalData(), m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, m_symbolTable, jitType, 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)); +#endif - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + return 0; +} - OwnPtr newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); +#if ENABLE(JIT) +void FunctionExecutable::jettisonOptimizedCodeForCall(JSGlobalData& globalData) +{ + jettisonCodeBlock(globalData, m_codeBlockForCall); + m_jitCodeForCall = m_codeBlockForCall->getJITCode(); + m_jitCodeForCallWithArityCheck = m_codeBlockForCall->getJITCodeWithArityCheck(); +} - OwnPtr generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); +void FunctionExecutable::jettisonOptimizedCodeForConstruct(JSGlobalData& globalData) +{ + jettisonCodeBlock(globalData, m_codeBlockForConstruct); + m_jitCodeForConstruct = m_codeBlockForConstruct->getJITCode(); + m_jitCodeForConstructWithArityCheck = m_codeBlockForConstruct->getJITCodeWithArityCheck(); +} +#endif - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); +void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + FunctionExecutable* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + 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); +} +void FunctionExecutable::discardCode() +{ #if ENABLE(JIT) - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); + // 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) + return; #endif + clearCode(); +} + +void FunctionExecutable::finalize(JSCell* cell) +{ + FunctionExecutable* executable = jsCast(cell); + Heap::heap(executable)->removeFunctionExecutable(executable); + executable->clearCode(); +} - return newCodeBlock->extractExceptionInfo(); +inline void FunctionExecutable::clearCode() +{ + if (m_codeBlockForCall) { + m_codeBlockForCall->clearEvalCache(); + m_codeBlockForCall.clear(); + } + if (m_codeBlockForConstruct) { + m_codeBlockForConstruct->clearEvalCache(); + m_codeBlockForConstruct.clear(); + } + Base::clearCode(); } -void FunctionExecutable::recompile(ExecState*) +void FunctionExecutable::unlinkCalls() { - delete m_codeBlock; - m_codeBlock = 0; - m_numParameters = NUM_PARAMETERS_NOT_COMPILED; #if ENABLE(JIT) - m_jitCode = JITCode(); + if (!!m_jitCodeForCall) { + ASSERT(m_codeBlockForCall); + m_codeBlockForCall->unlinkCalls(); + } + if (!!m_jitCodeForConstruct) { + ASSERT(m_codeBlockForConstruct); + m_codeBlockForConstruct->unlinkCalls(); + } #endif } -PassRefPtr FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) { - RefPtr program = exec->globalData().parser->parse(&exec->globalData(), debugger, exec, source, errLine, errMsg); - if (!program) + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr program = parse(&exec->globalData(), lexicalGlobalObject, source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception); + if (!program) { + ASSERT(*exception); return 0; + } + // Uses of this function that would not result in a single function expression are invalid. StatementNode* exprStatement = program->singleStatement(); ASSERT(exprStatement); ASSERT(exprStatement->isExprStatement()); - if (!exprStatement || !exprStatement->isExprStatement()) - return 0; - ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); ASSERT(funcExpr); ASSERT(funcExpr->isFuncExprNode()); - if (!funcExpr || !funcExpr->isFuncExprNode()) - return 0; - FunctionBodyNode* body = static_cast(funcExpr)->body(); ASSERT(body); - return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); + + return FunctionExecutable::create(exec->globalData(), functionName, functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); } UString FunctionExecutable::paramString() const { FunctionParameters& parameters = *m_parameters; - StringBuilder builder; + UStringBuilder builder; for (size_t pos = 0; pos < parameters.size(); ++pos) { if (!builder.isEmpty()) builder.append(", "); builder.append(parameters[pos].ustring()); } - return builder.release(); + return builder.toUString(); } -}; - - +}