Skip to content

Commit 4685815

Browse files
committed
SharedArrayBuffer - Initial work.
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
1 parent a4f9d82 commit 4685815

37 files changed

+3182
-809
lines changed

lib/Common/ConfigFlagsList.h

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

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

1015-
FLAGPR (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors" , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
1024+
FLAGPR (Boolean, ES6, ESObjectGetOwnPropertyDescriptors, "Enable Object.getOwnPropertyDescriptors" , DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors)
1025+
FLAGPRA (Boolean, ES6, ESSharedArrayBuffer , sab , "Enable SharedArrayBuffer" , DEFAULT_CONFIG_ESSharedArrayBuffer)
10161026

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

@@ -1473,5 +1483,6 @@ FLAGNR(Boolean, CFG, "Force enable CFG on jshost. version in the jshost's manife
14731483
#undef FLAGNR
14741484
#undef FLAGNRA
14751485
#undef FLAGPNR
1486+
#undef FLAGPRA
14761487

14771488
#endif

lib/Common/Core/ConfigFlagsTable.cpp

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

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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,10 @@ 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+
362+
RT_ERROR_MSG(JSERR_Function_LessArguments, 5662, "Function '%s' is called with less arguments", "Function called with less arguments", kjstRangeError, 0)
363+
RT_ERROR_MSG(JSERR_NeedTypedArrayObject, 5663, "", "Atomics function called with invalid typed array object", kjstTypeError, 0)
364+
RT_ERROR_MSG(JSERR_InvalidTypedArrayIndex, 5664, "", "access index is out of range", kjstRangeError, 0)
365+
RT_ERROR_MSG(JSERR_InvalidOperationOnTypedArray, 5665, "", "The operation is not supported on this typed array type", kjstRangeError, 0)
366+
RT_ERROR_MSG(JSERR_CannotSuspendBuffer, 5666, "", "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((Var)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)