diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/Executable.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/Executable.cpp | 638 |
1 files changed, 221 insertions, 417 deletions
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index 8a55026e2..bbd6ed23e 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2013, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,78 +27,37 @@ #include "Executable.h" #include "BatchedTransitionOptimizer.h" +#include "BytecodeGenerator.h" #include "CodeBlock.h" #include "DFGDriver.h" #include "JIT.h" -#include "JSCInlines.h" -#include "JSWASMModule.h" #include "LLIntEntrypoint.h" +#include "Operations.h" #include "Parser.h" -#include "ProfilerDatabase.h" -#include "TypeProfiler.h" -#include "WASMFunctionParser.h" -#include <wtf/CommaPrinter.h> #include <wtf/Vector.h> #include <wtf/text/StringBuilder.h> namespace JSC { -const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +#if ENABLE(JIT) void ExecutableBase::destroy(JSCell* cell) { static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase(); } +#endif void ExecutableBase::clearCode() { #if ENABLE(JIT) - m_jitCodeForCall = nullptr; - m_jitCodeForConstruct = nullptr; + 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 (classInfo() == FunctionExecutable::info()) { - FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); - executable->m_codeBlockForCall.clear(); - executable->m_codeBlockForConstruct.clear(); - return; - } - - if (classInfo() == EvalExecutable::info()) { - EvalExecutable* executable = jsCast<EvalExecutable*>(this); - executable->m_evalCodeBlock.clear(); - executable->m_unlinkedEvalCodeBlock.clear(); - return; - } - - if (classInfo() == ProgramExecutable::info()) { - ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); - executable->m_programCodeBlock.clear(); - executable->m_unlinkedProgramCodeBlock.clear(); - return; - } - - if (classInfo() == ModuleProgramExecutable::info()) { - ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); - executable->m_moduleProgramCodeBlock.clear(); - executable->m_unlinkedModuleProgramCodeBlock.clear(); - executable->m_moduleEnvironmentSymbolTable.clear(); - return; - } - -#if ENABLE(WEBASSEMBLY) - if (classInfo() == WebAssemblyExecutable::info()) { - WebAssemblyExecutable* executable = jsCast<WebAssemblyExecutable*>(this); - executable->m_codeBlockForCall.clear(); - return; - } -#endif - - ASSERT(classInfo() == NativeExecutable::info()); } #if ENABLE(DFG_JIT) @@ -115,12 +74,14 @@ Intrinsic ExecutableBase::intrinsic() const } #endif -const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +#if ENABLE(JIT) void NativeExecutable::destroy(JSCell* cell) { static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable(); } +#endif #if ENABLE(DFG_JIT) Intrinsic NativeExecutable::intrinsic() const @@ -129,75 +90,66 @@ Intrinsic NativeExecutable::intrinsic() const } #endif -const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; - -ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext) - : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED) - , m_features(isInStrictContext ? StrictModeFeature : 0) - , m_didTryToEnterInLoop(false) - , m_hasCapturedVariables(false) - , m_neverInline(false) - , m_neverOptimize(false) - , m_isArrowFunctionContext(isInArrowFunctionContext) - , m_derivedContextType(static_cast<unsigned>(derivedContextType)) - , m_overrideLineNumber(-1) - , m_firstLine(-1) - , m_lastLine(-1) - , m_startColumn(UINT_MAX) - , m_endColumn(UINT_MAX) - , m_typeProfilingStartOffset(UINT_MAX) - , m_typeProfilingEndOffset(UINT_MAX) - , m_source(source) -{ -} +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; +#if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); } +#endif -void ScriptExecutable::installCode(CodeBlock* codeBlock) -{ - installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); -} - -void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind) +void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) { + RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); + RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); + + VM& vm = *genericCodeBlock->vm(); + + if (vm.m_perBytecodeProfiler) + vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock); + ASSERT(vm.heap.isDeferred()); - CodeBlock* oldCodeBlock = nullptr; + CodeSpecializationKind kind = genericCodeBlock->specializationKind(); + + RefPtr<CodeBlock> oldCodeBlock; - switch (codeType) { + switch (kind) { + case CodeForCall: + m_jitCodeForCall = genericCodeBlock->jitCode(); + m_jitCodeForCallWithArityCheck = genericCodeBlock->jitCodeWithArityCheck(); + m_numParametersForCall = genericCodeBlock->numParameters(); + break; + case CodeForConstruct: + m_jitCodeForConstruct = genericCodeBlock->jitCode(); + m_jitCodeForConstructWithArityCheck = genericCodeBlock->jitCodeWithArityCheck(); + m_numParametersForConstruct = genericCodeBlock->numParameters(); + break; + } + + switch (genericCodeBlock->codeType()) { case GlobalCode: { ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); + ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); - oldCodeBlock = executable->m_programCodeBlock.get(); - executable->m_programCodeBlock.setMayBeNull(vm, this, codeBlock); - break; - } - - case ModuleCode: { - ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); - ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock); - - ASSERT(kind == CodeForCall); - - oldCodeBlock = executable->m_moduleProgramCodeBlock.get(); - executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, codeBlock); + oldCodeBlock = executable->m_programCodeBlock; + executable->m_programCodeBlock = codeBlock; break; } - + case EvalCode: { EvalExecutable* executable = jsCast<EvalExecutable*>(this); EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock); + ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); - oldCodeBlock = executable->m_evalCodeBlock.get(); - executable->m_evalCodeBlock.setMayBeNull(vm, this, codeBlock); + oldCodeBlock = executable->m_evalCodeBlock; + executable->m_evalCodeBlock = codeBlock; break; } @@ -207,53 +159,27 @@ void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType switch (kind) { case CodeForCall: - oldCodeBlock = executable->m_codeBlockForCall.get(); - executable->m_codeBlockForCall.setMayBeNull(vm, this, codeBlock); + oldCodeBlock = executable->m_codeBlockForCall; + executable->m_codeBlockForCall = codeBlock; break; case CodeForConstruct: - oldCodeBlock = executable->m_codeBlockForConstruct.get(); - executable->m_codeBlockForConstruct.setMayBeNull(vm, this, codeBlock); + oldCodeBlock = executable->m_codeBlockForConstruct; + executable->m_codeBlockForConstruct = codeBlock; break; } break; - } - } - - switch (kind) { - case CodeForCall: - m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr; - m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); - m_numParametersForCall = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED; - break; - case CodeForConstruct: - m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr; - m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr(); - m_numParametersForConstruct = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED; - break; - } - - if (genericCodeBlock) { - RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this); - RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType())); - - if (Options::verboseOSR()) - dataLog("Installing ", *genericCodeBlock, "\n"); - - if (vm.m_perBytecodeProfiler) - vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock); - - if (Debugger* debugger = genericCodeBlock->globalObject()->debugger()) - debugger->registerCodeBlock(genericCodeBlock); - } + } } if (oldCodeBlock) oldCodeBlock->unlinkIncomingCalls(); - vm.heap.writeBarrier(this); + Debugger* debugger = genericCodeBlock->globalObject()->debugger(); + if (debugger) + debugger->registerCodeBlock(genericCodeBlock); } -CodeBlock* ScriptExecutable::newCodeBlockFor( - CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception) +PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( + CodeSpecializationKind kind, JSScope* scope, JSObject*& exception) { VM* vm = scope->vm(); @@ -265,64 +191,47 @@ CodeBlock* ScriptExecutable::newCodeBlockFor( EvalExecutable* executable = jsCast<EvalExecutable*>(this); RELEASE_ASSERT(kind == CodeForCall); RELEASE_ASSERT(!executable->m_evalCodeBlock); - RELEASE_ASSERT(!function); - return EvalCodeBlock::create(vm, + return adoptRef(new EvalCodeBlock( executable, executable->m_unlinkedEvalCodeBlock.get(), scope, - executable->source().provider()); + executable->source().provider())); } if (classInfo() == ProgramExecutable::info()) { ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); RELEASE_ASSERT(kind == CodeForCall); RELEASE_ASSERT(!executable->m_programCodeBlock); - RELEASE_ASSERT(!function); - return ProgramCodeBlock::create(vm, + return adoptRef(new ProgramCodeBlock( executable, executable->m_unlinkedProgramCodeBlock.get(), scope, - executable->source().provider(), executable->source().startColumn()); - } - - if (classInfo() == ModuleProgramExecutable::info()) { - ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); - RELEASE_ASSERT(kind == CodeForCall); - RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock); - RELEASE_ASSERT(!function); - return ModuleProgramCodeBlock::create(vm, - executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope, - executable->source().provider(), executable->source().startColumn()); + executable->source().provider(), executable->source().startColumn())); } - + RELEASE_ASSERT(classInfo() == FunctionExecutable::info()); - RELEASE_ASSERT(function); FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); RELEASE_ASSERT(!executable->codeBlockFor(kind)); JSGlobalObject* globalObject = scope->globalObject(); ParserError error; DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff; - ProfilerMode profilerMode = globalObject->hasLegacyProfiler() ? ProfilerOn : ProfilerOff; - UnlinkedFunctionCodeBlock* unlinkedCodeBlock = - executable->m_unlinkedExecutable->unlinkedCodeBlockFor( - *vm, executable->m_source, kind, debuggerMode, profilerMode, error, - executable->parseMode()); - recordParse( - executable->m_unlinkedExecutable->features(), - executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), - lastLine(), startColumn(), endColumn()); + ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff; + UnlinkedFunctionCodeBlock* unlinkedCodeBlock = + executable->m_unlinkedExecutable->codeBlockFor( + *vm, executable->m_source, kind, debuggerMode, profilerMode, error); + recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn()); if (!unlinkedCodeBlock) { exception = vm->throwException( globalObject->globalExec(), error.toErrorObject(globalObject, executable->m_source)); - return nullptr; + return 0; } - + SourceProvider* provider = executable->source().provider(); unsigned sourceOffset = executable->source().startOffset(); unsigned startColumn = executable->source().startColumn(); - return FunctionCodeBlock::create(vm, - executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn); + return adoptRef(new FunctionCodeBlock( + executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn)); } -CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( +PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( CodeSpecializationKind kind) { if (classInfo() == EvalExecutable::info()) { @@ -330,9 +239,9 @@ CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( EvalExecutable* executable = jsCast<EvalExecutable*>(this); EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>( executable->m_evalCodeBlock->baselineVersion()); - EvalCodeBlock* result = EvalCodeBlock::create(vm(), - CodeBlock::CopyParsedBlock, *baseline); - result->setAlternative(*vm(), baseline); + RefPtr<EvalCodeBlock> result = adoptRef(new EvalCodeBlock( + CodeBlock::CopyParsedBlock, *baseline)); + result->setAlternative(baseline); return result; } @@ -341,20 +250,9 @@ CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>( executable->m_programCodeBlock->baselineVersion()); - ProgramCodeBlock* result = ProgramCodeBlock::create(vm(), - CodeBlock::CopyParsedBlock, *baseline); - result->setAlternative(*vm(), baseline); - return result; - } - - if (classInfo() == ModuleProgramExecutable::info()) { - RELEASE_ASSERT(kind == CodeForCall); - ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); - ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>( - executable->m_moduleProgramCodeBlock->baselineVersion()); - ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(vm(), - CodeBlock::CopyParsedBlock, *baseline); - result->setAlternative(*vm(), baseline); + RefPtr<ProgramCodeBlock> result = adoptRef(new ProgramCodeBlock( + CodeBlock::CopyParsedBlock, *baseline)); + result->setAlternative(baseline); return result; } @@ -362,15 +260,21 @@ CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( 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); + RefPtr<FunctionCodeBlock> result = adoptRef(new FunctionCodeBlock( + CodeBlock::CopyParsedBlock, *baseline)); + result->setAlternative(baseline); return result; } static void setupLLInt(VM& vm, CodeBlock* codeBlock) { +#if ENABLE(LLINT) LLInt::setEntrypoint(vm, codeBlock); +#else + UNUSED_PARAM(vm); + UNUSED_PARAM(codeBlock); + UNREACHABLE_FOR_PLATFORM(); +#endif } static void setupJIT(VM& vm, CodeBlock* codeBlock) @@ -386,16 +290,13 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock) } JSObject* ScriptExecutable::prepareForExecutionImpl( - ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind) + ExecState* exec, JSScope* scope, CodeSpecializationKind kind) { VM& vm = exec->vm(); DeferGC deferGC(vm.heap); - - if (vm.getAndClearFailNextNewCodeBlock()) - return createError(exec->callerFrame(), ASCIILiteral("Forced Failure")); - + JSObject* exception = 0; - CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception); + RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, scope, exception); if (!codeBlock) { RELEASE_ASSERT(exception); return exception; @@ -404,18 +305,29 @@ JSObject* ScriptExecutable::prepareForExecutionImpl( if (Options::validateBytecode()) codeBlock->validate(); - if (Options::useLLInt()) - setupLLInt(vm, codeBlock); + bool shouldUseLLInt; +#if !ENABLE(JIT) + // No JIT implies use of the C Loop LLINT. Override the options to reflect this. + Options::useLLInt() = true; + shouldUseLLInt = true; +#elif ENABLE(LLINT) + shouldUseLLInt = Options::useLLInt(); +#else + shouldUseLLInt = false; +#endif + + if (shouldUseLLInt) + setupLLInt(vm, codeBlock.get()); else - setupJIT(vm, codeBlock); + setupJIT(vm, codeBlock.get()); - installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); + installCode(codeBlock.get()); return 0; } -const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) }; +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ) +EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { JSGlobalObject* globalObject = exec->lexicalGlobalObject(); if (!globalObject->evalEnabled()) { @@ -423,10 +335,10 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source return 0; } - EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext, derivedContextType, isArrowFunctionContext); + EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); executable->finishCreation(exec->vm()); - UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, isArrowFunctionContext, variablesUnderTDZ); + UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable); if (!unlinkedEvalCode) return 0; @@ -435,8 +347,8 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source return executable; } -EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext) - : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext, derivedContextType, isArrowFunctionContext) +EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) { } @@ -445,15 +357,11 @@ void EvalExecutable::destroy(JSCell* cell) static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); } -const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false) + : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) { - m_typeProfilingStartOffset = 0; - m_typeProfilingEndOffset = source.length() - 1; - if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler()) - exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset); } void ProgramExecutable::destroy(JSCell* cell) @@ -461,43 +369,12 @@ void ProgramExecutable::destroy(JSCell* cell) static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); } -const ClassInfo ModuleProgramExecutable::s_info = { "ModuleProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ModuleProgramExecutable) }; - -ModuleProgramExecutable::ModuleProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false) -{ - m_typeProfilingStartOffset = 0; - m_typeProfilingEndOffset = source.length() - 1; - if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler()) - exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset); -} - -ModuleProgramExecutable* ModuleProgramExecutable::create(ExecState* exec, const SourceCode& source) -{ - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - ModuleProgramExecutable* executable = new (NotNull, allocateCell<ModuleProgramExecutable>(*exec->heap())) ModuleProgramExecutable(exec, source); - executable->finishCreation(exec->vm()); - - UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCode = globalObject->createModuleProgramCodeBlock(exec, executable); - if (!unlinkedModuleProgramCode) - return nullptr; - executable->m_unlinkedModuleProgramCodeBlock.set(exec->vm(), executable, unlinkedModuleProgramCode); +const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; - executable->m_moduleEnvironmentSymbolTable.set(exec->vm(), executable, jsCast<SymbolTable*>(unlinkedModuleProgramCode->constantRegister(unlinkedModuleProgramCode->moduleEnvironmentSymbolTableConstantRegisterOffset()).get())->cloneScopePart(exec->vm())); - - return executable; -} - -void ModuleProgramExecutable::destroy(JSCell* cell) -{ - static_cast<ModuleProgramExecutable*>(cell)->ModuleProgramExecutable::~ModuleProgramExecutable(); -} - -const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; - -FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn) - : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext(), unlinkedExecutable->derivedContextType(), false) +FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces) + : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext()) , m_unlinkedExecutable(vm, this, unlinkedExecutable) + , m_bodyIncludesBraces(bodyIncludesBraces) { RELEASE_ASSERT(!source.isNull()); ASSERT(source.length()); @@ -507,15 +384,6 @@ FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, Unlinke ASSERT(endColumn != UINT_MAX); m_startColumn = startColumn; m_endColumn = endColumn; - m_parametersStartOffset = unlinkedExecutable->parametersStartOffset(); - m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset(); - m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset(); -} - -void FunctionExecutable::finishCreation(VM& vm) -{ - Base::finishCreation(vm); - m_singletonFunction.set(vm, this, InferredValue::create(vm)); } void FunctionExecutable::destroy(JSCell* cell) @@ -544,10 +412,29 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_unlinkedEvalCodeBlock); if (thisObject->m_evalCodeBlock) - thisObject->m_evalCodeBlock->visitWeakly(visitor); + 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 EvalExecutable::clearCode() +{ + m_evalCodeBlock.clear(); + m_unlinkedEvalCodeBlock.clear(); + Base::clearCode(); } JSObject* ProgramExecutable::checkSyntax(ExecState* exec) @@ -555,15 +442,23 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) ParserError error; VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>( - vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, - JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error); + RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); if (programNode) return 0; - ASSERT(error.isValid()); + ASSERT(error.m_type != ParserError::ErrorNone); return error.toErrorObject(lexicalGlobalObject, m_source); } +void ProgramExecutable::unlinkCalls() +{ +#if ENABLE(JIT) + if (!m_jitCodeForCall) + return; + RELEASE_ASSERT(m_programCodeBlock); + m_programCodeBlock->unlinkCalls(); +#endif +} + JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { RELEASE_ASSERT(scope); @@ -576,73 +471,24 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF if (exception) return exception; - JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment(); - const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); - const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations(); - // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope. - // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation - { - ExecState* exec = globalObject->globalExec(); - // Check for intersection of "var" and "let"/"const"/"class" - for (auto& entry : lexicalDeclarations) { - if (variableDeclarations.contains(entry.key)) - return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); - } - - // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables. - // It's an error to introduce a shadow. - for (auto& entry : lexicalDeclarations) { - if (globalObject->hasProperty(exec, entry.key.get())) - return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'")); - - if (globalLexicalEnvironment->hasProperty(exec, entry.key.get())) - return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); - } - - // Check if any new "var"s will shadow any previous "let"/"const"/"class" names. - // It's an error to introduce a shadow. - if (!globalLexicalEnvironment->isEmpty()) { - for (auto& entry : variableDeclarations) { - if (globalLexicalEnvironment->hasProperty(exec, entry.key.get())) - return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); - } - } - } - - m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); BatchedTransitionOptimizer optimizer(vm, globalObject); - for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { - UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); - ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); - globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); - if (vm.typeProfiler() || vm.controlFlowProfiler()) { - vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), - unlinkedFunctionExecutable->typeProfilingStartOffset(), - unlinkedFunctionExecutable->typeProfilingEndOffset()); - } - } + const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); + const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); - for (auto& entry : variableDeclarations) { - ASSERT(entry.value.isVar()); - globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); + for (size_t i = 0; i < functionDeclarations.size(); ++i) { + UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get(); + JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo(), 0), scope); + globalObject->addFunction(callFrame, functionDeclarations[i].first, value); } - { - JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope()); - SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable(); - ConcurrentJITLocker locker(symbolTable->m_lock); - for (auto& entry : lexicalDeclarations) { - ScopeOffset offset = symbolTable->takeNextScopeOffset(locker); - SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0); - newEntry.prepareToWatch(); - symbolTable->add(locker, entry.key.get(), newEntry); - - ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue()); - RELEASE_ASSERT(offsetForAssert == offset); - } + for (size_t i = 0; i < variableDeclarations.size(); ++i) { + if (variableDeclarations[i].second & DeclarationStacks::IsConstant) + globalObject->addConst(callFrame, variableDeclarations[i].first); + else + globalObject->addVar(callFrame, variableDeclarations[i].first); } return 0; } @@ -651,21 +497,19 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, 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->visitWeakly(visitor); + thisObject->m_programCodeBlock->visitAggregate(visitor); } -void ModuleProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +void ProgramExecutable::clearCode() { - ModuleProgramExecutable* thisObject = jsCast<ModuleProgramExecutable*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - ScriptExecutable::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_unlinkedModuleProgramCodeBlock); - visitor.append(&thisObject->m_moduleEnvironmentSymbolTable); - if (thisObject->m_moduleProgramCodeBlock) - thisObject->m_moduleProgramCodeBlock->visitWeakly(visitor); + m_programCodeBlock.clear(); + m_unlinkedProgramCodeBlock.clear(); + Base::clearCode(); } FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) @@ -686,124 +530,84 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); ScriptExecutable::visitChildren(thisObject, visitor); if (thisObject->m_codeBlockForCall) - thisObject->m_codeBlockForCall->visitWeakly(visitor); + thisObject->m_codeBlockForCall->visitAggregate(visitor); if (thisObject->m_codeBlockForConstruct) - thisObject->m_codeBlockForConstruct->visitWeakly(visitor); + thisObject->m_codeBlockForConstruct->visitAggregate(visitor); visitor.append(&thisObject->m_unlinkedExecutable); - visitor.append(&thisObject->m_singletonFunction); } -FunctionExecutable* FunctionExecutable::fromGlobalCode( - const Identifier& name, ExecState& exec, const SourceCode& source, - JSObject*& exception, int overrideLineNumber) +SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) { - UnlinkedFunctionExecutable* unlinkedExecutable = - UnlinkedFunctionExecutable::fromGlobalCode( - name, exec, source, exception, overrideLineNumber); - if (!unlinkedExecutable) - return nullptr; - - return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); + return codeBlockFor(kind)->symbolTable(); } -#if ENABLE(WEBASSEMBLY) -const ClassInfo WebAssemblyExecutable::s_info = { "WebAssemblyExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(WebAssemblyExecutable) }; - -WebAssemblyExecutable::WebAssemblyExecutable(VM& vm, const SourceCode& source, JSWASMModule* module, unsigned functionIndex) - : ExecutableBase(vm, vm.webAssemblyExecutableStructure.get(), NUM_PARAMETERS_NOT_COMPILED) - , m_source(source) - , m_module(vm, this, module) - , m_functionIndex(functionIndex) +void FunctionExecutable::clearCodeIfNotCompiling() { + if (isCompiling()) + return; + clearCode(); } -void WebAssemblyExecutable::destroy(JSCell* cell) +void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() { - static_cast<WebAssemblyExecutable*>(cell)->WebAssemblyExecutable::~WebAssemblyExecutable(); + if (isCompiling()) + return; + m_unlinkedExecutable->clearCodeForRecompilation(); } -void WebAssemblyExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) +void FunctionExecutable::clearCode() { - WebAssemblyExecutable* thisObject = jsCast<WebAssemblyExecutable*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - ExecutableBase::visitChildren(thisObject, visitor); - if (thisObject->m_codeBlockForCall) - thisObject->m_codeBlockForCall->visitWeakly(visitor); - visitor.append(&thisObject->m_module); + m_codeBlockForCall.clear(); + m_codeBlockForConstruct.clear(); + Base::clearCode(); } -void WebAssemblyExecutable::prepareForExecution(ExecState* exec) +void FunctionExecutable::unlinkCalls() { - if (hasJITCodeForCall()) - return; - - VM& vm = exec->vm(); - DeferGC deferGC(vm.heap); - - WebAssemblyCodeBlock* codeBlock = WebAssemblyCodeBlock::create(&vm, - this, exec->lexicalGlobalObject()); - - WASMFunctionParser::compile(vm, codeBlock, m_module.get(), m_source, m_functionIndex); +#if ENABLE(JIT) + if (!!m_jitCodeForCall) { + RELEASE_ASSERT(m_codeBlockForCall); + m_codeBlockForCall->unlinkCalls(); + } + if (!!m_jitCodeForConstruct) { + RELEASE_ASSERT(m_codeBlockForConstruct); + m_codeBlockForConstruct->unlinkCalls(); + } +#endif +} - m_jitCodeForCall = codeBlock->jitCode(); - m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); - m_numParametersForCall = codeBlock->numParameters(); +FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +{ + UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception); + if (!unlinkedExecutable) + return 0; + unsigned lineCount = unlinkedExecutable->lineCount(); + unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset(); + unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset(); - m_codeBlockForCall.set(vm, this, codeBlock); + // We don't have any owner executable. The source string is effectively like a global + // string (like in the handling of eval). Hence, the startColumn is always 1. + unsigned startColumn = 1; + unsigned sourceLength = unlinkedExecutable->sourceLength(); + bool endColumnIsOnStartLine = !lineCount; + // The unlinkedBodyEndColumn is based-0. Hence, we need to add 1 to it. But if the + // endColumn is on the startLine, then we need to subtract back the adjustment for + // the open brace resulting in an adjustment of 0. + unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1); + unsigned startOffsetExcludingOpenBrace = startOffset + 1; + unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1; + SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, firstLine, startColumn); - Heap::heap(this)->writeBarrier(this); + return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false); } -#endif -void ExecutableBase::dump(PrintStream& out) const +String FunctionExecutable::paramString() const { - ExecutableBase* realThis = const_cast<ExecutableBase*>(this); - - if (classInfo() == NativeExecutable::info()) { - NativeExecutable* native = jsCast<NativeExecutable*>(realThis); - out.print("NativeExecutable:", RawPointer(bitwise_cast<void*>(native->function())), "/", RawPointer(bitwise_cast<void*>(native->constructor()))); - return; - } - - if (classInfo() == EvalExecutable::info()) { - EvalExecutable* eval = jsCast<EvalExecutable*>(realThis); - if (CodeBlock* codeBlock = eval->codeBlock()) - out.print(*codeBlock); - else - out.print("EvalExecutable w/o CodeBlock"); - return; - } - - if (classInfo() == ProgramExecutable::info()) { - ProgramExecutable* eval = jsCast<ProgramExecutable*>(realThis); - if (CodeBlock* codeBlock = eval->codeBlock()) - out.print(*codeBlock); - else - out.print("ProgramExecutable w/o CodeBlock"); - return; - } - - if (classInfo() == ModuleProgramExecutable::info()) { - ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(realThis); - if (CodeBlock* codeBlock = executable->codeBlock()) - out.print(*codeBlock); - else - out.print("ModuleProgramExecutable w/o CodeBlock"); - return; - } - - FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis); - if (!function->eitherCodeBlock()) - out.print("FunctionExecutable w/o CodeBlock"); - else { - CommaPrinter comma("/"); - if (function->codeBlockForCall()) - out.print(comma, *function->codeBlockForCall()); - if (function->codeBlockForConstruct()) - out.print(comma, *function->codeBlockForConstruct()); - } + return m_unlinkedExecutable->paramString(); } CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const |