]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Executable.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / Executable.cpp
index ff9f614a0f9ca4c8188d5b7536e97b8548371a7c..55240fd91f7bc7842f13e59281d10d21d86c4f50 100644 (file)
@@ -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
 #include "Executable.h"
 
 #include "BatchedTransitionOptimizer.h"
-#include "BytecodeGenerator.h"
 #include "CodeBlock.h"
 #include "DFGDriver.h"
 #include "JIT.h"
-#include "LLIntEntrypoint.h"
 #include "JSCInlines.h"
+#include "JSFunctionNameScope.h"
+#include "LLIntEntrypoint.h"
 #include "Parser.h"
 #include "ProfilerDatabase.h"
+#include "TypeProfiler.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();
     m_jitCodeForCallWithArityCheckAndPreserveRegs = MacroAssemblerCodePtr();
@@ -78,14 +77,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
@@ -94,20 +91,38 @@ 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)
+    : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
+    , m_source(source)
+    , m_features(isInStrictContext ? StrictModeFeature : 0)
+    , m_hasCapturedVariables(false)
+    , m_neverInline(false)
+    , m_didTryToEnterInLoop(false)
+    , 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)
+{
+}
 
-#if ENABLE(JIT)
 void ScriptExecutable::destroy(JSCell* cell)
 {
     static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
 }
-#endif
 
 void ScriptExecutable::installCode(CodeBlock* genericCodeBlock)
 {
     RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
     RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
     
+    if (Options::verboseOSR())
+        dataLog("Installing ", *genericCodeBlock, "\n");
+    
     VM& vm = *genericCodeBlock->vm();
     
     if (vm.m_perBytecodeProfiler)
@@ -184,10 +199,10 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock)
     Heap::heap(this)->writeBarrier(this);
 }
 
-PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
-    CodeSpecializationKind kind, JSFunction* function, JSScope** scope, JSObject*& exception)
+RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
+    CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception)
 {
-    VM* vm = (*scope)->vm();
+    VM* vm = scope->vm();
 
     ASSERT(vm->heap.isDeferred());
     ASSERT(startColumn() != UINT_MAX);
@@ -199,7 +214,7 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
         RELEASE_ASSERT(!executable->m_evalCodeBlock);
         RELEASE_ASSERT(!function);
         return adoptRef(new EvalCodeBlock(
-            executable, executable->m_unlinkedEvalCodeBlock.get(), *scope,
+            executable, executable->m_unlinkedEvalCodeBlock.get(), scope,
             executable->source().provider()));
     }
     
@@ -209,7 +224,7 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
         RELEASE_ASSERT(!executable->m_programCodeBlock);
         RELEASE_ASSERT(!function);
         return adoptRef(new ProgramCodeBlock(
-            executable, executable->m_unlinkedProgramCodeBlock.get(), *scope,
+            executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
             executable->source().provider(), executable->source().startColumn()));
     }
     
@@ -217,27 +232,32 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
     RELEASE_ASSERT(function);
     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
     RELEASE_ASSERT(!executable->codeBlockFor(kind));
-    JSGlobalObject* globalObject = (*scope)->globalObject();
+    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, executable->bodyIncludesBraces(), error);
-    recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn()); 
+            *vm, executable->m_source, kind, debuggerMode, profilerMode, error);
+    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;
     }
 
     // Parsing reveals whether our function uses features that require a separate function name object in the scope chain.
     // Be sure to add this scope before linking the bytecode because this scope will change the resolution depth of non-local variables.
-    if (!executable->m_didParseForTheFirstTime) {
-        executable->m_didParseForTheFirstTime = true;
-        function->addNameScopeIfNeeded(*vm);
-        *scope = function->scope();
+    if (functionNameIsInScope(executable->name(), executable->functionMode())
+        && functionNameScopeIsDynamic(executable->usesEval(), executable->isStrictMode())) {
+        // We shouldn't have to do this. But we do, because bytecode linking requires a real scope
+        // chain.
+        // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141885
+        SymbolTable* symbolTable =
+            SymbolTable::createNameScopeTable(*vm, executable->name(), ReadOnly | DontDelete);
+        scope = JSFunctionNameScope::create(
+            *vm, scope->globalObject(), scope, symbolTable, function);
     }
     
     SourceProvider* provider = executable->source().provider();
@@ -245,7 +265,7 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
     unsigned startColumn = executable->source().startColumn();
 
     return adoptRef(new FunctionCodeBlock(
-        executable, unlinkedCodeBlock, *scope, provider, sourceOffset, startColumn));
+        executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn));
 }
 
 PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
