blob: 8a2637c223c666594116fac162a5d3601118a370 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
namespace Js
{
class ArgumentsObject _ABSTRACT : public DynamicObject
{
private:
static PropertyId specialPropertyIds[];
protected:
DEFINE_VTABLE_CTOR_ABSTRACT(ArgumentsObject, DynamicObject);
public:
ArgumentsObject(DynamicType * type) : DynamicObject(type)
{
Assert(type->GetTypeId() == TypeIds_Arguments);
}
Var GetCaller(ScriptContext * scriptContext);
static Var GetCaller(ScriptContext * scriptContext, JavascriptStackWalker *walker, bool skipGlobal);
static bool Is(Var aValue);
virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, ForInCache * forInCache = nullptr) override;
virtual uint32 GetNumberOfArguments() const = 0;
virtual uint32 GetNextFormalArgIndex(uint32 index, BOOL enumNonEnumerable = FALSE, PropertyAttributes* attributes = nullptr) const = 0;
virtual Var GetHeapArguments() = 0;
virtual void SetHeapArguments(HeapArgumentsObject *args) = 0;
virtual BOOL AdvanceWalkerToArgsFrame(JavascriptStackWalker *walker) = 0;
};
class ES5HeapArgumentsObject;
// The arguments passed to a function are cached as follows:
// 1) any formal (i.e. named) arguments are copied to the ActivationObject hung off
// a HeapArgumentObject where they can be referenced by name
// 2) any additional actual arguments are stored as an index property on that HeapArgumentObject
//
// See JavascriptOperators::LoadHeapArguments for details of HeapArgumentObject creation.
//
// If a function has named arguments, the array elements of the Arguments object are synonymous for
// the local variables that hold the function arguments. This no longer holds true, however, if an
// array element of the Argument object is deleted.
class HeapArgumentsObject : public ArgumentsObject
{
friend class ::ActiveScriptProfilerHeapEnum;
protected:
DEFINE_VTABLE_CTOR(HeapArgumentsObject, ArgumentsObject);
private:
// We currently support only 2^24 arguments
Field(uint32) numOfArguments:31;
Field(uint32) callerDeleted:1;
DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(HeapArgumentsObject);
protected:
Field(uint32) formalCount;
Field(ActivationObject*) frameObject;
Field(BVSparse<Recycler>*) deletedArgs;
public:
HeapArgumentsObject(DynamicType * type);
HeapArgumentsObject(Recycler *recycler, ActivationObject* obj, uint32 formalCount, DynamicType * type);
void SetNumberOfArguments(uint32 len);
static HeapArgumentsObject* As(Var aValue);
BOOL HasItemAt(uint32 index);
virtual BOOL GetItemAt(uint32 index, Var *value, ScriptContext * scriptContext);
virtual BOOL SetItemAt(uint32 index, Var value);
virtual BOOL DeleteItemAt(uint32 index);
virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId) override;
virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
virtual PropertyQueryFlags HasItemQuery(uint32 index) override;
virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
virtual uint32 GetNumberOfArguments() const override;
virtual uint32 GetNextFormalArgIndex(uint32 index, BOOL enumNonEnumerable = FALSE, PropertyAttributes* attributes = nullptr) const override;
virtual Var GetHeapArguments() { return this; }
virtual void SetHeapArguments(HeapArgumentsObject *args)
{
AssertMsg(false, "Should never get here");
}
virtual BOOL AdvanceWalkerToArgsFrame(JavascriptStackWalker *walker) override;
virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags = PropertyOperation_None) override;
virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
virtual BOOL PreventExtensions() override;
virtual BOOL Seal() override;
virtual BOOL Freeze() override;
uint32 GetFormalCount() const
{
return this->formalCount;
}
void SetFormalCount(uint32 value)
{
this->formalCount = value;
}
ES5HeapArgumentsObject* ConvertToUnmappedArgumentsObject(bool overwriteArgsUsingFrameObject = true);
const ActivationObject* const GetFrameObject() { return frameObject; }
void SetFrameObject(ActivationObject * value)
{
AssertMsg(frameObject == nullptr, "Setting the frame object again?");
frameObject = value;
}
private:
ES5HeapArgumentsObject* ConvertToES5HeapArgumentsObject(bool overwriteArgsUsingFrameObject = true);
protected:
BOOL IsFormalArgument(uint32 index);
BOOL IsFormalArgument(PropertyId propertyId);
BOOL IsFormalArgument(PropertyId propertyId, uint32* pIndex); // Checks whether property is numeric, and on success sets that index.
BOOL IsArgumentDeleted(uint32 index) const;
#if ENABLE_TTD
public:
virtual void MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor) override;
virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
template <TTD::NSSnapObjects::SnapObjectType argsKind>
void ExtractSnapObjectDataInto_Helper(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc);
ES5HeapArgumentsObject* ConvertToES5HeapArgumentsObject_TTD();
#endif
};
// ES5 version of the HeapArgumentsObject: support for attributes on formal arguments.
// - Unless the user deals with SetWritable/Enumerable/Configurable/Accessors, regular HeapArgumentsObject is used.
// - When SetWritable/Enumerable/Configurable/Accessors is called, convert HeapArgumentsObject to ES5HeapArgumentsObject by swapping vtable.
// - Override GetItemAt/SetItemAt -- for disconnected items force GetItem/SetItem to use "this" rather than from frameObject.
// - Override GetEnumerator -- take care of enumerable = false arguments.
// - The "disconnect" happens when (as ES5 spec says) setting writable to false and setting accessors.
// Note: This implementation depends on v-table swapping so that HeapArgumentsObject instance can be
// converted to ES5HeapArgumentsObject at runtime when ES5 attribute/getter/setter support is needed.
// Thus, CAUTION: as a result, this class can't add any new instance fields,
// as the size of the instance must be same.
class ES5HeapArgumentsObject : public HeapArgumentsObject
{
friend struct AutoObjectArrayItemExistsValidator;
friend class ES5ArgumentsObjectEnumerator;
// Helper class to make sure that object array item exists for ES5HeapArgumentsObject
// and remove the item to roll back to original state if something fails/throws.
struct AutoObjectArrayItemExistsValidator
{
ES5HeapArgumentsObject* m_args;
bool m_isReleaseItemNeeded;
uint32 m_index;
AutoObjectArrayItemExistsValidator(ES5HeapArgumentsObject* args, uint32 index);
~AutoObjectArrayItemExistsValidator();
};
private:
DEFINE_VTABLE_CTOR(ES5HeapArgumentsObject, HeapArgumentsObject);
DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(ES5HeapArgumentsObject);
uint32 GetNextFormalArgIndexHelper(uint32 index, BOOL enumNonEnumerable, PropertyAttributes* attributes = nullptr) const;
public:
ES5HeapArgumentsObject(Recycler *recycler, ActivationObject* obj, uint32 formalCount, DynamicType * type)
: HeapArgumentsObject(recycler, obj, formalCount, type)
{
}
virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags) override;
virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, ForInCache * forInCache = nullptr) override;
virtual BOOL PreventExtensions() override;
virtual BOOL Seal() override;
virtual BOOL Freeze() override;
virtual uint32 GetNextFormalArgIndex(uint32 index, BOOL enumNonEnumerable = FALSE, PropertyAttributes* attributes = nullptr) const override;
virtual BOOL GetItemAt(uint32 index, Var *value, ScriptContext * scriptContext) override;
virtual BOOL SetItemAt(uint32 index, Var value) override;
virtual BOOL DeleteItemAt(uint32 index) override;
void DisconnectFormalFromNamedArgument(uint32 index);
BOOL IsFormalDisconnectedFromNamedArgument(uint32 index);
BOOL IsEnumerableByIndex(uint32 index);
BOOL SetConfigurableForFormal(uint32 index, PropertyId propertyId, BOOL value);
BOOL SetEnumerableForFormal(uint32 index, PropertyId propertyId, BOOL value);
BOOL SetWritableForFormal(uint32 index, PropertyId propertyId, BOOL value);
BOOL SetAccessorsForFormal(uint32 index, PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags = PropertyOperation_None);
BOOL SetPropertyWithAttributesForFormal(uint32 index, PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any);
#if ENABLE_TTD
public:
virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
#endif
};
}