Skip to content

Commit

Permalink
Use new V8 v2 write APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
danlapid committed Feb 5, 2025
1 parent b27f087 commit 8e6d7e5
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 42 deletions.
5 changes: 2 additions & 3 deletions src/workerd/api/node/buffer.c++
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,8 @@ uint32_t writeInto(jsg::Lock& js,
return 0;
}

static constexpr jsg::JsString::WriteOptions flags =
static_cast<jsg::JsString::WriteOptions>(jsg::JsString::MANY_WRITES_EXPECTED |
jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8);
static constexpr jsg::JsString::WriteOptions flags = static_cast<jsg::JsString::WriteOptions>(
jsg::JsString::NO_NULL_TERMINATION | jsg::JsString::REPLACE_INVALID_UTF8);

switch (encoding) {
case Encoding::ASCII:
Expand Down
6 changes: 2 additions & 4 deletions src/workerd/api/streams/encoding.c++
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ jsg::Ref<TextEncoderStream> TextEncoderStream::constructor(jsg::Lock& js) {
auto buffer = maybeBuffer.ToLocalChecked();

auto bytes = jsg::asBytes(buffer).releaseAsChars();
[[maybe_unused]] int read = 0;
[[maybe_unused]] auto written = str->WriteUtf8(js.v8Isolate, bytes.begin(), bytes.size(), &read,
v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8);
[[maybe_unused]] auto written = str->WriteUtf8V2(
js.v8Isolate, bytes.begin(), bytes.size(), v8::String::WriteFlags::kReplaceInvalidUtf8);

KJ_DASSERT(written == buffer->ByteLength());
KJ_DASSERT(read == str->Length());
controller->enqueue(js, v8::Uint8Array::New(buffer, 0, buffer->ByteLength()));
return js.resolvedPromise();
})},
Expand Down
30 changes: 18 additions & 12 deletions src/workerd/jsg/jsg.c++
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,11 @@ JsSymbol Lock::symbolAsyncDispose() {
return IsolateBase::from(v8Isolate).getSymbolAsyncDispose();
}

