forked from chakra-core/ChakraCore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDynamicObject.h
More file actions
358 lines (299 loc) · 18.1 KB
/
DynamicObject.h
File metadata and controls
358 lines (299 loc) · 18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//-------------------------------------------------------------------------------------------------------
// 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
class ScriptSite;
namespace Js
{
#if ENABLE_TTD
#define DEFINE_TTD_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(T) \
virtual void MarshalCrossSite_TTDInflate() \
{ \
AssertMsg(VirtualTableInfo<T>::HasVirtualTable(this), "Derived class need to define marshal"); \
VirtualTableInfo<Js::CrossSiteObject<T>>::SetVirtualTable(this); \
}
#else
#define DEFINE_TTD_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(T)
#endif
#if !defined(USED_IN_STATIC_LIB)
#define DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(T) \
friend class Js::CrossSiteObject<T>; \
virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) \
{ \
Assert(this->GetScriptContext() != scriptContext); \
AssertMsg(VirtualTableInfo<T>::HasVirtualTable(this), "Derived class need to define marshal to script context"); \
VirtualTableInfo<Js::CrossSiteObject<T>>::SetVirtualTable(this); \
}\
DEFINE_TTD_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(T)
#else
#define DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(T) \
virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) {Assert(FALSE);}
#endif
#if DBG
#define SetSlotArguments(propertyId, slotIndex, value) propertyId, false, slotIndex, value
#define SetSlotArgumentsRoot(propertyId, allowLetConst, slotIndex, value) propertyId, allowLetConst, slotIndex, value
#else
#define SetSlotArguments(propertyId, slotIndex, value) slotIndex, value
#define SetSlotArgumentsRoot(propertyId, allowLetConst, slotIndex, value) slotIndex, value
#endif
enum class DynamicObjectFlags : uint16
{
None = 0u,
ObjectArrayFlagsTag = 1u << 0, // Tag bit used to indicate the objectArrayOrFlags field is used as flags as opposed to object array pointer.
HasSegmentMap = 1u << 1,
HasNoMissingValues = 1u << 2, // The head segment of a JavascriptArray has no missing values.
InitialArrayValue = ObjectArrayFlagsTag | HasNoMissingValues,
AllArrayFlags = HasNoMissingValues | HasSegmentMap,
AllFlags = ObjectArrayFlagsTag | HasNoMissingValues | HasSegmentMap
};
ENUM_CLASS_HELPERS(DynamicObjectFlags, uint16);
class DynamicObject : public RecyclableObject
{
friend class CrossSite;
friend class DynamicTypeHandler;
friend class ModuleNamespace;
friend class DynamicObjectEnumerator;
friend class RecyclableObject;
friend struct InlineCache;
friend class ForInObjectEnumerator; // for cache enumerator
friend class JavascriptArray; // for xplat offsetof field access
friend class JavascriptNativeArray; // for xplat offsetof field access
friend class JavascriptOperators; // for ReplaceType
friend class PathTypeHandlerBase; // for ReplaceType
friend class JavascriptLibrary; // for ReplaceType
friend class ScriptFunction; // for ReplaceType;
friend class JSON::JSONParser; //for ReplaceType
friend class ModuleNamespace; // for slot setting.
#if ENABLE_OBJECT_SOURCE_TRACKING
public:
//Field for tracking object allocation
TTD::DiagnosticOrigin TTDDiagOriginInfo;
#endif
private:
Var* auxSlots;
// The objectArrayOrFlags field can store one of two things:
// a) a pointer to the object array holding numeric properties of this object, or
// b) a bitfield of flags.
// Because object arrays are not commonly used, the storage space can be reused to carry information that
// can improve performance for typical objects. To indicate the bitfield usage we set the least significant bit to 1.
// Object array pointer always trumps the flags, such that when the first numeric property is added to an
// object, its flags will be wiped out. Hence flags can only be used as a form of cache to improve performance.
// For functional correctness, some other fallback mechanism must exist to convey the information contained in flags.
// This fields always starts off initialized to null. Currently, only JavascriptArray overrides it to store flags, the
// bits it uses are DynamicObjectFlags::AllArrayFlags.
union
{
ArrayObject * objectArray; // Only if !IsAnyArray
struct // Only if IsAnyArray
{
DynamicObjectFlags arrayFlags;
ProfileId arrayCallSiteIndex;
};
};
CompileAssert(sizeof(ProfileId) == 2);
CompileAssert(static_cast<intptr_t>(DynamicObjectFlags::ObjectArrayFlagsTag) != 0);
void InitSlots(DynamicObject * instance, ScriptContext * scriptContext);
void SetTypeHandler(DynamicTypeHandler * typeHandler, bool hasChanged);
void ReplaceType(DynamicType * type);
void ReplaceTypeWithPredecessorType(DynamicType * previousType);
protected:
DEFINE_VTABLE_CTOR(DynamicObject, RecyclableObject);
DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(DynamicObject);
DynamicObject(DynamicType * type, const bool initSlots = true);
DynamicObject(DynamicType * type, ScriptContext * scriptContext);
// For boxing stack instance
DynamicObject(DynamicObject * instance);
DynamicTypeHandler * GetTypeHandler() const;
uint16 GetOffsetOfInlineSlots() const;
template <class T>
static T* NewObject(Recycler * recycler, DynamicType * type);
public:
static DynamicObject * New(Recycler * recycler, DynamicType * type);
static bool Is(Var aValue);
static DynamicObject* FromVar(Var value);
void EnsureSlots(int oldCount, int newCount, ScriptContext * scriptContext, DynamicTypeHandler * newTypeHandler = nullptr);
void EnsureSlots(int newCount, ScriptContext *scriptContext);
Var GetSlot(int index);
Var GetInlineSlot(int index);
Var GetAuxSlot(int index);
#if DBG
void SetSlot(PropertyId propertyId, bool allowLetConst, int index, Var value);
void SetInlineSlot(PropertyId propertyId, bool allowLetConst, int index, Var value);
void SetAuxSlot(PropertyId propertyId, bool allowLetConst, int index, Var value);
#else
void SetSlot(int index, Var value);
void SetInlineSlot(int index, Var value);
void SetAuxSlot(int index, Var value);
#endif
private:
bool IsObjectHeaderInlinedTypeHandlerUnchecked() const;
public:
bool IsObjectHeaderInlinedTypeHandler() const;
bool DeoptimizeObjectHeaderInlining();
public:
bool HasNonEmptyObjectArray() const;
DynamicType * GetDynamicType() const { return (DynamicType *)this->GetType(); }
// Check if a typeId is of any array type (JavascriptArray or ES5Array).
static bool IsAnyArrayTypeId(TypeId typeId);
// Check if a Var is either a JavascriptArray* or ES5Array*.
static bool IsAnyArray(const Var aValue);
bool UsesObjectArrayOrFlagsAsFlags() const
{
return !!(arrayFlags & DynamicObjectFlags::ObjectArrayFlagsTag);
}
ArrayObject* GetObjectArray() const
{
return HasObjectArray() ? GetObjectArrayOrFlagsAsArray() : nullptr;
}
bool HasObjectArray() const
{
// Only JavascriptArray uses the objectArrayOrFlags as flags.
Assert(DynamicObject::IsAnyArray((Var)this) || !UsesObjectArrayOrFlagsAsFlags() || IsObjectHeaderInlinedTypeHandler());
return ((objectArray != nullptr) && !UsesObjectArrayOrFlagsAsFlags() && !IsObjectHeaderInlinedTypeHandler());
}
ArrayObject* GetObjectArrayUnchecked() const
{
return HasObjectArrayUnchecked() ? GetObjectArrayOrFlagsAsArray() : nullptr;
}
bool HasObjectArrayUnchecked() const
{
return ((objectArray != nullptr) && !UsesObjectArrayOrFlagsAsFlags() && !IsObjectHeaderInlinedTypeHandlerUnchecked());
}
BOOL HasObjectArrayItem(uint32 index);
BOOL DeleteObjectArrayItem(uint32 index, PropertyOperationFlags flags);
BOOL GetObjectArrayItem(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext);
DescriptorFlags GetObjectArrayItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext);
BOOL SetObjectArrayItem(uint32 index, Var value, PropertyOperationFlags flags);
BOOL SetObjectArrayItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes);
BOOL SetObjectArrayItemAttributes(uint32 index, PropertyAttributes attributes);
BOOL SetObjectArrayItemWritable(PropertyId propertyId, BOOL writable);
BOOL SetObjectArrayItemAccessors(uint32 index, Var getter, Var setter);
void InvalidateHasOnlyWritableDataPropertiesInPrototypeChainCacheIfPrototype();
void ResetObject(DynamicType* type, BOOL keepProperties);
virtual void SetIsPrototype();
bool HasLockedType() const;
bool HasSharedType() const;
bool HasSharedTypeHandler() const;
bool LockType();
bool ShareType();
bool GetIsExtensible() const;
bool GetHasNoEnumerableProperties();
bool SetHasNoEnumerableProperties(bool value);
virtual bool HasReadOnlyPropertiesInvisibleToTypeHandler() { return false; }
void InitSlots(DynamicObject* instance);
virtual int GetPropertyCount() override;
virtual PropertyId GetPropertyId(PropertyIndex index) override;
virtual PropertyId GetPropertyId(BigPropertyIndex index) override;
PropertyIndex GetPropertyIndex(PropertyId propertyId) sealed;
virtual BOOL HasProperty(PropertyId propertyId) override;
virtual BOOL HasOwnProperty(PropertyId propertyId) override;
virtual BOOL GetProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual BOOL GetProperty(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual BOOL GetInternalProperty(Var instance, PropertyId internalPropertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual BOOL GetPropertyReference(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 BOOL SetInternalProperty(PropertyId internalPropertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
virtual BOOL InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags = PropertyOperation_None, PropertyValueInfo* info = nullptr) override;
virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags) override;
virtual BOOL IsFixedProperty(PropertyId propertyId) override;
virtual BOOL HasItem(uint32 index) override;
virtual BOOL HasOwnItem(uint32 index) override;
virtual BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
virtual BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext) override;
virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override;
virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags) override;
virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags) override;
virtual BOOL ToPrimitive(JavascriptHint hint, Var* result, ScriptContext * requestContext) override;
virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext * scriptContext, ForInCache * forInCache = nullptr) override;
virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags = PropertyOperation_None) override;
virtual BOOL GetAccessors(PropertyId propertyId, Var *getter, Var *setter, ScriptContext * requestContext) override;
virtual BOOL IsWritable(PropertyId propertyId) override;
virtual BOOL IsConfigurable(PropertyId propertyId) override;
virtual BOOL IsEnumerable(PropertyId propertyId) override;
virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetWritable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) override;
virtual BOOL SetAttributes(PropertyId propertyId, PropertyAttributes attributes) override;
virtual BOOL IsExtensible() override { return GetIsExtensible(); };
virtual BOOL PreventExtensions() override;
virtual BOOL Seal() override;
virtual BOOL Freeze() override;
virtual BOOL IsSealed() override;
virtual BOOL IsFrozen() override;
virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
virtual Var GetTypeOfString(ScriptContext * requestContext) override;
#if DBG
virtual bool CanStorePropertyValueDirectly(PropertyId propertyId, bool allowLetConst) override;
#endif
virtual void RemoveFromPrototype(ScriptContext * requestContext) override;
virtual void AddToPrototype(ScriptContext * requestContext) override;
virtual void SetPrototype(RecyclableObject* newPrototype) override;
virtual BOOL IsCrossSiteObject() const { return FALSE; }
virtual DynamicType* DuplicateType();
static bool IsTypeHandlerCompatibleForObjectHeaderInlining(DynamicTypeHandler * oldTypeHandler, DynamicTypeHandler * newTypeHandler);
void ChangeType();
void ChangeTypeIf(const Type* oldType);
BOOL FindNextProperty(BigPropertyIndex& index, JavascriptString** propertyString, PropertyId* propertyId, PropertyAttributes* attributes,
DynamicType *typeToEnumerate, EnumeratorFlags flags, ScriptContext * requestContext) const;
virtual BOOL HasDeferredTypeHandler() const sealed;
static DWORD GetOffsetOfAuxSlots();
static DWORD GetOffsetOfObjectArray();
static DWORD GetOffsetOfType();
Js::BigPropertyIndex GetPropertyIndexFromInlineSlotIndex(uint inlineSlotIndex);
Js::BigPropertyIndex GetPropertyIndexFromAuxSlotIndex(uint auxIndex);
BOOL GetAttributesWithPropertyIndex(PropertyId propertyId, BigPropertyIndex index, PropertyAttributes * attributes);
RecyclerWeakReference<DynamicObject>* CreateWeakReferenceToSelf();
void SetObjectArray(ArrayObject* objectArray);
protected:
BOOL GetEnumeratorWithPrefix(JavascriptEnumerator * prefixEnumerator, JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext * scriptContext, ForInCache * forInCache);
// These are only call for arrays
void InitArrayFlags(DynamicObjectFlags flags);
DynamicObjectFlags GetArrayFlags() const;
DynamicObjectFlags GetArrayFlags_Unchecked() const; // do not use except in extreme circumstances
void SetArrayFlags(const DynamicObjectFlags flags);
ProfileId GetArrayCallSiteIndex() const;
void SetArrayCallSiteIndex(ProfileId profileId);
static DynamicObject * BoxStackInstance(DynamicObject * instance);
private:
ArrayObject* EnsureObjectArray();
ArrayObject* GetObjectArrayOrFlagsAsArray() const { return objectArray; }
template <PropertyId propertyId>
BOOL ToPrimitiveImpl(Var* result, ScriptContext * requestContext);
BOOL CallToPrimitiveFunction(Var toPrimitiveFunction, PropertyId propertyId, Var* result, ScriptContext * requestContext);
#if DBG
public:
virtual bool DbgIsDynamicObject() const override { return true; }
#endif
#ifdef RECYCLER_STRESS
public:
virtual void Finalize(bool isShutdown) override;
virtual void Dispose(bool isShutdown) override;
virtual void Mark(Recycler *recycler) override;
#endif
#if ENABLE_TTD
public:
virtual TTD::NSSnapObjects::SnapObjectType GetSnapTag_TTD() const override;
virtual void ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc) override;
Js::Var* GetInlineSlots_TTD() const;
Js::Var* GetAuxSlots_TTD() const;
#if ENABLE_OBJECT_SOURCE_TRACKING
void SetDiagOriginInfoAsNeeded();
#endif
#endif
public:
virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
{
// This virtual function hinders linker to do ICF vtable of this class with other classes.
// ICF vtable causes unexpected behavior in type check code. Objects uses vtable as identify should
// override this function and return a unique value.
return VTableValue::VtableDynamicObject;
}
};
} // namespace Js