X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4e4e5a6f2694187498445a6ac6f1634ce8141119..93a3786624b2768d89bfa27e46598dc64e2fb70a:/runtime/Executable.cpp diff --git a/runtime/Executable.cpp b/runtime/Executable.cpp index 1916a23..9185376 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 @@ -26,274 +26,673 @@ #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 "StringBuilder.h" -#include "Vector.h" +#include +#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) { + static_cast(cell)->ExecutableBase::~ExecutableBase(); } #endif -VPtrHackExecutable::~VPtrHackExecutable() +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; } +#else +Intrinsic ExecutableBase::intrinsic() const +{ + 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; + static_cast(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(VM& vm, 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(); + vm.heap.jettisonDFGCodeBlock(static_pointer_cast(codeBlockToJettison.release())); +} +#endif - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; - 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; +#if ENABLE(JIT) +void ScriptExecutable::destroy(JSCell* cell) +{ + static_cast(cell)->ScriptExecutable::~ScriptExecutable(); } +#endif -JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; + +EvalExecutable::EvalExecutable(ExecState* exec, PassRefPtr codeCache, const SourceCode& source, bool inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) + , m_codeCache(codeCache) { - 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; } -JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +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()); - recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine()); + static_cast(cell)->EvalExecutable::~EvalExecutable(); +} - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - 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(); +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; - programNode->destroyData(); - return 0; +ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) +{ } -void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) +void ProgramExecutable::destroy(JSCell* cell) { - 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()); + static_cast(cell)->ProgramExecutable::~ProgramExecutable(); +} - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; - 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; +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; +} - body->destroyData(); +void FunctionExecutable::destroy(JSCell* cell) +{ + static_cast(cell)->FunctionExecutable::~FunctionExecutable(); +} + +JSObject* EvalExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) +{ + 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; } #if ENABLE(JIT) +bool EvalExecutable::jitCompile(ExecState* exec) +{ + return jitCompileIfAppropriate(exec, m_evalCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} +#endif + +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; + } +} -void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +JSObject* EvalExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { -#if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#if !ENABLE(JIT) + UNUSED_PARAM(jitType); + UNUSED_PARAM(bytecodeIndex); #endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + 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(); + } -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +#if ENABLE(JIT) + 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)); +#endif + + return 0; } -void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +#if ENABLE(JIT) +void EvalExecutable::jettisonOptimizedCode(VM& vm) { -#if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); + jettisonCodeBlock(vm, m_evalCodeBlock); + m_jitCodeForCall = m_evalCodeBlock->getJITCode(); + ASSERT(!m_jitCodeForCallWithArityCheck); +} #endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +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); + visitor.append(&thisObject->m_unlinkedEvalCodeBlock); +} + +void EvalExecutable::unlinkCalls() +{ +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + RELEASE_ASSERT(m_evalCodeBlock); + m_evalCodeBlock->unlinkCalls(); #endif } -void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +void EvalExecutable::clearCode() +{ + m_evalCodeBlock.clear(); + m_unlinkedEvalCodeBlock.clear(); + Base::clearCode(); +} + +JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +{ + ParserError error; + VM* vm = &exec->vm(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + RefPtr programNode = parse(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); + if (programNode) + return 0; + ASSERT(error.m_type != ParserError::ErrorNone); + return error.toErrorObject(lexicalGlobalObject, m_source); +} + +JSObject* ProgramExecutable::compileOptimized(ExecState* exec, JSScope* scope, unsigned bytecodeIndex) +{ + 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; +} + +#if ENABLE(JIT) +bool ProgramExecutable::jitCompile(ExecState* exec) +{ + return jitCompileIfAppropriate(exec, m_programCodeBlock, m_jitCodeForCall, JITCode::bottomTierJIT(), UINT_MAX, JITCompilationCanFail); +} +#endif + +JSObject* ProgramExecutable::compileInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { -#if ENABLE(INTERPRETER) - ASSERT(scopeChainNode->globalData->canUseJIT()); + SamplingRegion samplingRegion(samplingDescription(jitType)); + +#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(); + } + +#if ENABLE(JIT) + if (!prepareForExecution(exec, m_programCodeBlock, m_jitCodeForCall, jitType, bytecodeIndex)) + return 0; #endif - CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); - m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - codeBlock->discardBytecode(); +#if ENABLE(JIT) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock)); #endif + + 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; + RELEASE_ASSERT(m_programCodeBlock); + m_programCodeBlock->unlinkCalls(); #endif +} -void FunctionExecutable::markAggregate(MarkStack& markStack) +int ProgramExecutable::addGlobalVar(JSGlobalObject* globalObject, const Identifier& ident, ConstantMode constantMode, FunctionMode functionMode) { - if (m_codeBlock) - m_codeBlock->markAggregate(markStack); + // 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; } -ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { - RefPtr newFunctionBody = globalData->parser->parse(globalData, 0, 0, m_source); - if (m_forceUsesArguments) - newFunctionBody->setUsesArguments(); - newFunctionBody->finishParsing(m_parameters, m_name); + 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; - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); + m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCode); - OwnPtr newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); + 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); + } - OwnPtr generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); + 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; +} - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); +void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + 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); + visitor.append(&thisObject->m_unlinkedProgramCodeBlock); + if (thisObject->m_programCodeBlock) + thisObject->m_programCodeBlock->visitAggregate(visitor); +} + +void ProgramExecutable::clearCode() +{ + 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; +} + +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; +} + +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 ENABLE(INTERPRETER) - if (globalData->canUseJIT()) +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 - { - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); + +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; } -#endif - globalData->functionCodeBlockBeingReparsed = 0; + SourceProvider* provider = source().provider(); + unsigned sourceOffset = source().startOffset(); + unsigned startColumn = source().startColumn(); - return newCodeBlock->extractExceptionInfo(); + OwnPtr result = adoptPtr(new FunctionCodeBlock(this, unlinkedCodeBlock, globalObject, provider, sourceOffset, startColumn)); + result->copyPostParseDataFrom(codeBlockFor(specializationKind).get()); + return result.release(); } -ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) + +JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, JSScope* scope, JITCode::JITType jitType, unsigned bytecodeIndex) { - RefPtr newEvalBody = globalData->parser->parse(globalData, 0, 0, m_source); + 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); - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); +#if ENABLE(JIT) + if (!prepareFunctionForExecution(exec, m_codeBlockForCall, m_jitCodeForCall, m_jitCodeForCallWithArityCheck, jitType, bytecodeIndex, CodeForCall)) + return 0; +#endif - OwnPtr newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); +#if ENABLE(JIT) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall)); +#endif - OwnPtr generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); - generator->setRegeneratingForExceptionInfo(static_cast(codeBlock)); - generator->generate(); + return 0; +} - ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); +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; + OwnPtr newCodeBlock = produceCodeBlockFor(scope, CodeForConstruct, exception); + if (!newCodeBlock) + return exception; + + 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 ENABLE(INTERPRETER) - if (globalData->canUseJIT()) + if (!prepareFunctionForExecution(exec, m_codeBlockForConstruct, m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck, jitType, bytecodeIndex, CodeForConstruct)) + return 0; #endif - { - JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); - ASSERT(newJITCode.size() == generatedJITCode().size()); - } + +#if ENABLE(JIT) + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size()); +#else + Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct)); #endif - return newCodeBlock->extractExceptionInfo(); + return 0; } -void FunctionExecutable::recompile(ExecState*) -{ - delete m_codeBlock; - m_codeBlock = 0; - m_numParameters = NUM_PARAMETERS_NOT_COMPILED; #if ENABLE(JIT) - m_jitCode = JITCode(); +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) +{ + 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_codeBlockForCall) + thisObject->m_codeBlockForCall->visitAggregate(visitor); + if (thisObject->m_codeBlockForConstruct) + thisObject->m_codeBlockForConstruct->visitAggregate(visitor); + visitor.append(&thisObject->m_unlinkedExecutable); } -PassRefPtr FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) +void FunctionExecutable::clearCodeIfNotCompiling() { - RefPtr program = exec->globalData().parser->parse(&exec->globalData(), debugger, exec, source, errLine, errMsg); - if (!program) - return 0; + if (isCompiling()) + return; + clearCode(); +} - StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - if (!exprStatement || !exprStatement->isExprStatement()) - return 0; +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() +{ + if (isCompiling()) + return; + m_unlinkedExecutable->clearCodeForRecompilation(); +} + +void FunctionExecutable::clearCode() +{ + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); + Base::clearCode(); +} + +void FunctionExecutable::unlinkCalls() +{ +#if ENABLE(JIT) + if (!!m_jitCodeForCall) { + RELEASE_ASSERT(m_codeBlockForCall); + m_codeBlockForCall->unlinkCalls(); + } + if (!!m_jitCodeForConstruct) { + RELEASE_ASSERT(m_codeBlockForConstruct); + m_codeBlockForConstruct->unlinkCalls(); + } +#endif +} - ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); - ASSERT(funcExpr); - ASSERT(funcExpr->isFuncExprNode()); - if (!funcExpr || !funcExpr->isFuncExprNode()) +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** 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); +} - FunctionBodyNode* body = static_cast(funcExpr)->body(); - ASSERT(body); - return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); +String FunctionExecutable::paramString() const +{ + return m_unlinkedExecutable->paramString(); } -UString FunctionExecutable::paramString() const +CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const { - FunctionParameters& parameters = *m_parameters; - StringBuilder builder; - for (size_t pos = 0; pos < parameters.size(); ++pos) { - if (!builder.isEmpty()) - builder.append(", "); - builder.append(parameters[pos].ustring()); - } - return builder.build(); + if (this->classInfo() == &NativeExecutable::s_info) + return jsCast(this)->hashFor(kind); + + return jsCast(this)->hashFor(kind); } -}; +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))); +} +CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const +{ + return CodeBlockHash(source(), kind); +} +}