mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2024-11-23 04:09:40 +00:00
561 lines
21 KiB
C++
561 lines
21 KiB
C++
/*
|
|
* Copyright (C) 2009-2019 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "CodeBlock.h"
|
|
#include "Debugger.h"
|
|
#include "EvalCodeBlock.h"
|
|
#include "FunctionCodeBlock.h"
|
|
#include "GlobalExecutable.h"
|
|
#include "IsoCellSetInlines.h"
|
|
#include "JIT.h"
|
|
#include "JSCellInlines.h"
|
|
#include "JSGlobalObjectInlines.h"
|
|
#include "JSObjectInlines.h"
|
|
#include "JSTemplateObjectDescriptor.h"
|
|
#include "LLIntEntrypoint.h"
|
|
#include "ModuleProgramCodeBlock.h"
|
|
#include "ParserError.h"
|
|
#include "ProgramCodeBlock.h"
|
|
#include "VMInlines.h"
|
|
|
|
namespace JSC {
|
|
|
|
const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ScriptExecutable) };
|
|
|
|
ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, Intrinsic intrinsic)
|
|
: ExecutableBase(vm, structure)
|
|
, m_source(source)
|
|
, m_intrinsic(intrinsic)
|
|
, m_features(isInStrictContext ? StrictModeFeature : 0)
|
|
, m_hasCapturedVariables(false)
|
|
, m_neverInline(false)
|
|
, m_neverOptimize(false)
|
|
, m_neverFTLOptimize(false)
|
|
, m_isArrowFunctionContext(isInArrowFunctionContext)
|
|
, m_canUseOSRExitFuzzing(true)
|
|
, m_codeForGeneratorBodyWasGenerated(false)
|
|
, m_isInsideOrdinaryFunction(isInsideOrdinaryFunction)
|
|
, m_derivedContextType(static_cast<unsigned>(derivedContextType))
|
|
, m_evalContextType(static_cast<unsigned>(evalContextType))
|
|
{
|
|
}
|
|
|
|
void ScriptExecutable::destroy(JSCell* cell)
|
|
{
|
|
static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
|
|
}
|
|
|
|
void ScriptExecutable::clearCode(IsoCellSet& clearableCodeSet)
|
|
{
|
|
m_jitCodeForCall = nullptr;
|
|
m_jitCodeForConstruct = nullptr;
|
|
m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr<JSEntryPtrTag>();
|
|
m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr<JSEntryPtrTag>();
|
|
|
|
switch (type()) {
|
|
case FunctionExecutableType: {
|
|
FunctionExecutable* executable = static_cast<FunctionExecutable*>(this);
|
|
executable->m_codeBlockForCall.clear();
|
|
executable->m_codeBlockForConstruct.clear();
|
|
break;
|
|
}
|
|
case EvalExecutableType: {
|
|
EvalExecutable* executable = static_cast<EvalExecutable*>(this);
|
|
executable->m_evalCodeBlock.clear();
|
|
executable->m_unlinkedEvalCodeBlock.clear();
|
|
break;
|
|
}
|
|
case ProgramExecutableType: {
|
|
ProgramExecutable* executable = static_cast<ProgramExecutable*>(this);
|
|
executable->m_programCodeBlock.clear();
|
|
executable->m_unlinkedProgramCodeBlock.clear();
|
|
break;
|
|
}
|
|
case ModuleProgramExecutableType: {
|
|
ModuleProgramExecutable* executable = static_cast<ModuleProgramExecutable*>(this);
|
|
executable->m_moduleProgramCodeBlock.clear();
|
|
executable->m_unlinkedModuleProgramCodeBlock.clear();
|
|
executable->m_moduleEnvironmentSymbolTable.clear();
|
|
break;
|
|
}
|
|
default:
|
|
RELEASE_ASSERT_NOT_REACHED();
|
|
break;
|
|
}
|
|
|
|
ASSERT(&VM::SpaceAndSet::setFor(*subspace()) == &clearableCodeSet);
|
|
clearableCodeSet.remove(this);
|
|
}
|
|
|
|
void ScriptExecutable::installCode(CodeBlock* codeBlock)
|
|
{
|
|
installCode(codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
|
|
}
|
|
|
|
void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind)
|
|
{
|
|
if (genericCodeBlock)
|
|
CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ());
|
|
|
|
CodeBlock* oldCodeBlock = nullptr;
|
|
|
|
switch (codeType) {
|
|
case GlobalCode: {
|
|
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
|
|
ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock);
|
|
|
|
ASSERT(kind == CodeForCall);
|
|
|
|
oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get());
|
|
executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
|
|
break;
|
|
}
|
|
|
|
case ModuleCode: {
|
|
ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
|
|
ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock);
|
|
|
|
ASSERT(kind == CodeForCall);
|
|
|
|
oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get());
|
|
executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
|
|
break;
|
|
}
|
|
|
|
case EvalCode: {
|
|
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
|
|
EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock);
|
|
|
|
ASSERT(kind == CodeForCall);
|
|
|
|
oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get());
|
|
executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
|
|
break;
|
|
}
|
|
|
|
case FunctionCode: {
|
|
FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
|
|
FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock);
|
|
|
|
switch (kind) {
|
|
case CodeForCall:
|
|
oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get());
|
|
executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
|
|
break;
|
|
case CodeForConstruct:
|
|
oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get());
|
|
executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (kind) {
|
|
case CodeForCall:
|
|
m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
|
|
m_jitCodeForCallWithArityCheck = nullptr;
|
|
break;
|
|
case CodeForConstruct:
|
|
m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
|
|
m_jitCodeForConstructWithArityCheck = nullptr;
|
|
break;
|
|
}
|
|
|
|
auto& clearableCodeSet = VM::SpaceAndSet::setFor(*subspace());
|
|
if (hasClearableCode(vm))
|
|
clearableCodeSet.add(this);
|
|
else
|
|
clearableCodeSet.remove(this);
|
|
|
|
if (genericCodeBlock) {
|
|
RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
|
|
RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
|
|
|
|
dataLogLnIf(Options::verboseOSR(), "Installing ", *genericCodeBlock);
|
|
|
|
if (UNLIKELY(vm.m_perBytecodeProfiler))
|
|
vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock);
|
|
|
|
Debugger* debugger = genericCodeBlock->globalObject()->debugger();
|
|
if (UNLIKELY(debugger))
|
|
debugger->registerCodeBlock(genericCodeBlock);
|
|
}
|
|
|
|
if (oldCodeBlock)
|
|
oldCodeBlock->unlinkIncomingCalls();
|
|
|
|
vm.heap.writeBarrier(this);
|
|
}
|
|
|
|
bool ScriptExecutable::hasClearableCode(VM& vm) const
|
|
{
|
|
if (m_jitCodeForCall
|
|
|| m_jitCodeForConstruct
|
|
|| m_jitCodeForCallWithArityCheck
|
|
|| m_jitCodeForConstructWithArityCheck)
|
|
return true;
|
|
|
|
if (structure(vm)->classInfo() == FunctionExecutable::info()) {
|
|
auto* executable = static_cast<const FunctionExecutable*>(this);
|
|
if (executable->m_codeBlockForCall || executable->m_codeBlockForConstruct)
|
|
return true;
|
|
|
|
} else if (structure(vm)->classInfo() == EvalExecutable::info()) {
|
|
auto* executable = static_cast<const EvalExecutable*>(this);
|
|
if (executable->m_evalCodeBlock || executable->m_unlinkedEvalCodeBlock)
|
|
return true;
|
|
|
|
} else if (structure(vm)->classInfo() == ProgramExecutable::info()) {
|
|
auto* executable = static_cast<const ProgramExecutable*>(this);
|
|
if (executable->m_programCodeBlock || executable->m_unlinkedProgramCodeBlock)
|
|
return true;
|
|
|
|
} else if (structure(vm)->classInfo() == ModuleProgramExecutable::info()) {
|
|
auto* executable = static_cast<const ModuleProgramExecutable*>(this);
|
|
if (executable->m_moduleProgramCodeBlock
|
|
|| executable->m_unlinkedModuleProgramCodeBlock
|
|
|| executable->m_moduleEnvironmentSymbolTable)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CodeBlock* ScriptExecutable::newCodeBlockFor(
|
|
CodeSpecializationKind kind, JSFunction* function, JSScope* scope, Exception*& exception)
|
|
{
|
|
VM& vm = scope->vm();
|
|
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
ASSERT(vm.heap.isDeferred());
|
|
ASSERT(endColumn() != UINT_MAX);
|
|
|
|
JSGlobalObject* globalObject = scope->globalObject(vm);
|
|
|
|
if (classInfo(vm) == EvalExecutable::info()) {
|
|
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
RELEASE_ASSERT(!executable->m_evalCodeBlock);
|
|
RELEASE_ASSERT(!function);
|
|
auto* codeBlock = EvalCodeBlock::create(vm,
|
|
executable, executable->m_unlinkedEvalCodeBlock.get(), scope);
|
|
EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
|
|
if (!codeBlock) {
|
|
exception = throwException(
|
|
globalObject, throwScope,
|
|
createOutOfMemoryError(globalObject));
|
|
return nullptr;
|
|
}
|
|
return codeBlock;
|
|
}
|
|
|
|
if (classInfo(vm) == ProgramExecutable::info()) {
|
|
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
RELEASE_ASSERT(!executable->m_programCodeBlock);
|
|
RELEASE_ASSERT(!function);
|
|
auto* codeBlock = ProgramCodeBlock::create(vm,
|
|
executable, executable->m_unlinkedProgramCodeBlock.get(), scope);
|
|
EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
|
|
if (!codeBlock) {
|
|
exception = throwException(
|
|
globalObject, throwScope,
|
|
createOutOfMemoryError(globalObject));
|
|
return nullptr;
|
|
}
|
|
return codeBlock;
|
|
}
|
|
|
|
if (classInfo(vm) == ModuleProgramExecutable::info()) {
|
|
ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
|
|
RELEASE_ASSERT(!function);
|
|
auto* codeBlock = ModuleProgramCodeBlock::create(vm,
|
|
executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope);
|
|
EXCEPTION_ASSERT(throwScope.exception() || codeBlock);
|
|
if (!codeBlock) {
|
|
exception = throwException(
|
|
globalObject, throwScope,
|
|
createOutOfMemoryError(globalObject));
|
|
return nullptr;
|
|
}
|
|
return codeBlock;
|
|
}
|
|
|
|
RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info());
|
|
RELEASE_ASSERT(function);
|
|
FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
|
|
RELEASE_ASSERT(!executable->codeBlockFor(kind));
|
|
ParserError error;
|
|
OptionSet<CodeGenerationMode> codeGenerationMode = globalObject->defaultCodeGenerationMode();
|
|
// We continue using the same CodeGenerationMode for Generators because live generator objects can
|
|
// keep the state which is only valid with the CodeBlock compiled with the same CodeGenerationMode.
|
|
if (isGeneratorOrAsyncFunctionBodyParseMode(executable->parseMode())) {
|
|
if (!m_codeForGeneratorBodyWasGenerated) {
|
|
m_codeGenerationModeForGeneratorBody = codeGenerationMode;
|
|
m_codeForGeneratorBodyWasGenerated = true;
|
|
} else
|
|
codeGenerationMode = m_codeGenerationModeForGeneratorBody;
|
|
}
|
|
UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
|
|
executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
|
|
vm, executable->source(), kind, codeGenerationMode, error,
|
|
executable->parseMode());
|
|
recordParse(
|
|
executable->m_unlinkedExecutable->features(),
|
|
executable->m_unlinkedExecutable->hasCapturedVariables(),
|
|
lastLine(), endColumn());
|
|
if (!unlinkedCodeBlock) {
|
|
exception = throwException(
|
|
globalObject, throwScope,
|
|
error.toErrorObject(globalObject, executable->source()));
|
|
return nullptr;
|
|
}
|
|
|
|
auto* codeBlock = FunctionCodeBlock::create(vm, executable, unlinkedCodeBlock, scope);
|
|
if (throwScope.exception())
|
|
exception = throwScope.exception();
|
|
return codeBlock;
|
|
}
|
|
|
|
CodeBlock* ScriptExecutable::newReplacementCodeBlockFor(
|
|
CodeSpecializationKind kind)
|
|
{
|
|
VM& vm = this->vm();
|
|
if (classInfo(vm) == EvalExecutable::info()) {
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
|
|
EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>(
|
|
executable->codeBlock()->baselineVersion());
|
|
EvalCodeBlock* result = EvalCodeBlock::create(vm,
|
|
CodeBlock::CopyParsedBlock, *baseline);
|
|
result->setAlternative(vm, baseline);
|
|
return result;
|
|
}
|
|
|
|
if (classInfo(vm) == ProgramExecutable::info()) {
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
|
|
ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>(
|
|
executable->codeBlock()->baselineVersion());
|
|
ProgramCodeBlock* result = ProgramCodeBlock::create(vm,
|
|
CodeBlock::CopyParsedBlock, *baseline);
|
|
result->setAlternative(vm, baseline);
|
|
return result;
|
|
}
|
|
|
|
if (classInfo(vm) == ModuleProgramExecutable::info()) {
|
|
RELEASE_ASSERT(kind == CodeForCall);
|
|
ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
|
|
ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>(
|
|
executable->codeBlock()->baselineVersion());
|
|
ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(vm,
|
|
CodeBlock::CopyParsedBlock, *baseline);
|
|
result->setAlternative(vm, baseline);
|
|
return result;
|
|
}
|
|
|
|
RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info());
|
|
FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
|
|
FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>(
|
|
executable->codeBlockFor(kind)->baselineVersion());
|
|
FunctionCodeBlock* result = FunctionCodeBlock::create(vm,
|
|
CodeBlock::CopyParsedBlock, *baseline);
|
|
result->setAlternative(vm, baseline);
|
|
return result;
|
|
}
|
|
|
|
static void setupLLInt(CodeBlock* codeBlock)
|
|
{
|
|
LLInt::setEntrypoint(codeBlock);
|
|
}
|
|
|
|
static void setupJIT(VM& vm, CodeBlock* codeBlock)
|
|
{
|
|
#if ENABLE(JIT)
|
|
CompilationResult result = JIT::compile(vm, codeBlock, JITCompilationMustSucceed);
|
|
RELEASE_ASSERT(result == CompilationSuccessful);
|
|
#else
|
|
UNUSED_PARAM(vm);
|
|
UNUSED_PARAM(codeBlock);
|
|
UNREACHABLE_FOR_PLATFORM();
|
|
#endif
|
|
}
|
|
|
|
Exception* ScriptExecutable::prepareForExecutionImpl(
|
|
VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
|
|
{
|
|
auto throwScope = DECLARE_THROW_SCOPE(vm);
|
|
DeferGCForAWhile deferGC(vm.heap);
|
|
|
|
if (UNLIKELY(vm.getAndClearFailNextNewCodeBlock())) {
|
|
JSGlobalObject* globalObject = scope->globalObject(vm);
|
|
return throwException(globalObject, throwScope, createError(globalObject, "Forced Failure"_s));
|
|
}
|
|
|
|
Exception* exception = nullptr;
|
|
CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception);
|
|
resultCodeBlock = codeBlock;
|
|
EXCEPTION_ASSERT(!!throwScope.exception() == !codeBlock);
|
|
if (UNLIKELY(!codeBlock))
|
|
return exception;
|
|
|
|
if (Options::validateBytecode())
|
|
codeBlock->validate();
|
|
|
|
if (Options::useLLInt())
|
|
setupLLInt(codeBlock);
|
|
else
|
|
setupJIT(vm, codeBlock);
|
|
|
|
installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
|
|
return nullptr;
|
|
}
|
|
|
|
ScriptExecutable* ScriptExecutable::topLevelExecutable()
|
|
{
|
|
switch (type()) {
|
|
case FunctionExecutableType:
|
|
return jsCast<FunctionExecutable*>(this)->topLevelExecutable();
|
|
default:
|
|
return this;
|
|
}
|
|
}
|
|
|
|
JSArray* ScriptExecutable::createTemplateObject(JSGlobalObject* globalObject, JSTemplateObjectDescriptor* descriptor)
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
TemplateObjectMap& templateObjectMap = ensureTemplateObjectMap(vm);
|
|
TemplateObjectMap::AddResult result;
|
|
{
|
|
auto locker = holdLock(cellLock());
|
|
result = templateObjectMap.add(descriptor->endOffset(), WriteBarrier<JSArray>());
|
|
}
|
|
if (JSArray* array = result.iterator->value.get())
|
|
return array;
|
|
JSArray* templateObject = descriptor->createTemplateObject(globalObject);
|
|
RETURN_IF_EXCEPTION(scope, nullptr);
|
|
result.iterator->value.set(vm, this, templateObject);
|
|
return templateObject;
|
|
}
|
|
|
|
auto ScriptExecutable::ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest) -> TemplateObjectMap&
|
|
{
|
|
if (dest)
|
|
return *dest;
|
|
auto result = makeUnique<TemplateObjectMap>();
|
|
WTF::storeStoreFence();
|
|
dest = WTFMove(result);
|
|
return *dest;
|
|
}
|
|
|
|
auto ScriptExecutable::ensureTemplateObjectMap(VM& vm) -> TemplateObjectMap&
|
|
{
|
|
switch (type()) {
|
|
case FunctionExecutableType:
|
|
return static_cast<FunctionExecutable*>(this)->ensureTemplateObjectMap(vm);
|
|
case EvalExecutableType:
|
|
return static_cast<EvalExecutable*>(this)->ensureTemplateObjectMap(vm);
|
|
case ProgramExecutableType:
|
|
return static_cast<ProgramExecutable*>(this)->ensureTemplateObjectMap(vm);
|
|
case ModuleProgramExecutableType:
|
|
default:
|
|
ASSERT(type() == ModuleProgramExecutableType);
|
|
return static_cast<ModuleProgramExecutable*>(this)->ensureTemplateObjectMap(vm);
|
|
}
|
|
}
|
|
|
|
CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const
|
|
{
|
|
return CodeBlockHash(source(), kind);
|
|
}
|
|
|
|
Optional<int> ScriptExecutable::overrideLineNumber(VM& vm) const
|
|
{
|
|
if (inherits<FunctionExecutable>(vm))
|
|
return jsCast<const FunctionExecutable*>(this)->overrideLineNumber();
|
|
return WTF::nullopt;
|
|
}
|
|
|
|
unsigned ScriptExecutable::typeProfilingStartOffset(VM& vm) const
|
|
{
|
|
if (inherits<FunctionExecutable>(vm))
|
|
return jsCast<const FunctionExecutable*>(this)->typeProfilingStartOffset(vm);
|
|
if (inherits<EvalExecutable>(vm))
|
|
return UINT_MAX;
|
|
return 0;
|
|
}
|
|
|
|
unsigned ScriptExecutable::typeProfilingEndOffset(VM& vm) const
|
|
{
|
|
if (inherits<FunctionExecutable>(vm))
|
|
return jsCast<const FunctionExecutable*>(this)->typeProfilingEndOffset(vm);
|
|
if (inherits<EvalExecutable>(vm))
|
|
return UINT_MAX;
|
|
return source().length() - 1;
|
|
}
|
|
|
|
void ScriptExecutable::recordParse(CodeFeatures features, bool hasCapturedVariables, int lastLine, unsigned endColumn)
|
|
{
|
|
switch (type()) {
|
|
case FunctionExecutableType:
|
|
// Since UnlinkedFunctionExecutable holds the information to calculate lastLine and endColumn, we do not need to remember them in ScriptExecutable's fields.
|
|
jsCast<FunctionExecutable*>(this)->recordParse(features, hasCapturedVariables);
|
|
return;
|
|
default:
|
|
jsCast<GlobalExecutable*>(this)->recordParse(features, hasCapturedVariables, lastLine, endColumn);
|
|
return;
|
|
}
|
|
}
|
|
|
|
int ScriptExecutable::lastLine() const
|
|
{
|
|
switch (type()) {
|
|
case FunctionExecutableType:
|
|
return jsCast<const FunctionExecutable*>(this)->lastLine();
|
|
default:
|
|
return jsCast<const GlobalExecutable*>(this)->lastLine();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned ScriptExecutable::endColumn() const
|
|
{
|
|
switch (type()) {
|
|
case FunctionExecutableType:
|
|
return jsCast<const FunctionExecutable*>(this)->endColumn();
|
|
default:
|
|
return jsCast<const GlobalExecutable*>(this)->endColumn();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
} // namespace JSC
|