zoukankan      html  css  js  c++  java
  • Chakra TypedArray代码实现笔记

    ArrayBuffer.cpp阅读

    对象继承关系

    JavascriptArrayBuffer:
    ArrayBuffer:
    ArrayBufferBase:
    DynamicObject:
    RecyclableObject:
    FinalizableObject
    
    template<> TypedArray<Typed>
    TypedArray
    TypedArrayBase
    ArrayBufferParent
    ArrayObject
    DynamicObject
    RecyclableObject
    FinalizableObject
    

    FinalizableObject类

    抽象类FinalizableObject,所有Object类的基类

    class FinalizableObject
    {
    public:
        virtual void Finalize(bool isShutdown) = 0;
        virtual void Dispose(bool isShutdown) = 0;
        virtual void Mark(Recycler * recycler) = 0;
        virtual void OnMark() {}
    };
    

    RecyclableObject类

    //TO DO
    RecyclableObject类涉及到内存管理相关的操作

       class RecyclableObject : public FinalizableObject
        {
            
    		friend class JavascriptOperators;
    
        protected:
            Field(Type *) type;
            DEFINE_VTABLE_CTOR_NOBASE(RecyclableObject);
    
            virtual RecyclableObject* GetPrototypeSpecial();
    
        public:
            static bool Is(Var aValue);//static方法,传入地址判断是否为RecyclableObject对象
            static RecyclableObject* FromVar(Var varValue);//static方法,传入地址返回对象
            RecyclableObject(Type * type);//构造函数
    
            ScriptContext* GetScriptContext() const;//返回ScriptContext
            TypeId GetTypeId() const;//返回TypeId
            RecyclableObject* GetPrototype() const;//return prototype;
            JavascriptMethod GetEntryPoint() const;//return entryPoint;
            JavascriptLibrary* GetLibrary() const;// return javascriptLibrary;
            Recycler* GetRecycler() const;// return recycler;
            void SetIsPrototype();
    
            // Is this object known to have only writable data properties
            // (i.e. no accessors or non-writable properties)?
            bool HasOnlyWritableDataProperties();//查询访问属性
    
            void ClearWritableDataOnlyDetectionBit();//删除只读属性  propertyTypes &= ~PropertyTypesWritableDataOnlyDetection;
            bool IsWritableDataOnlyDetectionBitSet();
    
            inline Type * GetType() const { return type; }
    
            // In order to avoid a branch, every object has an entry point if it gets called like a
            // function - however, if it can't be called like a function, it's set to DefaultEntryPoint
            // which will emit an error.
            static Var DefaultEntryPoint(RecyclableObject* function, CallInfo callInfo, ...);
    
            BOOL HasItem(uint32 index);
            BOOL HasProperty(PropertyId propertyId);
            BOOL GetProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            BOOL GetProperty(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            BOOL GetPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            BOOL GetItem(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext);
            BOOL GetItemReference(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext);
    
            virtual PropertyId GetPropertyId(PropertyIndex index) { return Constants::NoProperty; }
            virtual PropertyId GetPropertyId(BigPropertyIndex index) { return Constants::NoProperty; }
            virtual PropertyIndex GetPropertyIndex(PropertyId propertyId) { return Constants::NoSlot; }
            virtual int GetPropertyCount() { return 0; }
            virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId);
            virtual BOOL HasOwnProperty( PropertyId propertyId);
            virtual BOOL HasOwnPropertyNoHostObject( PropertyId propertyId);
            virtual BOOL HasOwnPropertyCheckNoRedecl( PropertyId propertyId) { Assert(FALSE); return FALSE; }
            virtual BOOL UseDynamicObjectForNoHostObjectAccess() { return FALSE; }
            virtual DescriptorFlags GetSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext) { return None; }
            virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext) { return None; }
            virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            virtual BOOL GetInternalProperty(Var instance, PropertyId internalPropertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            virtual BOOL GetAccessors(PropertyId propertyId, Var* getter, Var* setter, ScriptContext * requestContext);
            virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext);
            virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info);
            virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info);
            virtual BOOL SetInternalProperty(PropertyId internalPropertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info);
            virtual BOOL InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags = PropertyOperation_None, PropertyValueInfo* info = NULL);
            virtual BOOL EnsureProperty(PropertyId propertyId);
            virtual BOOL EnsureNoRedeclProperty(PropertyId propertyId);
            virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any);
            virtual BOOL InitPropertyScoped(PropertyId propertyId, Var value);
            virtual BOOL InitFuncScoped(PropertyId propertyId, Var value);
            virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags);
            virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags);
            virtual BOOL IsFixedProperty(PropertyId propertyId);
            virtual PropertyQueryFlags HasItemQuery(uint32 index);
            virtual BOOL HasOwnItem(uint32 index);
            virtual PropertyQueryFlags GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext);
            virtual PropertyQueryFlags GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext);
            virtual DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) { return None; }
            virtual BOOL SetItem(uint32 index, Var value, PropertyOperationFlags flags);
            virtual BOOL DeleteItem(uint32 index, PropertyOperationFlags flags);
            virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, ForInCache * forInCache = nullptr);
            virtual BOOL ToPrimitive(JavascriptHint hint, Var* value, ScriptContext * requestContext);
            virtual BOOL SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags = PropertyOperation_None);
            virtual BOOL Equals(__in Var other, __out BOOL* value, ScriptContext* requestContext);
            virtual BOOL StrictEquals(__in Var other, __out BOOL* value, ScriptContext* requestContext);
            virtual BOOL IsWritable(PropertyId propertyId) { return false; }
            virtual BOOL IsConfigurable(PropertyId propertyId) { return false; }
            virtual BOOL IsEnumerable(PropertyId propertyId) { return false; }
            virtual BOOL IsExtensible() { return false; }
            virtual BOOL IsProtoImmutable() const { return false; }
            virtual BOOL PreventExtensions() { return false; };     // Sets [[Extensible]] flag of instance to false
            virtual void ThrowIfCannotDefineProperty(PropertyId propId, const PropertyDescriptor& descriptor);
            virtual void ThrowIfCannotGetOwnPropertyDescriptor(PropertyId propId) {}
            virtual BOOL GetDefaultPropertyDescriptor(PropertyDescriptor& descriptor);
            virtual BOOL Seal() { return false; }                   // Seals the instance, no additional property can be added or deleted
            virtual BOOL Freeze() { return false; }                 // Freezes the instance, no additional property can be added or deleted or written
            virtual BOOL IsSealed() { return false; }
            virtual BOOL IsFrozen() { return false; }
            virtual BOOL SetWritable(PropertyId propertyId, BOOL value) { return false; }
            virtual BOOL SetConfigurable(PropertyId propertyId, BOOL value) { return false; }
            virtual BOOL SetEnumerable(PropertyId propertyId, BOOL value) { return false; }
            virtual BOOL SetAttributes(PropertyId propertyId, PropertyAttributes attributes) { return false; }
    
            virtual BOOL GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext) { return false; }
            virtual uint GetSpecialPropertyCount() const { return 0; }
            virtual PropertyId const * GetSpecialPropertyIds() const { return nullptr; }
            virtual RecyclableObject* GetThisObjectOrUnWrap(); // Due to the withScope object there are times we need to unwrap
    
            virtual BOOL HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache = NULL);
    
            BOOL SkipsPrototype() const;
            BOOL CanHaveInterceptors() const;
            BOOL IsExternal() const;
            // Used only in JsVarToExtension where it may be during dispose and the type is not available
            virtual BOOL IsExternalVirtual() const { return FALSE; }
    
            virtual RecyclableObject* GetConfigurablePrototype(ScriptContext * requestContext) { return GetPrototype(); }
            virtual Js::JavascriptString* GetClassName(ScriptContext * requestContext);
            virtual RecyclableObject* GetProxiedObjectForHeapEnum();
    
            virtual void RemoveFromPrototype(ScriptContext * requestContext) { AssertMsg(false, "Shouldn't call this implementation."); }
            virtual void AddToPrototype(ScriptContext * requestContext) { AssertMsg(false, "Shouldn't call this implementation."); }
            virtual void SetPrototype(RecyclableObject* newPrototype) { AssertMsg(false, "Shouldn't call this implementation."); }
    
            virtual BOOL ToString(Js::Var* value, Js::ScriptContext* scriptContext) { AssertMsg(FALSE, "Do not use this function."); return false; }
    
            // don't need cross-site: in HostDispatch it's IDispatchEx based; in CustomExternalObject we have marshalling code explicitly.
            virtual Var GetNamespaceParent(Js::Var aChild) { return nullptr; }
            virtual HRESULT QueryObjectInterface(REFIID riid, void **ppvObj);
    
            virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext);
            virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext);
            virtual RecyclableObject* ToObject(ScriptContext * requestContext);
            virtual Var GetTypeOfString(ScriptContext* requestContext);
    
            // don't need cross-site: only supported in HostDispatch.
            virtual Var InvokePut(Arguments args);
            virtual BOOL GetRemoteTypeId(TypeId* typeId);
    
            // Only implemented by the HostDispatch object for cross-thread support
            // Only supports a subset of entry points to be called remotely.
            // For a list of supported entry points see the BuiltInOperation enum defined in JscriptInfo.idl
            virtual BOOL InvokeBuiltInOperationRemotely(JavascriptMethod entryPoint, Arguments args, Var* result) { return FALSE; };
    
            // don't need cross-site: only supported in HostDispatch.
            virtual DynamicObject* GetRemoteObject();
    
            // don't need cross-site: get the HostDispatch for global object/module root. don't need marshalling.
            virtual Var GetHostDispatchVar();
    
            virtual RecyclableObject * CloneToScriptContext(ScriptContext* requestContext);
    
            // If dtor is called, that means that OOM happened (mostly), then the vtable might not be initialized
            // to the base class', so we can't assert.
            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"); }
    
            static uint32 GetOffsetOfType() { return offsetof(RecyclableObject, type); }
    
            virtual void InvalidateCachedScope() { return; }
            virtual BOOL HasDeferredTypeHandler() const { return false; }
    
        private:
    
            bool dtorCalled;
    #endif
            friend class LowererMD;
            friend class LowererMDArch;
            friend struct InlineCache;
    
        private:
            UINT m_heapEnumValidationCookie;
        public:
            void SetHeapEnumValidationCookie(int cookie ) { m_heapEnumValidationCookie = cookie; }
            int GetHeapEnumValidationCookie() { return m_heapEnumValidationCookie; }
    #endif
        };
    

    ArrayBufferBase类

    ArrayBufferBase类包含一系列关于ArrayBuffer的重要操作,但是这是个抽象类,方法并未实现。
    GetByteLength //获取buffer size
    GetBuffer //获取buffer地址
    IsArrayBuffer //判断类型
    IsSharedArrayBuffer //判断类型

    比较重要的是提供了static方法AllocWrapper,负责分配VirtualBuffer内存

    class ArrayBufferBase : public DynamicObject
        {
        protected:
    		#define MAX_ASMJS_ARRAYBUFFER_LENGTH 0x100000000 // 4GB
           
    		//这个static函数会以函数指针作为参数传递,与malloc做选择
    		template<size_t MaxVirtualSize = MAX_ASMJS_ARRAYBUFFER_LENGTH>
            static void* __cdecl AllocWrapper(DECLSPEC_GUARD_OVERFLOW size_t length);
    		//VirtualFree
            static void FreeMemAlloc(Var ptr);
    
        public:
            virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) = 0;//pure virtual
    		//构造函数,设置isDetached=0
            ArrayBufferBase(DynamicType *type) : DynamicObject(type), isDetached(false) { }
            bool IsDetached() { return isDetached; }
    
            virtual bool IsArrayBuffer() = 0;//pure virtual
            virtual bool IsSharedArrayBuffer() = 0;//pure virtual
            virtual bool IsWebAssemblyArrayBuffer() { return false; }
            virtual ArrayBuffer * GetAsArrayBuffer() = 0;//pure virtual
            virtual SharedArrayBuffer * GetAsSharedArrayBuffer() { return nullptr; }
            virtual void AddParent(ArrayBufferParent* parent) { }//not defined
            virtual uint32 GetByteLength() const = 0;//pure virtual
            virtual BYTE* GetBuffer() const = 0;//pure virtual
            virtual bool IsValidVirtualBufferLength(uint length) const { return false; };//说明Base类是基类,不可直接使用
            
            //通用的static接口
            static bool Is(Var value);//static 判断类型
            static ArrayBufferBase* FromVar(Var value);//static 类型转换
    		// #define offsetof(s,m) ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
            static int GetIsDetachedOffset() { return offsetof(ArrayBufferBase, isDetached); }
    
        protected:
            Field(bool) isDetached;
        };
    

    ArrayBufferBase内存结构,此对象只有一个isDetached成员

    Js::ArrayBufferBase
    {
        Js::DynamicObject
    	isDetached bool
    }
    

    ArrayBuffer类

    ArrayBuffer类是直接对应于javascript中ArrayBuffer对象

    ArrayBuffer方法
    
    ArrayBuffer.isView(arg)
        如果参数是ArrayBuffer的视图实例就返回true,例如 typed array objects 或 DataView。否则返回false。
    ArrayBuffer.transfer(oldBuffer [, newByteLength])
        返回一个新的ArrayBuffer,其内容取自oldBuffer的数据,并且根据 newByteLength 的大小来对数据进行截取或者以0扩展。
    ArrayBuffer.prototype.slice()
        返回一个新的 ArrayBuffer ,它的内容是这个 ArrayBuffer 的字节副本,从begin(包括),到end(不包括)。如果begin或end是负数,则指的是从数组末尾开始的索引,而不是从头开始。
    ArrayBuffer.slice()
        和 ArrayBuffer.prototype.slice()功能一样
        
    ArrayBuffer属性
        
    ArrayBuffer.length
        ArrayBuffer构造函数的length属性,它的值是1
    ArrayBuffer.prototype.constructor
        指定函数,它创建一个对象的原型。其初始值是标准ArrayBuffer内置构造函数。
    ArrayBuffer.prototype.byteLength 只读
        数组的字节大小。在数组创建时确定,并且不可变更。只读
    
    内存结构
    可以看到对于ArrayBuffer来说,重要的结构在ArrayBuffer对象中都已给出
    
    Js::ArrayBuffer
    {
    	Js::ArrayBufferBase	Js::ArrayBufferBase
    	primaryParent	Recycler*
    	otherParents	OtherParents*
    	buffer			byte*
    	bufferLength	uint32
    }
    
    class ArrayBuffer : public ArrayBufferBase
        {
        public:
            // we need to install cross-site thunk on the nested array buffer when marshaling
            // typed array.
            DEFINE_VTABLE_CTOR_ABSTRACT(ArrayBuffer, ArrayBufferBase);
        private:
            void DetachBufferFromParent(ArrayBufferParent* parent);
        public:
    	
            template <typename FreeFN>
            class ArrayBufferDetachedState : public ArrayBufferDetachedStateBase
            {
            public:
                FreeFN* freeFunction;
    
                ArrayBufferDetachedState(BYTE* buffer, uint32 bufferLength, FreeFN* freeFunction, ArrayBufferAllocationType allocationType)
                    : ArrayBufferDetachedStateBase(TypeIds_ArrayBuffer, buffer, bufferLength, allocationType),
                    freeFunction(freeFunction)
                {}
    
                virtual void ClearSelfOnly() override
                {
                    HeapDelete(this);
                }
    
                virtual void DiscardState() override
                {
                    if (this->buffer != nullptr)
                    {
                        freeFunction(this->buffer);
                        this->buffer = nullptr;
                    }
                    this->bufferLength = 0;
                }
    
                virtual void Discard() override
                {
                    ClearSelfOnly();
                }
            };
    
    
            class EntryInfo
            {
            public:
                static FunctionInfo NewInstance;
                static FunctionInfo Slice;
                static FunctionInfo IsView;
                static FunctionInfo GetterByteLength;
                static FunctionInfo GetterSymbolSpecies;
                static FunctionInfo Transfer;
            };
    
            //newArr = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);
    		static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
    		
    		//ArrayBuffer.prototype.slice()
            static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
    		
    		//ArrayBuffer.isView()
    		//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/isView
            static Var EntryIsView(RecyclableObject* function, CallInfo callInfo, ...);
    		
    		//ArrayBuffer.prototype.byteLength
    		//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/byteLength
            static Var EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...);
    		
            static Var EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...);
    		
    		//ArrayBuffer.transfer()
    		//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/transfer
            static Var EntryTransfer(RecyclableObject* function, CallInfo callInfo, ...);
    		
    		//判定类型
            static bool Is(Var aValue);
    		//
            static ArrayBuffer* NewFromDetachedState(DetachedStateBase* state, JavascriptLibrary *library);
    		//类型转换
            static ArrayBuffer* FromVar(Var aValue);
    	
    		//Detach
            virtual ArrayBufferDetachedStateBase* DetachAndGetState();
            virtual uint32 GetByteLength() const override { return bufferLength; }
            virtual BYTE* GetBuffer() const override { return buffer; }
    
            static int GetByteLengthOffset() { return offsetof(ArrayBuffer, bufferLength); }//ArrayBuffer中bufferLength的offset
            static int GetBufferOffset() { return offsetof(ArrayBuffer, buffer); }//ArrayBuffer中buffer的offset
    		
    		//设定parent
            virtual void AddParent(ArrayBufferParent* parent) override;
    		
            //maximum 2G -1  for amd64
            static const uint32 MaxArrayBufferLength = 0x7FFFFFFF;
    
            static const uint32 ParentsCleanupThreshold = 1000;
    
            virtual bool IsValidAsmJsBufferLength(uint length, bool forceCheck = false) { return false; }
            virtual bool IsArrayBuffer() override { return true; }
            virtual bool IsSharedArrayBuffer() override { return false; }
            virtual ArrayBuffer * GetAsArrayBuffer() override { return ArrayBuffer::FromVar(this); }
    
            static uint32 ToIndex(Var value, int32 errorCode, ScriptContext *scriptContext, uint32 MaxAllowedLength, bool checkSameValueZero = true);
    
            virtual ArrayBuffer * TransferInternal(DECLSPEC_GUARD_OVERFLOW uint32 newBufferLength) = 0;
        
    	protected:
    	
            typedef void __cdecl FreeFn(void* ptr);
    		
            virtual ArrayBufferDetachedStateBase* CreateDetachedState(BYTE* buffer, DECLSPEC_GUARD_OVERFLOW uint32 bufferLength) = 0;
    
            static uint32 GetIndexFromVar(Js::Var arg, uint32 length, ScriptContext* scriptContext);
    
            //In most cases, the ArrayBuffer will only have one parent
            Field(RecyclerWeakReference<ArrayBufferParent>*) primaryParent;
    
            struct OtherParents :public SList<RecyclerWeakReference<ArrayBufferParent>*, Recycler>
            {
                OtherParents(Recycler* recycler)
                    :SList<RecyclerWeakReference<ArrayBufferParent>*, Recycler>(recycler), increasedCount(0)
                {
                }
                Field(uint) increasedCount;
            };
    
            Field(OtherParents*) otherParents;
    
            FieldNoBarrier(BYTE*) buffer;      // Points to a heap allocated RGBA buffer, can be null
            Field(uint32) bufferLength;       // Number of bytes allocated
        };
    

    TypedArrayBase

    对于TypedArray的常见操作都已经给出,但是是纯虚函数

    class TypedArrayBase : public ArrayBufferParent
        {
            friend ArrayBuffer;
            friend ArrayBufferBase;
    
        public:
            static Var GetDefaultConstructor(Var object, ScriptContext* scriptContext);
    
            class EntryInfo
            {
            public:
                static FunctionInfo NewInstance;
                static FunctionInfo Set;
                static FunctionInfo Subarray;
    
                static FunctionInfo From;
                static FunctionInfo Of;
                static FunctionInfo CopyWithin;
                static FunctionInfo Entries;
                static FunctionInfo Every;
                static FunctionInfo Fill;
                static FunctionInfo Filter;
                static FunctionInfo Find;
                static FunctionInfo FindIndex;
                static FunctionInfo ForEach;
                static FunctionInfo IndexOf;
                static FunctionInfo Includes;
                static FunctionInfo Join;
                static FunctionInfo Keys;
                static FunctionInfo LastIndexOf;
                static FunctionInfo Map;
                static FunctionInfo Reduce;
                static FunctionInfo ReduceRight;
                static FunctionInfo Reverse;
                static FunctionInfo Slice;
                static FunctionInfo Some;
                static FunctionInfo Sort;
                static FunctionInfo Values;
    
                static FunctionInfo GetterBuffer;
                static FunctionInfo GetterByteLength;
                static FunctionInfo GetterByteOffset;
                static FunctionInfo GetterLength;
                static FunctionInfo GetterSymbolToStringTag;
                static FunctionInfo GetterSymbolSpecies;
            };
    
            TypedArrayBase(ArrayBufferBase* arrayBuffer, uint byteOffset, uint mappedLength, uint elementSize, DynamicType* type);
    		
    		//创建函数
            static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
    
            static Var EntrySet(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntrySubarray(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryFrom(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryOf(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryCopyWithin(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryEntries(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryEvery(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryFill(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryFilter(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryFind(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryFindIndex(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryForEach(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryIncludes(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryJoin(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryKeys(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryLastIndexOf(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryMap(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryReduce(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryReduceRight(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryReverse(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntrySlice(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntrySome(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntrySort(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryValues(RecyclableObject* function, CallInfo callInfo, ...);
    
            static Var EntryGetterBuffer(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryGetterByteLength(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryGetterByteOffset(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryGetterLength(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryGetterSymbolToStringTag(RecyclableObject* function, CallInfo callInfo, ...);
            static Var EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...);
    
            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 DescriptorFlags GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext) override;
            virtual PropertyQueryFlags HasPropertyQuery(Js::PropertyId propertyId) override;
            virtual BOOL HasOwnProperty(Js::PropertyId propertyId) override;
            virtual PropertyQueryFlags GetPropertyQuery(Js::Var originalInstance, Js::PropertyId propertyId, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) override;
            virtual PropertyQueryFlags GetPropertyQuery(Js::Var originalInstance, Js::JavascriptString* propertyNameString, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) override;
            virtual PropertyQueryFlags GetPropertyReferenceQuery(Js::Var originalInstance, Js::PropertyId propertyId, Js::Var* value, Js::PropertyValueInfo* info, Js::ScriptContext* requestContext) override;
            virtual PropertyQueryFlags HasItemQuery(uint32 index) override;
            virtual BOOL DeleteItem(uint32 index, Js::PropertyOperationFlags flags) override { return false; }
            virtual PropertyQueryFlags GetItemQuery(Js::Var originalInstance, uint32 index, Js::Var* value, Js::ScriptContext * requestContext) override;
            virtual BOOL SetItem(uint32 index, Js::Var value, Js::PropertyOperationFlags flags = PropertyOperation_None) override;
            virtual BOOL SetProperty(Js::PropertyId propertyId, Js::Var value, Js::PropertyOperationFlags flags, Js::PropertyValueInfo* info) override;
            virtual BOOL SetProperty(Js::JavascriptString* propertyNameString, Js::Var value, Js::PropertyOperationFlags flags, Js::PropertyValueInfo* info) override;
            virtual BOOL DeleteProperty(Js::PropertyId propertyId, Js::PropertyOperationFlags flags) override;
            virtual BOOL DeleteProperty(JavascriptString *propertyNameString, Js::PropertyOperationFlags flags) override;
            virtual PropertyQueryFlags GetItemReferenceQuery(Js::Var originalInstance, uint32 index, Js::Var* value, Js::ScriptContext * requestContext) override;
            virtual BOOL GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, ForInCache * forInCache = nullptr) override;
            virtual JavascriptEnumerator * GetIndexEnumerator(EnumeratorFlags flags, ScriptContext * requestContext) override;
    
            virtual BOOL IsEnumerable(PropertyId propertyId)  override;
            virtual BOOL IsConfigurable(PropertyId propertyId)  override;
            virtual BOOL IsWritable(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 SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags) override;
    
            virtual BOOL InitProperty(Js::PropertyId propertyId, Js::Var value, PropertyOperationFlags flags = PropertyOperation_None, Js::PropertyValueInfo* info = NULL) override;
            virtual BOOL SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags = PropertyOperation_None, SideEffects possibleSideEffects = SideEffects_Any) override;
            static BOOL Is(Var aValue);
            static BOOL Is(TypeId typeId);
            static TypedArrayBase* FromVar(Var aValue);
            // Returns false if this is not a TypedArray or it's not detached
            static BOOL IsDetachedTypedArray(Var aValue);
            static HRESULT GetBuffer(Var aValue, ArrayBuffer** outBuffer, uint32* outOffset, uint32* outLength);
            static TypedArrayBase * ValidateTypedArray(Var aValue, ScriptContext *scriptContext, LPCWSTR apiName);
            static TypedArrayBase * ValidateTypedArray(Arguments &args, ScriptContext *scriptContext, LPCWSTR apiName);
            static Var TypedArrayCreate(Var constructor, Arguments *args, uint32 length, ScriptContext *scriptContext);
    
    		//写入操作 pure virtual
            virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) = 0;
            virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) = 0;
            virtual Var  DirectGetItem(__in uint32 index) = 0;
            virtual BOOL DirectSetItemNoDetachCheck(__in uint32 index, __in Js::Var value) = 0;
            virtual Var  DirectGetItemNoDetachCheck(__in uint32 index) = 0;
    
            virtual Var TypedAdd(__in uint32 index, Var second) = 0;
            virtual Var TypedAnd(__in uint32 index, Var second) = 0;
            virtual Var TypedLoad(__in uint32 index) = 0;
            virtual Var TypedOr(__in uint32 index, Var second) = 0;
            virtual Var TypedStore(__in uint32 index, Var second) = 0;
            virtual Var TypedSub(__in uint32 index, Var second) = 0;
            virtual Var TypedXor(__in uint32 index, Var second) = 0;
            virtual Var TypedExchange(__in uint32 index, Var second) = 0;
            virtual Var TypedCompareExchange(__in uint32 index, Var comparand, Var replacementValue) = 0;
    		
    		//TypedArray.prototype.byteLength
            uint32 GetByteLength() const { return length * BYTES_PER_ELEMENT; }
    		//TypedArray.prototype.byteOffset
            uint32 GetByteOffset() const { return byteOffset; }
            uint32 GetBytesPerElement() const { return BYTES_PER_ELEMENT; }
    		//TypedArray.prototype.buffer
            byte*  GetByteBuffer() const { return buffer; };
    		
            bool IsDetachedBuffer() const { return this->GetArrayBuffer()->IsDetached(); }
            void ClearLengthAndBufferOnDetach();
            static Var CommonSet(Arguments& args);
            static Var CommonSubarray(Arguments& args);
    
            void SetObject(RecyclableObject* arraySource, uint32 targetLength, uint32 offset = 0);
            void SetObjectNoDetachCheck(RecyclableObject* arraySource, uint32 targetLength, uint32 offset = 0);
            void Set(TypedArrayBase* typedArraySource, uint32 offset = 0);
    
            virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
            virtual BOOL GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
    
            static bool TryGetLengthForOptimizedTypedArray(const Var var, uint32 *const lengthRef, TypeId *const typeIdRef);
            BOOL ValidateIndexAndDirectSetItem(__in Js::Var index, __in Js::Var value, __out bool * isNumericIndex);
            uint32 ValidateAndReturnIndex(__in Js::Var index, __out bool * skipOperation, __out bool * isNumericIndex);
    
            // objectArray support
            virtual BOOL SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes) override;
    
            Var FindMinOrMax(Js::ScriptContext * scriptContext, TypeId typeId, bool findMax);
            template<typename T, bool checkNaNAndNegZero> Var FindMinOrMax(Js::ScriptContext * scriptContext, bool findMax);
    
            static Var GetKeysEntriesValuesHelper(Arguments& args, ScriptContext *scriptContext, LPCWSTR apiName, JavascriptArrayIteratorKind kind);
    
            static uint32 GetFromIndex(Var arg, uint32 length, ScriptContext *scriptContext);
    
        private:
            uint32 GetSourceLength(RecyclableObject* arraySource, uint32 targetLength, uint32 offset);
    
        protected:
            static Var CreateNewInstanceFromIterator(RecyclableObject *iterator, ScriptContext *scriptContext, uint32 elementSize, PFNCreateTypedArray pfnCreateTypedArray);
            static Var CreateNewInstance(Arguments& args, ScriptContext* scriptContext, uint32 elementSize, PFNCreateTypedArray pfnCreateTypedArray );
            static bool ArrayIteratorPrototypeHasUserDefinedNext(ScriptContext *scriptContext);
            static BOOL CanonicalNumericIndexString(PropertyId propertyId, ScriptContext *scriptContext);
            static BOOL CanonicalNumericIndexString(JavascriptString *propertyString, ScriptContext *scriptContext);
    
            typedef int(__cdecl* CompareElementsFunction)(void*, const void*, const void*);
            virtual CompareElementsFunction GetCompareElementsFunction() = 0;
    
            virtual Var Subarray(uint32 begin, uint32 end) = 0;
            Field(int32) BYTES_PER_ELEMENT;
            Field(uint32) byteOffset;
            FieldNoBarrier(BYTE*) buffer;   // beginning of mapped array.
    
        public:
            static uint32 GetOffsetOfBuffer()  { return offsetof(TypedArrayBase, buffer); }
            static uint32 GetOffsetOfLength()  { return offsetof(TypedArrayBase, length); }
    
        };
    

    TypedArray

    内存结构

    Js::TypedArray
    {
        Js::TypedArrayBase
        {
    		Js::ArrayBufferParent
    		{
    		    Js::ArrayObject
    		    arrayBuffer	        Js::JavascriptArrayBuffer*
    		}
    		BYTES_PER_ELEMENT		int
    		byteOffset		unsigned int
    		buffer          unsigned char *
        }
    }
    
    

    TypedArray类复写实现了虚函数和实际的操作方法
    并不存在单独的TypedArray类型的类,都是针对模版进行的特例化

        template <typename TypeName, bool clamped = false, bool virtualAllocated = false>
        class TypedArray : public TypedArrayBase
        {
        protected:
            DEFINE_VTABLE_CTOR(TypedArray, TypedArrayBase);
            virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext)
            {
                Assert(this->GetScriptContext() != scriptContext);
                AssertMsg(VirtualTableInfo<TypedArray>::HasVirtualTable(this), "Derived class need to define marshal to script context");
    
                VirtualTableInfo<Js::CrossSiteObject<TypedArray<TypeName, clamped, virtualAllocated>>>::SetVirtualTable(this);
                ArrayBufferBase* arrayBuffer = this->GetArrayBuffer();
                if (arrayBuffer && !arrayBuffer->IsCrossSiteObject())
                {
                    arrayBuffer->MarshalToScriptContext(scriptContext);
                }
            }
    
            TypedArray(DynamicType *type): TypedArrayBase(nullptr, 0, 0, sizeof(TypeName), type) { buffer = nullptr; }
    
        public:
            class EntryInfo
            {
            public:
                static FunctionInfo NewInstance;
                static FunctionInfo Set;
            };
    
            TypedArray(ArrayBufferBase* arrayBuffer, uint32 byteOffset, uint32 mappedLength, DynamicType* type);
    
            static Var Create(ArrayBufferBase* arrayBuffer, uint32 byteOffSet, uint32 mappedLength, JavascriptLibrary* javascriptLibrary);
            static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
    
            static Var EntrySet(RecyclableObject* function, CallInfo callInfo, ...);
    
            Var Subarray(uint32 begin, uint32 end);
    
            static BOOL Is(Var aValue);
            static TypedArray<TypeName, clamped, virtualAllocated>* FromVar(Var aValue);
    
            inline Var BaseTypedDirectGetItem(__in uint32 index)
            {
                if (this->IsDetachedBuffer()) // 9.4.5.8 IntegerIndexedElementGet
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
    
                if (index < GetLength())
                {
                    Assert((index + 1)* sizeof(TypeName)+GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                    TypeName* typedBuffer = (TypeName*)buffer;
                    return JavascriptNumber::ToVar(typedBuffer[index], GetScriptContext());
                }
                return GetLibrary()->GetUndefined();
            }
    
            inline Var TypedDirectGetItemWithCheck(__in uint32 index)
            {
                if (this->IsDetachedBuffer()) // 9.4.5.8 IntegerIndexedElementGet
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
    
                if (index < GetLength())
                {
                    Assert((index + 1)* sizeof(TypeName)+GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                    TypeName* typedBuffer = (TypeName*)buffer;
                    return JavascriptNumber::ToVarWithCheck(typedBuffer[index], GetScriptContext());
                }
                return GetLibrary()->GetUndefined();
            }
    
            inline Var BaseTypedDirectGetItemNoDetachCheck(__in uint32 index)
            {
                Assert(!IsDetachedBuffer());
                Assert(index < GetLength());
                Assert((index + 1)* sizeof(TypeName) + GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                TypeName* typedBuffer = (TypeName*)buffer;
                return JavascriptNumber::ToVar(typedBuffer[index], GetScriptContext());
            }
    
            inline Var DirectGetItemVarCheckNoDetachCheck(__in uint32 index)
            {
                Assert(!IsDetachedBuffer());
                Assert(index < GetLength());
                Assert((index + 1)* sizeof(TypeName) + GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                TypeName* typedBuffer = (TypeName*)buffer;
                return JavascriptNumber::ToVarWithCheck(typedBuffer[index], GetScriptContext());
            }
    
            inline BOOL DirectSetItemAtRange(TypedArray *fromArray, __in int32 iSrcStart, __in int32 iDstStart, __in uint32 length, TypeName(*convFunc)(Var value, ScriptContext* scriptContext))
            {
                TypeName* dstBuffer = (TypeName*)buffer;
                TypeName* srcBuffer = (TypeName*)fromArray->buffer;
                Assert(srcBuffer && dstBuffer);
                Assert(length <= ArrayBuffer::MaxArrayBufferLength / sizeof(TypeName));
                // caller checks that src and dst index are the same
                Assert(iSrcStart == iDstStart);
    
                if (this->IsDetachedBuffer() || fromArray->IsDetachedBuffer())
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
    
                // Fixup destination start in case it's negative
                uint32 start = iDstStart;
                if (iDstStart < 0)
                {
                    if ((int64)(length) + iDstStart < 0)
                    {
                        // nothing to do, all index are no-op
                        return true;
                    }
    
                    length += iDstStart;
                    start = 0;
                }
    
                uint32 dstLength = UInt32Math::Add(start, length) < GetLength() ? length : GetLength() > start ? GetLength() - start : 0;
                uint32 srcLength = start + length < fromArray->GetLength() ? length : (fromArray->GetLength() > start ? fromArray->GetLength() - start : 0);
    
                // length is the minimum of length, srcLength and dstLength
                length = length < srcLength ? (length < dstLength ? length : dstLength) : (srcLength < dstLength ? srcLength : dstLength);
    
                const size_t byteSize = sizeof(TypeName) * length;
                Assert(byteSize >= length); // check for overflow
                js_memcpy_s(dstBuffer + start, dstLength * sizeof(TypeName), srcBuffer + start, byteSize);
    
                if (dstLength > length)
                {
                    TypeName undefinedValue = convFunc(GetLibrary()->GetUndefined(), GetScriptContext());
                    for (uint32 i = length; i < dstLength; i++)
                    {
                        dstBuffer[i] = undefinedValue;
                    }
                }
    
                return true;
            }
    
            inline BOOL DirectSetItemAtRange(__in int32 start, __in uint32 length, __in Js::Var value, TypeName(*convFunc)(Var value, ScriptContext* scriptContext))
            {
                if (CrossSite::IsCrossSiteObjectTyped(this))
                {
                    return false;
                }
                TypeName typedValue = convFunc(value, GetScriptContext());
    
                if (this->IsDetachedBuffer()) // 9.4.5.9 IntegerIndexedElementSet
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
                uint32 newStart = start, newLength = length;
    
                if (start < 0)
                {
                    if ((int64)(length) + start < 0)
                    {
                        // nothing to do, all index are no-op
                        return true;
                    }
                    newStart = 0;
                    // fixup the length with the change
                    newLength += start;
                }
                if (newStart >= GetLength())
                {
                    // If we want to start copying past the length of the array, all index are no-op
                    return true;
                }
                if (UInt32Math::Add(newStart, newLength) > GetLength())
                {
                    newLength = GetLength() - newStart;
                }
    
                TypeName* typedBuffer = (TypeName*)buffer;
    
                if (typedValue == 0 || sizeof(TypeName) == 1)
                {
                    const size_t byteSize = sizeof(TypeName) * newLength;
                    Assert(byteSize >= newLength); // check for overflow
                    memset(typedBuffer + newStart, (int)typedValue, byteSize);
                }
                else
                {
                    for (uint32 i = 0; i < newLength; i++)
                    {
                        typedBuffer[newStart + i] = typedValue;
                    }
                }
    
                return TRUE;
            }
    
            inline BOOL BaseTypedDirectSetItem(__in uint32 index, __in Js::Var value, TypeName (*convFunc)(Var value, ScriptContext* scriptContext))
            {
                // This call can potentially invoke user code, and may end up detaching the underlying array (this).
                // Therefore it was brought out and above the IsDetached check
                TypeName typedValue = convFunc(value, GetScriptContext());
    
                if (this->IsDetachedBuffer()) // 9.4.5.9 IntegerIndexedElementSet
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
    
                if (index >= GetLength())
                {
                    return FALSE;
                }
    
                AssertMsg(index < GetLength(), "Trying to set out of bound index for typed array.");
                Assert((index + 1)* sizeof(TypeName) + GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                TypeName* typedBuffer = (TypeName*)buffer;
    
                typedBuffer[index] = typedValue;
    
                return TRUE;
            }
    
            inline BOOL BaseTypedDirectSetItemNoSet(__in uint32 index, __in Js::Var value, TypeName (*convFunc)(Var value, ScriptContext* scriptContext))
            {
                // This call can potentially invoke user code, and may end up detaching the underlying array (this).
                // Therefore it was brought out and above the IsDetached check
                convFunc(value, GetScriptContext());
    
                if (this->IsDetachedBuffer()) // 9.4.5.9 IntegerIndexedElementSet
                {
                    JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_DetachedTypedArray);
                }
    
                return FALSE;
            }
    
            inline BOOL BaseTypedDirectSetItemNoDetachCheck(__in uint32 index, __in Js::Var value, TypeName(*convFunc)(Var value, ScriptContext* scriptContext))
            {
                TypeName typedValue = convFunc(value, GetScriptContext());
    
                // The caller of the function made sure that no IsDetached check required.
                // The caller of the function also made sure that no length check required.
    
                Assert(!IsDetachedBuffer());
                AssertMsg(index < GetLength(), "Trying to set out of bound index for typed array.");
                Assert((index + 1)* sizeof(TypeName) + GetByteOffset() <= GetArrayBuffer()->GetByteLength());
                TypeName* typedBuffer = (TypeName*)buffer;
    
                typedBuffer[index] = typedValue;
    
                return TRUE;
            }
    
    
            virtual BOOL DirectSetItem(__in uint32 index, __in Js::Var value) override sealed;
            virtual BOOL DirectSetItemNoSet(__in uint32 index, __in Js::Var value) override sealed;
            virtual Var  DirectGetItem(__in uint32 index) override sealed;
            virtual BOOL DirectSetItemNoDetachCheck(__in uint32 index, __in Js::Var value) override sealed;
            virtual Var  DirectGetItemNoDetachCheck(__in uint32 index) override sealed;
            virtual Var TypedAdd(__in uint32 index, Var second) override;
            virtual Var TypedAnd(__in uint32 index, Var second) override;
            virtual Var TypedLoad(__in uint32 index) override;
            virtual Var TypedOr(__in uint32 index, Var second) override;
            virtual Var TypedStore(__in uint32 index, Var second) override;
            virtual Var TypedSub(__in uint32 index, Var second) override;
            virtual Var TypedXor(__in uint32 index, Var second) override;
            virtual Var TypedExchange(__in uint32 index, Var second) override;
            virtual Var TypedCompareExchange(__in uint32 index, Var comparand, Var replacementValue) override;
    
            static BOOL DirectSetItem(__in TypedArray* arr, __in uint32 index, __in Js::Var value)
            {
                AssertMsg(arr != nullptr, "Array shouldn't be nullptr.");
    
                return arr->DirectSetItem(index, value);
            }
    
        protected:
            CompareElementsFunction GetCompareElementsFunction()
            {
                return &TypedArrayCompareElementsHelper<TypeName>;
            }
    
        public:
            virtual VTableValue DummyVirtualFunctionToHinderLinkerICF();
        };
    
  • 相关阅读:
    spring学习笔记__spring的单例多例模式
    spring学习笔记_spring入门
    Lambda表达式
    反射
    fatal error: call to undefined function imagettftext
    阿里云 centos 安装apache和php
    php 使用 极光推送 类
    php socket解决方案
    身份证号码 15位和18位 验证
    php memcache扩展 出现错误dyld: Symbol not found: _mmc_queue_free
  • 原文地址:https://www.cnblogs.com/Ox9A82/p/7308337.html
Copyright © 2011-2022 走看看