blob: 19d07e66ad58e23e18ab46683958d1839a4c9881 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
namespace Js
{
class FunctionProxy;
class FunctionBody;
class ParseableFunctionInfo;
class DeferDeserializeFunctionInfo;
class FunctionInfo: public FinalizableObject
{
friend class RemoteFunctionBody;
protected:
DEFINE_VTABLE_CTOR_NOBASE(FunctionInfo);
public:
enum Attributes : uint32
{
None = 0x00000,
ErrorOnNew = 0x00001,
SkipDefaultNewObject = 0x00002,
DoNotProfile = 0x00004,
HasNoSideEffect = 0x00008, // calling function doesn't cause an implicit flags to be set,
// the callee will detect and set implicit flags on its individual operations
NeedCrossSiteSecurityCheck = 0x00010,
DeferredDeserialize = 0x00020, // The function represents something that needs to be deserialized on use
DeferredParse = 0x00040, // The function represents something that needs to be parsed on use
CanBeHoisted = 0x00080, // The function return value won't be changed in a loop so the evaluation can be hoisted.
SuperReference = 0x00100,
ClassMethod = 0x00200, // The function is a class method
ClassConstructor = 0x00400, // The function is a class constructor
Lambda = 0x01000,
CapturesThis = 0x02000, // Only lambdas will set this; denotes whether the lambda referred to this, used by debugger
Generator = 0x04000,
BuiltInInlinableAsLdFldInlinee = 0x08000,
Async = 0x10000,
Module = 0x20000, // The function is the function body wrapper for a module
EnclosedByGlobalFunc = 0x40000,
CanDefer = 0x80000,
AllowDirectSuper = 0x100000,
BaseConstructorKind = 0x200000
};
FunctionInfo(JavascriptMethod entryPoint, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = nullptr);
FunctionInfo(JavascriptMethod entryPoint, _no_write_barrier_tag, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = nullptr);
FunctionInfo(FunctionInfo& that); // Todo: (leish)(swb) find a way to prevent non-static initializer calling this ctor
static bool Is(void *ptr);
static DWORD GetFunctionBodyImplOffset() { return offsetof(FunctionInfo, functionBodyImpl); }
static BYTE GetOffsetOfFunctionProxy()
{
CompileAssert(offsetof(FunctionInfo, functionBodyImpl) <= UCHAR_MAX);
return offsetof(FunctionInfo, functionBodyImpl);
}
static DWORD GetAttributesOffset() { return offsetof(FunctionInfo, attributes); }
void VerifyOriginalEntryPoint() const;
JavascriptMethod GetOriginalEntryPoint() const;
JavascriptMethod GetOriginalEntryPoint_Unchecked() const;
void SetOriginalEntryPoint(const JavascriptMethod originalEntryPoint);
bool IsAsync() const { return ((this->attributes & Async) != 0); }
bool IsDeferred() const { return ((this->attributes & (DeferredDeserialize | DeferredParse)) != 0); }
static bool IsLambda(Attributes attributes) { return ((attributes & Lambda) != 0); }
bool IsLambda() const { return IsLambda(this->attributes); }
bool IsConstructor() const { return ((this->attributes & ErrorOnNew) == 0); }
static bool IsGenerator(Attributes attributes) { return ((attributes & Generator) != 0); }
bool IsGenerator() const { return IsGenerator(this->attributes); }
bool IsClassConstructor() const { return ((this->attributes & ClassConstructor) != 0); }
bool IsClassMethod() const { return ((this->attributes & ClassMethod) != 0); }
bool IsModule() const { return ((this->attributes & Module) != 0); }
bool HasSuperReference() const { return ((this->attributes & SuperReference) != 0); }
bool CanBeDeferred() const { return ((this->attributes & CanDefer) != 0); }
static bool IsCoroutine(Attributes attributes) { return ((attributes & (Async | Generator)) != 0); }
bool IsCoroutine() const { return IsCoroutine(this->attributes); }
BOOL HasBody() const { return functionBodyImpl != NULL; }
BOOL HasParseableInfo() const { return this->HasBody() && !this->IsDeferredDeserializeFunction(); }
FunctionProxy * GetFunctionProxy() const
{
return functionBodyImpl;
}
void SetFunctionProxy(FunctionProxy * proxy)
{
functionBodyImpl = proxy;
}
ParseableFunctionInfo* GetParseableFunctionInfo() const
{
Assert(functionBodyImpl == nullptr || !IsDeferredDeserializeFunction());
return (ParseableFunctionInfo*)GetFunctionProxy();
}
void SetParseableFunctionInfo(ParseableFunctionInfo* func)
{
Assert(functionBodyImpl == nullptr || !IsDeferredDeserializeFunction());
SetFunctionProxy((FunctionProxy*)func);
}
DeferDeserializeFunctionInfo* GetDeferDeserializeFunctionInfo() const
{
Assert(functionBodyImpl == nullptr || IsDeferredDeserializeFunction());
return (DeferDeserializeFunctionInfo*)PointerValue(functionBodyImpl);
}
FunctionBody * GetFunctionBody() const;
Attributes GetAttributes() const { return attributes; }
static Attributes GetAttributes(Js::RecyclableObject * function);
void SetAttributes(Attributes attr) { attributes = attr; }
LocalFunctionId GetLocalFunctionId() const { return functionId; }
void SetLocalFunctionId(LocalFunctionId functionId) { this->functionId = functionId; }
uint GetCompileCount() const { return compileCount; }
void SetCompileCount(uint count) { compileCount = count; }
virtual void Finalize(bool isShutdown) override
{
}
virtual void Dispose(bool isShutdown) override
{
}
virtual void Mark(Recycler *recycler) override { AssertMsg(false, "Mark called on object that isn't TrackableObject"); }
BOOL IsDeferredDeserializeFunction() const { return ((this->attributes & DeferredDeserialize) == DeferredDeserialize); }
BOOL IsDeferredParseFunction() const { return ((this->attributes & DeferredParse) == DeferredParse); }
void SetCapturesThis() { attributes = (Attributes)(attributes | Attributes::CapturesThis); }
bool GetCapturesThis() const { return (attributes & Attributes::CapturesThis) != 0; }
void SetEnclosedByGlobalFunc() { attributes = (Attributes)(attributes | Attributes::EnclosedByGlobalFunc ); }
bool GetEnclosedByGlobalFunc() const { return (attributes & Attributes::EnclosedByGlobalFunc) != 0; }
void SetAllowDirectSuper() { attributes = (Attributes)(attributes | Attributes::AllowDirectSuper); }
bool GetAllowDirectSuper() const { return (attributes & Attributes::AllowDirectSuper) != 0; }
void SetBaseConstructorKind() { attributes = (Attributes)(attributes | Attributes::BaseConstructorKind); }
bool GetBaseConstructorKind() const { return (attributes & Attributes::BaseConstructorKind) != 0; }
protected:
FieldNoBarrier(JavascriptMethod) originalEntryPoint;
FieldWithBarrier(FunctionProxy *) functionBodyImpl; // Implementation of the function- null if the function doesn't have a body
Field(LocalFunctionId) functionId; // Per host source context (source file) function Id
Field(uint) compileCount;
Field(Attributes) attributes;
};
// Helper FunctionInfo for builtins that we don't want to profile (script profiler).
class NoProfileFunctionInfo : public FunctionInfo
{
public:
NoProfileFunctionInfo(JavascriptMethod entryPoint)
: FunctionInfo(entryPoint, Attributes::DoNotProfile)
{}
NoProfileFunctionInfo(JavascriptMethod entryPoint, _no_write_barrier_tag)
: FunctionInfo(FORCE_NO_WRITE_BARRIER_TAG(entryPoint), Attributes::DoNotProfile)
{}
};
};