Implement Workers (#3645)

* copy files

* format

* options

* Introduce `Worker`, `onmessage`, `onerror`, and `postMessage` globals

* Stub `Worker.prototype.ref` & `Worker.prototype.unref`

* Update web_worker.zig

* Worker works

* Add "mini" mode

* add wakeup

* Partially fix the keep-alive issue

* clean up refer behavior

* Implement `serialize` & `deserialize` in `bun:jsc` & add polyfill for `node:v8`

* Types & docs

* Update globals.d.ts

* Add mutex

* Fixes

---------

Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2023-07-16 21:15:24 -07:00
committed by GitHub
parent 7fc392b182
commit 209dc981c0
46 changed files with 2796 additions and 75 deletions

View File

@@ -74,6 +74,7 @@
#include <JavaScriptCore/ExceptionHelpers.h>
#include <JavaScriptCore/IterationKind.h>
#include <JavaScriptCore/JSArrayBuffer.h>
#include <JavaScriptCore/ArrayBuffer.h>
#include <JavaScriptCore/JSArrayBufferView.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSDataView.h>
@@ -2527,7 +2528,7 @@ public:
Vector<std::unique_ptr<DetachedRTCDataChannel>>&& detachedRTCDataChannels
#endif
,
ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
ArrayBufferContentsArray* arrayBufferContentsArray, const Span<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
#if ENABLE(WEBASSEMBLY)
,
WasmModuleArray* wasmModules, WasmMemoryHandleArray* wasmMemoryHandles
@@ -2540,7 +2541,7 @@ public:
{
if (!buffer.size())
return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError);
CloneDeserializer deserializer(lexicalGlobalObject, globalObject, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths, sharedBuffers
CloneDeserializer deserializer(lexicalGlobalObject, globalObject, arrayBufferContentsArray, Span<uint8_t> { buffer.begin(), buffer.end() }, blobURLs, blobFilePaths, sharedBuffers
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
WTFMove(detachedOffscreenCanvases)
@@ -2660,7 +2661,7 @@ private:
// m_version = 0xFFFFFFFF;
// }
CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer
CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const Span<uint8_t>& buffer
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
Vector<std::unique_ptr<DetachedOffscreenCanvas>>&& detachedOffscreenCanvases = {}
@@ -2766,7 +2767,7 @@ private:
// m_version = 0xFFFFFFFF;
// }
CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
CloneDeserializer(JSGlobalObject* lexicalGlobalObject, JSGlobalObject* globalObject, ArrayBufferContentsArray* arrayBufferContents, const Span<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers
#if ENABLE(OFFSCREEN_CANVAS_IN_WORKERS)
,
Vector<std::unique_ptr<DetachedOffscreenCanvas>>&& detachedOffscreenCanvases
@@ -5282,6 +5283,73 @@ String SerializedScriptValue::toString() const
return CloneDeserializer::deserializeString(m_data);
}
Ref<JSC::ArrayBuffer> SerializedScriptValue::toArrayBuffer()
{
if (this->m_data.size() == 0) {
return ArrayBuffer::create(static_cast<size_t>(0), static_cast<unsigned>(1));
}
this->ref();
auto arrayBuffer = ArrayBuffer::createFromBytes(
this->m_data.data(), this->m_data.size(), createSharedTask<void(void*)>([protectedThis = Ref { *this }](void* p) {
protectedThis->deref();
}));
// Note: using the SharedArrayBufferContents::create function directly didn't work.
arrayBuffer->makeShared();
return arrayBuffer;
}
JSC::JSValue SerializedScriptValue::fromArrayBuffer(JSC::JSGlobalObject& domGlobal, JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* arrayBuffer, size_t byteOffset, size_t maxByteLength, SerializationErrorMode throwExceptions, bool* didFail)
{
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
if (!arrayBuffer || arrayBuffer->isDetached()) {
if (didFail)
*didFail = true;
if (throwExceptions == SerializationErrorMode::Throwing)
throwTypeError(globalObject, throwScope, "Cannot deserialize a detached ArrayBuffer"_s);
return JSC::jsUndefined();
}
auto blobURLs = Vector<String> {};
auto blobFiles = Vector<String> {};
if (arrayBuffer->isShared()) {
// prevent detaching while in-use
arrayBuffer->pin();
}
auto* data = static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset;
auto size = std::min(arrayBuffer->byteLength(), maxByteLength);
auto span = Span<uint8_t> { data, size };
auto result = CloneDeserializer::deserialize(&domGlobal, globalObject, nullptr, span, blobURLs, blobFiles, nullptr
#if ENABLE(WEBASSEMBLY)
,
nullptr, nullptr
#endif
#if ENABLE(WEB_CODECS)
,
WTFMove(m_serializedVideoChunks), WTFMove(m_serializedVideoFrames)
#endif
);
if (arrayBuffer->isShared()) {
arrayBuffer->unpin();
}
if (didFail) {
*didFail = result.second != SerializationReturnCode::SuccessfullyCompleted;
}
if (throwExceptions == SerializationErrorMode::Throwing)
maybeThrowExceptionIfSerializationFailed(*globalObject, result.second);
return result.first ? result.first : jsNull();
}
// JSValue SerializedScriptValue::deserialize(JSGlobalObject& lexicalGlobalObject, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions, bool* didFail)
// {
// return deserialize(lexicalGlobalObject, globalObject, {}, throwExceptions, didFail);
@@ -5396,7 +5464,8 @@ JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, J
return toRef(lexicalGlobalObject, value);
}
Ref<SerializedScriptValue> SerializedScriptValue::nullValue()
Ref<SerializedScriptValue>
SerializedScriptValue::nullValue()
{
return adoptRef(*new SerializedScriptValue(Vector<uint8_t>()));
}