@@ -301,7 +321,7 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock)
 }
 
 JSObject* ScriptExecutable::prepareForExecutionImpl(
-    ExecState* exec, JSFunction* function, JSScope** scope, CodeSpecializationKind kind)
+    ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
 {
     VM& vm = exec->vm();
     DeferGC deferGC(vm.heap);
@@ -325,9 +345,9 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
     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)
 {
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     if (!globalObject->evalEnabled()) {
@@ -338,7 +358,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
     EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
     executable->finishCreation(exec->vm());
 
-    UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable);
+    UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode);
     if (!unlinkedEvalCode)
         return 0;
 
@@ -348,7 +368,7 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
 }
 
 EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
-    : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext)
+    : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext)
 {
 }
 
@@ -357,11 +377,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)
 {
+    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,13 +393,13 @@ 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 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, bool bodyIncludesBraces)
+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())
     , m_unlinkedExecutable(vm, this, unlinkedExecutable)
-    , m_bodyIncludesBraces(bodyIncludesBraces)
-    , m_didParseForTheFirstTime(false)
 {
     RELEASE_ASSERT(!source.isNull());
     ASSERT(source.length());
@@ -385,6 +409,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)
@@ -413,8 +446,6 @@ 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);
@@ -433,7 +464,7 @@ void EvalExecutable::unlinkCalls()
 
 void EvalExecutable::clearCode()
 {
-    m_evalCodeBlock.clear();
+    m_evalCodeBlock = nullptr;
     m_unlinkedEvalCodeBlock.clear();
     Base::clearCode();
 }
@@ -443,10 +474,12 @@ 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, 0, Identifier(), JSParserBuiltinMode::NotBuiltin, 
+        JSParserStrictMode::NotStrict, JSParserCodeType::Program, error);
     if (programNode)
         return 0;
-    ASSERT(error.m_type != ParserError::ErrorNone);
+    ASSERT(error.isValid());
     return error.toErrorObject(lexicalGlobalObject, m_source);
 }
 
@@ -477,12 +510,16 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF
     BatchedTransitionOptimizer optimizer(vm, globalObject);
 
     const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
-    const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations();
 
-    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()), scope);
-        globalObject->addFunction(callFrame, functionDeclarations[i].first, value);
+    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 < variableDeclarations.size(); ++i) {
@@ -498,8 +535,6 @@ 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)
@@ -508,7 +543,7 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
 
 void ProgramExecutable::clearCode()
 {
-    m_programCodeBlock.clear();
+    m_programCodeBlock = nullptr;
     m_unlinkedProgramCodeBlock.clear();
     Base::clearCode();
 }
@@ -531,14 +566,13 @@ 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);
     if (thisObject->m_codeBlockForConstruct)
         thisObject->m_codeBlockForConstruct->visitAggregate(visitor);
     visitor.append(&thisObject->m_unlinkedExecutable);
+    visitor.append(&thisObject->m_singletonFunction);
 }
 
 SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind)
@@ -546,24 +580,15 @@ SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind)
     return codeBlockFor(kind)->symbolTable();
 }
 
-void FunctionExecutable::clearCodeIfNotCompiling()
-{
-    if (isCompiling())
-        return;
-    clearCode();
-}
-
-void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling()
+void FunctionExecutable::clearUnlinkedCodeForRecompilation()
 {
-    if (isCompiling())
-        return;
     m_unlinkedExecutable->clearCodeForRecompilation();
 }
 
 void FunctionExecutable::clearCode()
 {
-    m_codeBlockForCall.clear();
-    m_codeBlockForConstruct.clear();
+    m_codeBlockForCall = nullptr;
+    m_codeBlockForConstruct = nullptr;
     Base::clearCode();
 }
 
@@ -581,34 +606,17 @@ void FunctionExecutable::unlinkCalls()
 #endif
 }
 
-FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
+FunctionExecutable* FunctionExecutable::fromGlobalCode(
+    const Identifier& name, ExecState& exec, const SourceCode& source, 
+    JSObject*& exception, int overrideLineNumber)
 {
-    UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception);
+    UnlinkedFunctionExecutable* unlinkedExecutable = 
+        UnlinkedFunctionExecutable::fromGlobalCode(
+            name, exec, source, exception, overrideLineNumber);
     if (!unlinkedExecutable)
-        return 0;
-    unsigned lineCount = unlinkedExecutable->lineCount();
-    unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset();
-    unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset();
-
-    // 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);
+        return nullptr;
 
-    return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false);
-}
-
-String FunctionExecutable::paramString() const
-{
-    return m_unlinkedExecutable->paramString();
+    return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber);
 }
 
 void ExecutableBase::dump(PrintStream& out) const