void ExternalMemoryAdjustment::maybeDeferAdjustment(v8::Isolate* isolate, size_t amount) {
void ExternalMemoryAdjustment::maybeDeferAdjustment(
v8::ExternalMemoryAccounter& externalMemoryAccounter, v8::Isolate* isolate, size_t amount) {
if (isolate == nullptr) return;
if (v8::Locker::IsLocked(isolate)) {
isolate->AdjustAmountOfExternalAllocatedMemory(static_cast<int64_t>(-amount));
externalMemoryAccounter.Decrease(isolate, amount);
} else {
// Otherwise, if we don't have the isolate locked, defer the adjustment to the next
// time that we do.
Expand All @@ -301,16 +302,19 @@ void ExternalMemoryAdjustment::maybeDeferAdjustment(v8::Isolate* isolate, size_t
}
}

ExternalMemoryAdjustment::ExternalMemoryAdjustment(v8::Isolate* isolate, size_t amount)
: amount(amount),
isolate(isolate) {
ExternalMemoryAdjustment::ExternalMemoryAdjustment(
v8::ExternalMemoryAccounter& externalMemoryAccounter, v8::Isolate* isolate, size_t amount)
: externalMemoryAccounter(externalMemoryAccounter),
isolate(isolate),
amount(amount) {
KJ_DASSERT(isolate != nullptr);
isolate->AdjustAmountOfExternalAllocatedMemory(amount);
externalMemoryAccounter.Increase(isolate, amount);
}

ExternalMemoryAdjustment::ExternalMemoryAdjustment(ExternalMemoryAdjustment&& other)
: amount(other.amount),
isolate(other.isolate) {
: externalMemoryAccounter(other.externalMemoryAccounter),
isolate(other.isolate),
amount(other.amount) {
other.amount = 0;
other.isolate = nullptr;
}
Expand All @@ -319,7 +323,8 @@ ExternalMemoryAdjustment& ExternalMemoryAdjustment::operator=(ExternalMemoryAdju
// If we currently have an amount, adjust it back to zero.
// In the case we don't have the isolate lock here, the adjustment
// will be deferred until the next time we do.
if (amount > 0) maybeDeferAdjustment(isolate, amount);
if (amount > 0) maybeDeferAdjustment(externalMemoryAccounter, isolate, amount);
externalMemoryAccounter = kj::mv(other.externalMemoryAccounter);
amount = other.amount;
isolate = other.isolate;
other.amount = 0;
Expand All @@ -329,22 +334,23 @@ ExternalMemoryAdjustment& ExternalMemoryAdjustment::operator=(ExternalMemoryAdju

ExternalMemoryAdjustment::~ExternalMemoryAdjustment() noexcept(false) {
if (amount != 0) {
maybeDeferAdjustment(isolate, amount);
maybeDeferAdjustment(externalMemoryAccounter, isolate, amount);
}
}

void ExternalMemoryAdjustment::adjust(Lock& js, ssize_t amount) {
amount = kj::max(amount, -static_cast<ssize_t>(this->amount));
this->amount += amount;
isolate->AdjustAmountOfExternalAllocatedMemory(amount);
externalMemoryAccounter.Update(isolate, amount);
}

void ExternalMemoryAdjustment::set(Lock& js, size_t amount) {
adjust(js, amount - this->amount);
}

ExternalMemoryAdjustment Lock::getExternalMemoryAdjustment(int64_t amount) {
return ExternalMemoryAdjustment(v8Isolate, amount);
return ExternalMemoryAdjustment(
IsolateBase::from(v8Isolate).getExternalMemoryAccounter(), v8Isolate, amount);
}

Name::Name(kj::String string): hash(kj::hashCode(string)), inner(kj::mv(string)) {}
Expand Down
11 changes: 7 additions & 4 deletions src/workerd/jsg/jsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <workerd/jsg/exception.h>
#include <workerd/jsg/memory.h>

#include <v8-external-memory-accounter.h>
#include <v8-profiler.h>
#include <v8.h>

Expand Down Expand Up @@ -2220,8 +2221,8 @@ class DOMException;
// The allocation amount can be adjusted up or down during the lifetime of an object.
class ExternalMemoryAdjustment final {
public:
ExternalMemoryAdjustment() = default;
ExternalMemoryAdjustment(v8::Isolate* isolate, size_t amount);
ExternalMemoryAdjustment(
v8::ExternalMemoryAccounter& externalMemoryAccounter, v8::Isolate* isolate, size_t amount);
ExternalMemoryAdjustment(ExternalMemoryAdjustment&& other);
ExternalMemoryAdjustment& operator=(ExternalMemoryAdjustment&& other);
KJ_DISALLOW_COPY(ExternalMemoryAdjustment);
Expand All @@ -2243,10 +2244,12 @@ class ExternalMemoryAdjustment final {
}

private:
size_t amount = 0;
v8::ExternalMemoryAccounter& externalMemoryAccounter;
v8::Isolate* isolate = nullptr;
size_t amount = 0;

static void maybeDeferAdjustment(v8::Isolate* isolate, size_t amount);
static void maybeDeferAdjustment(
v8::ExternalMemoryAccounter& externalMemoryAccounter, v8::Isolate* isolate, size_t amount);
};

// Represents an isolate lock, which allows the current thread to execute JavaScript code within
Expand Down
18 changes: 12 additions & 6 deletions src/workerd/jsg/jsvalue.c++
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ int JsString::length(jsg::Lock& js) const {
return inner->Length();
}

int JsString::utf8Length(jsg::Lock& js) const {
return inner->Utf8Length(js.v8Isolate);
size_t JsString::utf8Length(jsg::Lock& js) const {
return inner->Utf8LengthV2(js.v8Isolate);
}

kj::String JsString::toString(jsg::Lock& js) const {
Expand All @@ -286,8 +286,10 @@ JsString::WriteIntoStatus JsString::writeInto(
Lock& js, kj::ArrayPtr<char> buffer, WriteOptions options) const {
WriteIntoStatus result = {0, 0};
if (buffer.size() > 0) {
result.written =
inner->WriteUtf8(js.v8Isolate, buffer.begin(), buffer.size(), &result.read, options);
result.written = inner->WriteUtf8V2(js.v8Isolate, buffer.begin(), buffer.size(), options);
if (result.written > 0) {
result.read = length(js);
}
}
return result;
}
Expand All @@ -296,7 +298,9 @@ JsString::WriteIntoStatus JsString::writeInto(
Lock& js, kj::ArrayPtr<uint16_t> buffer, WriteOptions options) const {
WriteIntoStatus result = {0, 0};
if (buffer.size() > 0) {
result.written = inner->Write(js.v8Isolate, buffer.begin(), 0, buffer.size(), options);
inner->WriteV2(js.v8Isolate, 0, buffer.size(), buffer.begin(), options);
result.read = length(js);
result.written = length(js);
}
return result;
}
Expand All @@ -305,7 +309,9 @@ JsString::WriteIntoStatus JsString::writeInto(
Lock& js, kj::ArrayPtr<kj::byte> buffer, WriteOptions options) const {
WriteIntoStatus result = {0, 0};
if (buffer.size() > 0) {
result.written = inner->WriteOneByte(js.v8Isolate, buffer.begin(), 0, buffer.size(), options);
inner->WriteOneByteV2(js.v8Isolate, 0, buffer.size(), buffer.begin(), options);
result.read = length(js);
result.written = length(js);
}
return result;
}
Expand Down
14 changes: 6 additions & 8 deletions src/workerd/jsg/jsvalue.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class JsArray final: public JsBase<v8::Array, JsArray> {
class JsString final: public JsBase<v8::String, JsString> {
public:
int length(Lock& js) const KJ_WARN_UNUSED_RESULT;
int utf8Length(Lock& js) const KJ_WARN_UNUSED_RESULT;
size_t utf8Length(Lock& js) const KJ_WARN_UNUSED_RESULT;
kj::String toString(Lock& js) const KJ_WARN_UNUSED_RESULT;
int hashCode() const;

Expand All @@ -249,11 +249,9 @@ class JsString final: public JsBase<v8::String, JsString> {
static JsString concat(Lock& js, const JsString& one, const JsString& two) KJ_WARN_UNUSED_RESULT;

enum WriteOptions {
NONE = v8::String::NO_OPTIONS,
MANY_WRITES_EXPECTED = v8::String::HINT_MANY_WRITES_EXPECTED,
NO_NULL_TERMINATION = v8::String::NO_NULL_TERMINATION,
PRESERVE_ONE_BYTE_NULL = v8::String::PRESERVE_ONE_BYTE_NULL,
REPLACE_INVALID_UTF8 = v8::String::REPLACE_INVALID_UTF8,
NONE = v8::String::WriteFlags::kNullTerminate,
NO_NULL_TERMINATION = v8::String::WriteFlags::kNone,
REPLACE_INVALID_UTF8 = v8::String::WriteFlags::kReplaceInvalidUtf8,
};

template <typename T>
Expand Down Expand Up @@ -442,11 +440,11 @@ inline kj::Array<T> JsString::toArray(Lock& js, WriteOptions options) const {
if constexpr (kj::isSameType<T, kj::byte>()) {
KJ_ASSERT(inner->ContainsOnlyOneByte());
auto buf = kj::heapArray<kj::byte>(inner->Length());
inner->WriteOneByte(js.v8Isolate, buf.begin(), 0, buf.size(), options);
inner->WriteOneByteV2(js.v8Isolate, 0, buf.size(), buf.begin(), options);
return kj::mv(buf);
} else {
auto buf = kj::heapArray<uint16_t>(inner->Length());
inner->Write(js.v8Isolate, buf.begin(), 0, buf.size(), options);
inner->WriteV2(js.v8Isolate, 0, buf.size(), buf.begin(), options);
return kj::mv(buf);
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/workerd/jsg/setup.c++
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ void IsolateBase::deferExternalMemoryDecrement(int64_t size) {
void IsolateBase::clearPendingExternalMemoryDecrement() {
KJ_ASSERT(v8::Locker::IsLocked(ptr));
int64_t amount = pendingExternalMemoryDecrement.exchange(0, std::memory_order_relaxed);
if (amount > 0) ptr->AdjustAmountOfExternalAllocatedMemory(-amount);
if (amount > 0) {
externalMemoryAccounter.Decrease(ptr, amount);
}
}

void IsolateBase::terminateExecution() const {
Expand Down
7 changes: 7 additions & 0 deletions src/workerd/jsg/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ class IsolateBase {
return JsSymbol(symbolAsyncDispose.Get(ptr));
}

v8::ExternalMemoryAccounter& getExternalMemoryAccounter() {
return externalMemoryAccounter;
}

private:
template <typename TypeWrapper>
friend class Isolate;
Expand Down Expand Up @@ -264,6 +268,9 @@ class IsolateBase {
// Polyfilled Symbol.asyncDispose.
v8::Global<v8::Symbol> symbolAsyncDispose;

// Used to account for external memory
v8::ExternalMemoryAccounter externalMemoryAccounter;

// We expect queues to remain relatively small -- 8 is the largest size I have observed from local
// testing.
static constexpr auto DESTRUCTION_QUEUE_INITIAL_SIZE = 8;
Expand Down
7 changes: 3 additions & 4 deletions src/workerd/jsg/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,7 @@ class StringWrapper {
#else
auto buf = kj::heapArray<char>(str->Utf8Length(isolate) + 1);
#endif
str->WriteUtf8(isolate, buf.begin(), buf.size());
buf[buf.size() - 1] = 0;
str->WriteUtf8V2(isolate, buf.begin(), buf.size(), v8::String::WriteFlags::kNullTerminate);
return kj::String(kj::mv(buf));
}

Expand Down Expand Up @@ -1018,8 +1017,8 @@ class DictWrapper {
#else
auto buf = kj::heapArray<char>(v8String->Utf8Length(isolate) + 1);
#endif
v8String->WriteUtf8(isolate, buf.begin(), buf.size());
buf[buf.size() - 1] = 0;
v8String->WriteUtf8V2(
isolate, buf.begin(), buf.size(), v8::String::WriteFlags::kNullTerminate);
return kj::String(kj::mv(buf));
};

Expand Down

0 comments on commit 8e6d7e5

Please sign in to comment.