Skip to content

Commit 7d57bb3

Browse files
committed
[MERGE #1533 @akroshg] SharedArrayBuffer - Initial work.
Merge pull request #1533 from akroshg:sab This work is to implement a prototype version of the `SharedArrayBuffer`. The spec is in the stage2. The `SharedArrayBuffer` is behind the `ESSharedArrayBuffer` (or -sab) flag. Highlights. Introduce the `SharedArrayBuffer` type and its implementation. Refactor the `ArrayBuffer` to a common class (`ArrayBufferBase`) so that both `SharedArrayBuffer` and `ArrayBuffer` leverage the common functionality and machinery. `Atomics` object (spec'ed) is introduced to provide the atomic operation on the buffer which is shared. Currently it is using the Win32 based APIs to provide the functionality. All 12 methods of `Atomics` are implemented. All `TypedArray` views are changed to make use of `SharedArrayBuffer` as well. The `Serialization/Deserialization` implementation is in the different repo. Added test cases to validate most of the functionality. sharedarraybuffer - initial work
2 parents c391c55 + ba48081 commit 7d57bb3

40 files changed

+3889
-1332
lines changed

lib/Common/ConfigFlagsList.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ PHASE(All)
574574
#define DEFAULT_CONFIG_ES7TrailingComma (true)
575575
#define DEFAULT_CONFIG_ES7ValuesEntries (true)
576576
#define DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors (true)
577+
#define DEFAULT_CONFIG_ESSharedArrayBuffer (false)
577578
#define DEFAULT_CONFIG_ES6Verbose (false)
578579
#define DEFAULT_CONFIG_ES6All (false)
579580
// ES6 DEFAULT BEHAVIOR
@@ -784,6 +785,14 @@ PHASE(All)
784785
#define FLAGPR(Type, ParentName, Name, String, Default) FLAG(Type, Name, String, Default, ParentName, FALSE)
785786
#define FLAGR(Type, Name, String, Default) FLAG(Type, Name, String, Default, NoParent, FALSE)
786787

788+
// Release flags with parent and acronym
789+
#ifndef FLAGPRA
790+
#define FLAGPRA(Type, ParentName, Name, Acronym, String, Default) \
791+
FLAGPR(Type, ParentName, Name, String, Default) \
792+
FLAGNR(Type, Acronym, String, Default)
793+
#endif
794+
795+
787796
// RELEASE FLAGS WITH REGISTRY OVERRIDE
788797
#define FLAGPR_REGOVR_ASMJS(Type, ParentName, Name, String, Default) FLAG_REGOVR_ASMJS(Type, Name, String, Default, ParentName, FALSE)
789798
#define FLAGPR_REGOVR_EXP(Type, ParentName, Name, String, Default) FLAG_REGOVR_EXP(Type, Name, String, Default, ParentName, FALSE)
@@ -1013,7 +1022,8 @@ FLAGPR (Boolean, ES6, ES6Verbose , "Enable ES6 verbose tra
10131022
#endif
10141023
FLAGPR_REGOVR_EXP(Boolean, ES6, ArrayBufferTransfer , "Enable ArrayBuffer.transfer" , DEFAULT_CONFIG_ArrayBufferTransfer)
10151024

1016-
FLAGPR (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors" , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
1025+
FLAGPR (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors" , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
1026+
FLAGPRA (Boolean, ES6, ESSharedArrayBuffer , sab , "Enable SharedArrayBuffer" , DEFAULT_CONFIG_ESSharedArrayBuffer)
10171027

10181028
// /ES6 (BLUE+1) features/flags
10191029

@@ -1474,5 +1484,6 @@ FLAGNR(Boolean, CFG, "Force enable CFG on jshost. version in the jshost's manife
14741484
#undef FLAGNR
14751485
#undef FLAGNRA
14761486
#undef FLAGPNR
1487+
#undef FLAGPRA
14771488

14781489
#endif

lib/Common/Core/ConfigFlagsTable.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ namespace Js
396396
Name = Acronym; \
397397
}
398398
#if ENABLE_DEBUG_CONFIG_OPTIONS
399+
#define FLAGPRA(Type, ParentName, Name, Acronym, ...) \
400+
if(!IsEnabled(Name##Flag) && IsEnabled(Acronym##Flag)) \
401+
{ \
402+
Enable(Name##Flag); \
403+
Name = Acronym; \
404+
}
399405
#define FLAGRA(Type, Name, Acronym, ...) FLAGNRA(Type, Name, Acronym, __VA_ARGS__)
400406
#endif
401407
#include "ConfigFlagsList.h"

lib/Jsrt/Jsrt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1880,7 +1880,7 @@ Js::ArrayObject* CreateTypedArray(Js::ScriptContext *scriptContext, void* data,
18801880
{
18811881
Js::JavascriptLibrary* library = scriptContext->GetLibrary();
18821882

1883-
Js::ArrayBuffer* arrayBuffer = RecyclerNew(
1883+
Js::ArrayBufferBase* arrayBuffer = RecyclerNew(
18841884
scriptContext->GetRecycler(),
18851885
Js::ExternalArrayBuffer,
18861886
reinterpret_cast<BYTE*>(data),

lib/Parser/rterrors.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,8 @@ RT_ERROR_MSG(JSERR_InvalidHint, 5658, "%s: invalid hint", "invalid hint", kjstTy
357357

358358
RT_ERROR_MSG(JSERR_This_NeedNamespace, 5659, "%s: 'this' is not a Module Namespace object", "Module Namespace object expected", kjstTypeError, JSERR_This_NeedNamespace) // {Locked="\'this\'"}
359359
RT_ERROR_MSG(JSERR_This_NeedListIterator, 5660, "%s: 'this' is not a List Iterator object", "List Iterator expected", kjstTypeError, 0)
360+
RT_ERROR_MSG(JSERR_NeedSharedArrayBufferObject, 5661, "%s is not a SharedArrayBuffer", "SharedArrayBuffer object expected", kjstTypeError, 0)
361+
RT_ERROR_MSG(JSERR_NeedTypedArrayObject, 5662, "", "Atomics function called with invalid typed array object", kjstTypeError, 0)
362+
RT_ERROR_MSG(JSERR_InvalidTypedArrayIndex, 5663, "", "Access index is out of range", kjstRangeError, 0)
363+
RT_ERROR_MSG(JSERR_InvalidOperationOnTypedArray, 5664, "", "The operation is not supported on this typed array type", kjstRangeError, 0)
364+
RT_ERROR_MSG(JSERR_CannotSuspendBuffer, 5665, "", "Current agent cannot be suspended", kjstRangeError, 0)

lib/Runtime/Base/FunctionBody.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace Js
4747
class AmsJsModuleInfo;
4848
#endif
4949
class ArrayBuffer;
50+
class SharedArrayBuffer;
5051
class FunctionCodeGenRuntimeData;
5152
#pragma endregion
5253

lib/Runtime/Base/JnDirectFields.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,14 @@ ENTRY(screen)
697697
ENTRY(padStart)
698698
ENTRY(padEnd)
699699

700+
ENTRY(SharedArrayBuffer)
701+
ENTRY(Atomics)
702+
ENTRY(compareExchange)
703+
ENTRY(exchange)
704+
ENTRY(isLockFree)
705+
ENTRY(wait)
706+
ENTRY(wake)
707+
700708
// Note: Do not add fields for conditionally-compiled PropertyIds into this file.
701709
// The bytecode for internal javascript libraries is built on chk but re-used in fre builds.
702710
// Having a mismatch in the number of PropertyIds will cause a failure loading bytecode.

lib/Runtime/Base/ThreadConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ FLAG_RELEASE(SkipSplitOnNoResult, SkipSplitOnNoResult)
4747
FLAG_RELEASE(IsES7AsyncAndAwaitEnabled, ES7AsyncAwait)
4848
FLAG_RELEASE(IsArrayBufferTransferEnabled, ArrayBufferTransfer)
4949
FLAG_RELEASE(IsESObjectGetOwnPropertyDescriptorsEnabled, ESObjectGetOwnPropertyDescriptors)
50+
FLAG_RELEASE(IsESSharedArrayBufferEnabled, ESSharedArrayBuffer)
5051
#ifdef ENABLE_PROJECTION
5152
FLAG(AreWinRTDelegatesInterfaces, WinRTDelegateInterfaces)
5253
FLAG_RELEASE(IsWinRTAdaptiveAppsEnabled, WinRTAdaptiveApps)

lib/Runtime/Language/JavascriptOperators.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5330,9 +5330,10 @@ namespace Js
53305330
{
53315331
switch (state->GetTypeId())
53325332
{
5333+
case TypeIds_SharedArrayBuffer:
5334+
return Js::SharedArrayBuffer::NewFromSharedState(state, library);
53335335
case TypeIds_ArrayBuffer:
53345336
return Js::ArrayBuffer::NewFromDetachedState(state, library);
5335-
break;
53365337
default:
53375338
AssertMsg(false, "We should explicitly have a case statement for each object which has detached state.");
53385339
return nullptr;

lib/Runtime/Library/ArrayBuffer.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66

77
namespace Js
88
{
9+
bool ArrayBufferBase::Is(Var value)
10+
{
11+
return ArrayBuffer::Is(value) || SharedArrayBuffer::Is(value);
12+
}
13+
14+
ArrayBufferBase* ArrayBufferBase::FromVar(Var value)
15+
{
16+
Assert(ArrayBufferBase::Is(value));
17+
return static_cast<ArrayBuffer *> (value);
18+
}
19+
920
ArrayBuffer* ArrayBuffer::NewFromDetachedState(DetachedStateBase* state, JavascriptLibrary *library)
1021
{
1122
ArrayBufferDetachedStateBase* arrayBufferState = (ArrayBufferDetachedStateBase *)state;
@@ -426,7 +437,7 @@ namespace Js
426437

427438
template <class Allocator>
428439
ArrayBuffer::ArrayBuffer(uint32 length, DynamicType * type, Allocator allocator) :
429-
DynamicObject(type), mIsAsmJsBuffer(false), isBufferCleared(false),isDetached(false)
440+
ArrayBufferBase(type), mIsAsmJsBuffer(false), isBufferCleared(false),isDetached(false)
430441
{
431442
buffer = nullptr;
432443
bufferLength = 0;
@@ -473,7 +484,7 @@ namespace Js
473484
}
474485

475486
ArrayBuffer::ArrayBuffer(byte* buffer, uint32 length, DynamicType * type) :
476-
buffer(buffer), bufferLength(length), DynamicObject(type), mIsAsmJsBuffer(false), isDetached(false)
487+
buffer(buffer), bufferLength(length), ArrayBufferBase(type), mIsAsmJsBuffer(false), isDetached(false)
477488
{
478489
if (length > MaxArrayBufferLength)
479490
{

lib/Runtime/Library/ArrayBuffer.h

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,38 @@
99
namespace Js
1010
{
1111
class ArrayBufferParent;
12-
class ArrayBuffer : public DynamicObject
12+
class ArrayBuffer;
13+
class SharedArrayBuffer;
14+
class ArrayBufferBase : public DynamicObject
15+
{
16+
public:
17+
DEFINE_VTABLE_CTOR_ABSTRACT(ArrayBufferBase, DynamicObject);
18+
19+
virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) = 0;
20+
21+
ArrayBufferBase(DynamicType *type) : DynamicObject(type) { }
22+
23+
virtual bool IsArrayBuffer() = 0;
24+
virtual bool IsSharedArrayBuffer() = 0;
25+
virtual ArrayBuffer * GetAsArrayBuffer() = 0;
26+
virtual SharedArrayBuffer * GetAsSharedArrayBuffer() { return nullptr; }
27+
virtual void AddParent(ArrayBufferParent* parent) { }
28+
virtual void RemoveParent(ArrayBufferParent* parent) { }
29+
virtual bool IsDetached() { return false; }
30+
virtual uint32 GetByteLength() const = 0;
31+
virtual BYTE* GetBuffer() const = 0;
32+
virtual bool IsValidVirtualBufferLength(uint length) { return false; }
33+
34+
static bool Is(Var value);
35+
static ArrayBufferBase* FromVar(Var value);
36+
};
37+
38+
class ArrayBuffer : public ArrayBufferBase
1339
{
1440
public:
1541
// we need to install cross-site thunk on the nested array buffer when marshaling
1642
// typed array.
17-
DEFINE_VTABLE_CTOR_ABSTRACT(ArrayBuffer, DynamicObject);
18-
virtual void MarshalToScriptContext(Js::ScriptContext * scriptContext) = 0;
43+
DEFINE_VTABLE_CTOR_ABSTRACT(ArrayBuffer, ArrayBufferBase);
1944
#define MAX_ASMJS_ARRAYBUFFER_LENGTH 0x100000000 //4GB
2045
private:
2146
void ClearParentsLength(ArrayBufferParent* parent);
@@ -84,17 +109,17 @@ namespace Js
84109
virtual BOOL GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext) override;
85110

86111
virtual ArrayBufferDetachedStateBase* DetachAndGetState();
87-
bool IsDetached() { return this->isDetached; }
112+
virtual bool IsDetached() override { return this->isDetached; }
88113
void SetIsAsmJsBuffer(){ mIsAsmJsBuffer = true; }
89-
uint32 GetByteLength() const { return bufferLength; }
90-
BYTE* GetBuffer() const { return buffer; }
114+
virtual uint32 GetByteLength() const override { return bufferLength; }
115+
virtual BYTE* GetBuffer() const override { return buffer; }
91116

92117
static int GetByteLengthOffset() { return offsetof(ArrayBuffer, bufferLength); }
93118
static int GetIsDetachedOffset() { return offsetof(ArrayBuffer, isDetached); }
94119
static int GetBufferOffset() { return offsetof(ArrayBuffer, buffer); }
95120

96-
void AddParent(ArrayBufferParent* parent);
97-
void RemoveParent(ArrayBufferParent* parent);
121+
virtual void AddParent(ArrayBufferParent* parent) override;
122+
virtual void RemoveParent(ArrayBufferParent* parent) override;
98123
#if _WIN64
99124
//maximum 2G -1 for amd64
100125
static const uint32 MaxArrayBufferLength = 0x7FFFFFFF;
@@ -103,8 +128,12 @@ namespace Js
103128
static const uint32 MaxArrayBufferLength = 1 << 30;
104129
#endif
105130
virtual bool IsValidAsmJsBufferLength(uint length, bool forceCheck = false) { return false; }
106-
virtual bool IsValidVirtualBufferLength(uint length) { return false; }
131+
virtual bool IsArrayBuffer() override { return true; }
132+
virtual bool IsSharedArrayBuffer() override { return false; }
133+
virtual ArrayBuffer * GetAsArrayBuffer() override { return ArrayBuffer::FromVar(this); }
134+
107135
protected:
136+
108137
typedef void __cdecl FreeFn(void* ptr);
109138
virtual ArrayBufferDetachedStateBase* CreateDetachedState(BYTE* buffer, DECLSPEC_GUARD_OVERFLOW uint32 bufferLength) = 0;
110139
virtual ArrayBuffer * TransferInternal(DECLSPEC_GUARD_OVERFLOW uint32 newBufferLength) = 0;
@@ -130,14 +159,15 @@ namespace Js
130159
class ArrayBufferParent : public ArrayObject
131160
{
132161
friend ArrayBuffer;
162+
friend ArrayBufferBase;
133163

134164
private:
135-
ArrayBuffer* arrayBuffer;
165+
ArrayBufferBase* arrayBuffer;
136166

137167
protected:
138168
DEFINE_VTABLE_CTOR_ABSTRACT(ArrayBufferParent, ArrayObject);
139169

140-
ArrayBufferParent(DynamicType * type, uint32 length, ArrayBuffer* arrayBuffer)
170+
ArrayBufferParent(DynamicType * type, uint32 length, ArrayBufferBase* arrayBuffer)
141171
: ArrayObject(type, /*initSlots*/true, length),
142172
arrayBuffer(arrayBuffer)
143173
{
@@ -153,19 +183,8 @@ namespace Js
153183
}
154184
}
155185

156-
void SetArrayBuffer(ArrayBuffer* arrayBuffer)
157-
{
158-
this->ClearArrayBuffer();
159-
160-
if (arrayBuffer != nullptr)
161-
{
162-
this->arrayBuffer->AddParent(this);
163-
this->arrayBuffer = arrayBuffer;
164-
}
165-
}
166-
167186
public:
168-
ArrayBuffer* GetArrayBuffer() const
187+
ArrayBufferBase* GetArrayBuffer() const
169188
{
170189
return this->arrayBuffer;
171190
}

0 commit comments

Comments
 (0)