/* * Copyright (C) 2012-2018 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "CodeSpecializationKind.h" #include "ConstructAbility.h" #include "ExecutableInfo.h" #include "ExpressionRangeInfo.h" #include "Identifier.h" #include "Intrinsic.h" #include "JSCast.h" #include "ParserModes.h" #include "RegExp.h" #include "SourceCode.h" #include "VariableEnvironment.h" #include namespace JSC { class Decoder; class FunctionMetadataNode; class FunctionExecutable; class ParserError; class SourceProvider; class UnlinkedFunctionCodeBlock; class CachedFunctionExecutable; enum UnlinkedFunctionKind { UnlinkedNormalFunction, UnlinkedBuiltinFunction, }; class UnlinkedFunctionExecutable final : public JSCell { public: friend class CodeCache; friend class VM; friend class CachedFunctionExecutable; typedef JSCell Base; static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; template static IsoSubspace* subspaceFor(VM& vm) { return &vm.unlinkedFunctionExecutableSpace.space; } static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor = false) { UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell(vm->heap)) UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, isBuiltinDefaultClassConstructor); instance->finishCreation(*vm); return instance; } ~UnlinkedFunctionExecutable(); const Identifier& name() const { return m_name; } const Identifier& ecmaName() const { return m_ecmaName; } void setEcmaName(const Identifier& name) { m_ecmaName = name; } unsigned parameterCount() const { return m_parameterCount; }; // Excluding 'this'! SourceParseMode parseMode() const { return static_cast(m_sourceParseMode); }; SourceCode classSource() const { if (m_rareData) return m_rareData->m_classSource; return SourceCode(); } void setClassSource(const SourceCode& source) { ensureRareData().m_classSource = source; } bool isInStrictContext() const { return m_isInStrictContext; } FunctionMode functionMode() const { return static_cast(m_functionMode); } ConstructorKind constructorKind() const { return static_cast(m_constructorKind); } SuperBinding superBinding() const { return static_cast(m_superBinding); } unsigned lineCount() const { return m_lineCount; } unsigned linkedStartColumn(unsigned parentStartColumn) const { return m_unlinkedBodyStartColumn + (!m_firstLineOffset ? parentStartColumn : 1); } unsigned linkedEndColumn(unsigned startColumn) const { return m_unlinkedBodyEndColumn + (!m_lineCount ? startColumn : 1); } unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; } unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; } unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; } unsigned startOffset() const { return m_startOffset; } unsigned sourceLength() { return m_sourceLength; } unsigned parametersStartOffset() const { return m_parametersStartOffset; } unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } void setInvalidTypeProfilingOffsets(); UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor( VM&, const SourceCode&, CodeSpecializationKind, OptionSet, ParserError&, SourceParseMode); static UnlinkedFunctionExecutable* fromGlobalCode( const Identifier&, ExecState&, const SourceCode&, JSObject*& exception, int overrideLineNumber, Optional functionConstructorParametersEndPosition); SourceCode linkedSourceCode(const SourceCode&) const; JS_EXPORT_PRIVATE FunctionExecutable* link(VM&, ScriptExecutable* topLevelExecutable, const SourceCode& parentSource, Optional overrideLineNumber = WTF::nullopt, Intrinsic = NoIntrinsic); void clearCode(VM& vm) { m_unlinkedCodeBlockForCall.clear(); m_unlinkedCodeBlockForConstruct.clear(); vm.unlinkedFunctionExecutableSpace.set.remove(this); } void recordParse(CodeFeatures features, bool hasCapturedVariables) { m_features = features; m_hasCapturedVariables = hasCapturedVariables; } CodeFeatures features() const { return m_features; } bool hasCapturedVariables() const { return m_hasCapturedVariables; } static const bool needsDestruction = true; static void destroy(JSCell*); bool isBuiltinFunction() const { return m_isBuiltinFunction; } bool isAnonymousBuiltinFunction() const { return isBuiltinFunction() && name().isPrivateName(); } ConstructAbility constructAbility() const { return static_cast(m_constructAbility); } JSParserScriptMode scriptMode() const { return static_cast(m_scriptMode); } bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; } bool isClass() const { if (!m_rareData) return false; return !m_rareData->m_classSource.isNull(); } VariableEnvironment parentScopeTDZVariables() const { if (!m_rareData || !m_rareData->m_parentScopeTDZVariables) return VariableEnvironment(); return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment(); } bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); } JSC::DerivedContextType derivedContextType() const {return static_cast(m_derivedContextType); } String sourceURLDirective() const { if (m_rareData) return m_rareData->m_sourceURLDirective; return String(); } String sourceMappingURLDirective() const { if (m_rareData) return m_rareData->m_sourceMappingURLDirective; return String(); } void setSourceURLDirective(const String& sourceURL) { ensureRareData().m_sourceURLDirective = sourceURL; } void setSourceMappingURLDirective(const String& sourceMappingURL) { ensureRareData().m_sourceMappingURLDirective = sourceMappingURL; } void finalizeUnconditionally(VM&); struct RareData { WTF_MAKE_STRUCT_FAST_ALLOCATED; SourceCode m_classSource; String m_sourceURLDirective; String m_sourceMappingURLDirective; CompactVariableMap::Handle m_parentScopeTDZVariables; }; private: UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional, JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor); UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&); void decodeCachedCodeBlocks(VM&); bool codeBlockEdgeMayBeWeak() const { // Currently, bytecode cache assumes that the tree of UnlinkedFunctionExecutable and UnlinkedCodeBlock will not be destroyed while the parent is live. // Bytecode cache uses this asumption to avoid duplicate materialization by bookkeeping the heap cells in the offste-to-pointer map. return VM::useUnlinkedCodeBlockJettisoning() && !m_isGeneratedFromCache; } unsigned m_firstLineOffset : 31; unsigned m_isInStrictContext : 1; unsigned m_lineCount : 31; unsigned m_hasCapturedVariables : 1; unsigned m_unlinkedFunctionNameStart : 31; unsigned m_isBuiltinFunction : 1; unsigned m_unlinkedBodyStartColumn : 31; unsigned m_isBuiltinDefaultClassConstructor : 1; unsigned m_unlinkedBodyEndColumn : 31; unsigned m_constructAbility: 1; unsigned m_startOffset : 31; unsigned m_scriptMode: 1; // JSParserScriptMode unsigned m_sourceLength : 31; unsigned m_superBinding : 1; unsigned m_parametersStartOffset : 31; unsigned m_isCached : 1; unsigned m_typeProfilingStartOffset; unsigned m_typeProfilingEndOffset; unsigned m_parameterCount; CodeFeatures m_features; SourceParseMode m_sourceParseMode; unsigned m_constructorKind : 2; unsigned m_functionMode : 2; // FunctionMode unsigned m_derivedContextType: 2; unsigned m_isGeneratedFromCache : 1; union { WriteBarrier m_unlinkedCodeBlockForCall; RefPtr m_decoder; }; union { WriteBarrier m_unlinkedCodeBlockForConstruct; struct { int32_t m_cachedCodeBlockForCallOffset; int32_t m_cachedCodeBlockForConstructOffset; }; }; Identifier m_name; Identifier m_ecmaName; RareData& ensureRareData() { if (LIKELY(m_rareData)) return *m_rareData; return ensureRareDataSlow(); } RareData& ensureRareDataSlow(); std::unique_ptr m_rareData; protected: static void visitChildren(JSCell*, SlotVisitor&); public: static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedFunctionExecutableType, StructureFlags), info()); } DECLARE_EXPORT_INFO; }; } // namespace JSC