diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/runtime/Executable.cpp | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/runtime/Executable.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/Executable.cpp | 638 |
1 files changed, 417 insertions, 221 deletions
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp index bbd6ed23e..8a55026e2 100644 --- a/Source/JavaScriptCore/runtime/Executable.cpp +++ b/Source/JavaScriptCore/runtime/Executable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2013, 2015 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,37 +27,78 @@ #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, 0, CREATE_METHOD_TABLE(ExecutableBase) }; +const ClassInfo ExecutableBase::s_info = { "Executable", 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.clear(); - m_jitCodeForConstruct.clear(); + m_jitCodeForCall = nullptr; + m_jitCodeForConstruct = nullptr; 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) @@ -74,14 +115,12 @@ Intrinsic ExecutableBase::intrinsic() const } #endif -const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) }; +const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 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 @@ -90,66 +129,75 @@ Intrinsic NativeExecutable::intrinsic() const } #endif -const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) }; +const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 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) +{ +} -#if ENABLE(JIT) void ScriptExecutable::destroy(JSCell* cell) { static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable(); } -#endif -void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) +void ScriptExecutable::installCode(CodeBlock* codeBlock) +{ + installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); +} + +void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind) { - 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()); - CodeSpecializationKind kind = genericCodeBlock->specializationKind(); - - RefPtr<CodeBlock> oldCodeBlock; + CodeBlock* oldCodeBlock = nullptr; - 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()) { + switch (codeType) { case GlobalCode: { ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock); - ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); - oldCodeBlock = executable->m_programCodeBlock; - executable->m_programCodeBlock = codeBlock; + 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); + break; + } + case EvalCode: { EvalExecutable* executable = jsCast<EvalExecutable*>(this); EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock); - ASSERT(!codeBlock->jitCodeWithArityCheck()); ASSERT(kind == CodeForCall); - oldCodeBlock = executable->m_evalCodeBlock; - executable->m_evalCodeBlock = codeBlock; + oldCodeBlock = executable->m_evalCodeBlock.get(); + executable->m_evalCodeBlock.setMayBeNull(vm, this, codeBlock); break; } @@ -159,27 +207,53 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock) switch (kind) { case CodeForCall: - oldCodeBlock = executable->m_codeBlockForCall; - executable->m_codeBlockForCall = codeBlock; + oldCodeBlock = executable->m_codeBlockForCall.get(); + executable->m_codeBlockForCall.setMayBeNull(vm, this, codeBlock); break; case CodeForConstruct: - oldCodeBlock = executable->m_codeBlockForConstruct; - executable->m_codeBlockForConstruct = codeBlock; + oldCodeBlock = executable->m_codeBlockForConstruct.get(); + executable->m_codeBlockForConstruct.setMayBeNull(vm, this, 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(); - Debugger* debugger = genericCodeBlock->globalObject()->debugger(); - if (debugger) - debugger->registerCodeBlock(genericCodeBlock); + vm.heap.writeBarrier(this); } -PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( - CodeSpecializationKind kind, JSScope* scope, JSObject*& exception) +CodeBlock* ScriptExecutable::newCodeBlockFor( + CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception) { VM* vm = scope->vm(); @@ -191,47 +265,64 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor( EvalExecutable* executable = jsCast<EvalExecutable*>(this); RELEASE_ASSERT(kind == CodeForCall); RELEASE_ASSERT(!executable->m_evalCodeBlock); - return adoptRef(new EvalCodeBlock( + RELEASE_ASSERT(!function); + return EvalCodeBlock::create(vm, 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); - return adoptRef(new ProgramCodeBlock( + RELEASE_ASSERT(!function); + return ProgramCodeBlock::create(vm, executable, executable->m_unlinkedProgramCodeBlock.get(), scope, - executable->source().provider(), executable->source().startColumn())); + 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()); + } + 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->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()); + 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()); if (!unlinkedCodeBlock) { exception = vm->throwException( globalObject->globalExec(), error.toErrorObject(globalObject, executable->m_source)); - return 0; + return nullptr; } - + SourceProvider* provider = executable->source().provider(); unsigned sourceOffset = executable->source().startOffset(); unsigned startColumn = executable->source().startColumn(); - return adoptRef(new FunctionCodeBlock( - executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn)); + return FunctionCodeBlock::create(vm, + executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn); } -PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( +CodeBlock* ScriptExecutable::newReplacementCodeBlockFor( CodeSpecializationKind kind) { if (classInfo() == EvalExecutable::info()) { @@ -239,9 +330,9 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( EvalExecutable* executable = jsCast<EvalExecutable*>(this); EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>( executable->m_evalCodeBlock->baselineVersion()); - RefPtr<EvalCodeBlock> result = adoptRef(new EvalCodeBlock( - CodeBlock::CopyParsedBlock, *baseline)); - result->setAlternative(baseline); + EvalCodeBlock* result = EvalCodeBlock::create(vm(), + CodeBlock::CopyParsedBlock, *baseline); + result->setAlternative(*vm(), baseline); return result; } @@ -250,9 +341,20 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>( executable->m_programCodeBlock->baselineVersion()); - RefPtr<ProgramCodeBlock> result = adoptRef(new ProgramCodeBlock( - CodeBlock::CopyParsedBlock, *baseline)); - result->setAlternative(baseline); + 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); return result; } @@ -260,21 +362,15 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor( FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>( executable->codeBlockFor(kind)->baselineVersion()); - RefPtr<FunctionCodeBlock> result = adoptRef(new FunctionCodeBlock( - CodeBlock::CopyParsedBlock, *baseline)); - result->setAlternative(baseline); + FunctionCodeBlock* result = FunctionCodeBlock::create(vm(), + CodeBlock::CopyParsedBlock, *baseline); + result->setAlternative(*vm(), 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) @@ -290,13 +386,16 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock) } JSObject* ScriptExecutable::prepareForExecutionImpl( - ExecState* exec, JSScope* scope, CodeSpecializationKind kind) + ExecState* exec, JSFunction* function, 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; - RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, scope, exception); + CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception); if (!codeBlock) { RELEASE_ASSERT(exception); return exception; @@ -305,29 +404,18 @@ JSObject* ScriptExecutable::prepareForExecutionImpl( if (Options::validateBytecode()) codeBlock->validate(); - 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()); + if (Options::useLLInt()) + setupLLInt(vm, codeBlock); else - setupJIT(vm, codeBlock.get()); + setupJIT(vm, codeBlock); - installCode(codeBlock.get()); + installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind()); return 0; } -const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) }; +const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) }; -EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext) +EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ) { JSGlobalObject* globalObject = exec->lexicalGlobalObject(); if (!globalObject->evalEnabled()) { @@ -335,10 +423,10 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source return 0; } - EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext); + EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext, derivedContextType, isArrowFunctionContext); executable->finishCreation(exec->vm()); - UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable); + UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, isArrowFunctionContext, variablesUnderTDZ); if (!unlinkedEvalCode) return 0; @@ -347,8 +435,8 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source return executable; } -EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext) - : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext) +EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext) + : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext, derivedContextType, isArrowFunctionContext) { } @@ -357,11 +445,15 @@ void EvalExecutable::destroy(JSCell* cell) static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable(); } -const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; +const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) }; ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source) - : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false) + : ScriptExecutable(exec->vm().programExecutableStructure.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); } void ProgramExecutable::destroy(JSCell* cell) @@ -369,12 +461,43 @@ void ProgramExecutable::destroy(JSCell* cell) static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable(); } -const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) }; +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); -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()) + 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) , m_unlinkedExecutable(vm, this, unlinkedExecutable) - , m_bodyIncludesBraces(bodyIncludesBraces) { RELEASE_ASSERT(!source.isNull()); ASSERT(source.length()); @@ -384,6 +507,15 @@ 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) @@ -412,29 +544,10 @@ 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); - 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 EvalExecutable::clearCode() -{ - m_evalCodeBlock.clear(); - m_unlinkedEvalCodeBlock.clear(); - Base::clearCode(); + if (thisObject->m_evalCodeBlock) + thisObject->m_evalCodeBlock->visitWeakly(visitor); } JSObject* ProgramExecutable::checkSyntax(ExecState* exec) @@ -442,23 +555,15 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec) ParserError error; VM* vm = &exec->vm(); JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); - RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error); + std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>( + vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error); if (programNode) return 0; - ASSERT(error.m_type != ParserError::ErrorNone); + ASSERT(error.isValid()); 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); @@ -471,24 +576,73 @@ 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); - const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); - const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations(); + 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()); + } + } - 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); + for (auto& entry : variableDeclarations) { + ASSERT(entry.value.isVar()); + globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); } - 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); + { + 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); + } } return 0; } @@ -497,19 +651,21 @@ 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->visitAggregate(visitor); + thisObject->m_programCodeBlock->visitWeakly(visitor); } -void ProgramExecutable::clearCode() +void ModuleProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { - m_programCodeBlock.clear(); - m_unlinkedProgramCodeBlock.clear(); - Base::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); } FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) @@ -530,84 +686,124 @@ 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->visitAggregate(visitor); + thisObject->m_codeBlockForCall->visitWeakly(visitor); if (thisObject->m_codeBlockForConstruct) - thisObject->m_codeBlockForConstruct->visitAggregate(visitor); + thisObject->m_codeBlockForConstruct->visitWeakly(visitor); visitor.append(&thisObject->m_unlinkedExecutable); + visitor.append(&thisObject->m_singletonFunction); } -SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind) +FunctionExecutable* FunctionExecutable::fromGlobalCode( + const Identifier& name, ExecState& exec, const SourceCode& source, + JSObject*& exception, int overrideLineNumber) { - return codeBlockFor(kind)->symbolTable(); -} + UnlinkedFunctionExecutable* unlinkedExecutable = + UnlinkedFunctionExecutable::fromGlobalCode( + name, exec, source, exception, overrideLineNumber); + if (!unlinkedExecutable) + return nullptr; -void FunctionExecutable::clearCodeIfNotCompiling() -{ - if (isCompiling()) - return; - clearCode(); + return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber); } -void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling() +#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) { - if (isCompiling()) - return; - m_unlinkedExecutable->clearCodeForRecompilation(); } -void FunctionExecutable::clearCode() +void WebAssemblyExecutable::destroy(JSCell* cell) { - m_codeBlockForCall.clear(); - m_codeBlockForConstruct.clear(); - Base::clearCode(); + static_cast<WebAssemblyExecutable*>(cell)->WebAssemblyExecutable::~WebAssemblyExecutable(); } -void FunctionExecutable::unlinkCalls() +void WebAssemblyExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor) { -#if ENABLE(JIT) - if (!!m_jitCodeForCall) { - RELEASE_ASSERT(m_codeBlockForCall); - m_codeBlockForCall->unlinkCalls(); - } - if (!!m_jitCodeForConstruct) { - RELEASE_ASSERT(m_codeBlockForConstruct); - m_codeBlockForConstruct->unlinkCalls(); - } -#endif + 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); } -FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception) +void WebAssemblyExecutable::prepareForExecution(ExecState* exec) { - 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(); + 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); - // 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); + m_jitCodeForCall = codeBlock->jitCode(); + m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr(); + m_numParametersForCall = codeBlock->numParameters(); + + m_codeBlockForCall.set(vm, this, codeBlock); - return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false); + Heap::heap(this)->writeBarrier(this); } +#endif -String FunctionExecutable::paramString() const +void ExecutableBase::dump(PrintStream& out) const { - return m_unlinkedExecutable->paramString(); + 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()); + } } CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const |