summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/Executable.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
commita4e969f4965059196ca948db781e52f7cfebf19e (patch)
tree6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/runtime/Executable.cpp
parent41386e9cb918eed93b3f13648cbef387e371e451 (diff)
downloadWebKitGtk-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.cpp638
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