Skip to content

Commit 89e0df1

Browse files
tsaichienmeta-codesync[bot]
authored andcommitted
Add ArrayBuffer::detached method (#55944)
Summary: Pull Request resolved: #55944 Add a `ArrayBuffer::detached` method that returns true if the ArrayBuffer is detached, false otherwise. Default implementation just checks for the `detached` property Changelog: [Internal] Reviewed By: lavenzg Differential Revision: D92993088 fbshipit-source-id: 77d7055ddc35c21e915915daa2415b44017f81bb
1 parent 79843fc commit 89e0df1

4 files changed

Lines changed: 64 additions & 0 deletions

File tree

packages/react-native/ReactCommon/jsi/jsi/decorator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
392392
uint8_t* data(const ArrayBuffer& ab) override {
393393
return plain_.data(ab);
394394
}
395+
bool detached(const ArrayBuffer& ab) override {
396+
return plain_.detached(ab);
397+
}
395398
Value getValueAtIndex(const Array& a, size_t i) override {
396399
return plain_.getValueAtIndex(a, i);
397400
}
@@ -969,6 +972,10 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
969972
Around around{with_};
970973
return RD::data(ab);
971974
}
975+
bool detached(const ArrayBuffer& ab) override {
976+
Around around{with_};
977+
return RD::detached(ab);
978+
}
972979
Value getValueAtIndex(const Array& a, size_t i) override {
973980
Around around{with_};
974981
return RD::getValueAtIndex(a, i);

packages/react-native/ReactCommon/jsi/jsi/jsi.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,15 @@ std::shared_ptr<MutableBuffer> Runtime::tryGetMutableBuffer(
557557
return nullptr;
558558
}
559559

560+
bool Runtime::detached(const ArrayBuffer& buffer) {
561+
Value prop = buffer.getProperty(*this, "detached");
562+
if (!prop.isBool()) {
563+
throw JSINativeException(
564+
"ArrayBuffer.detached is not supported by this runtime");
565+
}
566+
return prop.getBool();
567+
}
568+
560569
Pointer& Pointer::operator=(Pointer&& other) noexcept {
561570
if (ptr_) {
562571
ptr_->invalidate();

packages/react-native/ReactCommon/jsi/jsi/jsi.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ class JSI_EXPORT IRuntime : public ICast {
563563
virtual size_t size(const Array&) = 0;
564564
virtual size_t size(const ArrayBuffer&) = 0;
565565
virtual uint8_t* data(const ArrayBuffer&) = 0;
566+
virtual bool detached(const ArrayBuffer&) = 0;
566567
virtual Value getValueAtIndex(const Array&, size_t i) = 0;
567568
virtual void
568569
setValueAtIndexImpl(const Array&, size_t i, const Value& value) = 0;
@@ -724,6 +725,8 @@ class JSI_EXPORT Runtime : public IRuntime {
724725
std::shared_ptr<MutableBuffer> tryGetMutableBuffer(
725726
const jsi::ArrayBuffer& arrayBuffer) override;
726727

728+
bool detached(const ArrayBuffer&) override;
729+
727730
protected:
728731
friend class Pointer;
729732
friend class PropNameID;
@@ -1471,6 +1474,11 @@ class JSI_EXPORT ArrayBuffer : public Object {
14711474
return runtime.tryGetMutableBuffer(*this);
14721475
}
14731476

1477+
/// \return true if the ArrayBuffer is detached, false otherwise.
1478+
bool detached(IRuntime& runtime) const {
1479+
return runtime.detached(*this);
1480+
}
1481+
14741482
private:
14751483
friend class Object;
14761484
friend class Value;

packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,46 @@ TEST_P(JSITest, ArrayPush) {
21212121
EXPECT_TRUE(arr.getValueAtIndex(rd, 3).isUndefined());
21222122
}
21232123

2124+
TEST_P(JSITest, ArrayBufferDetachedTest) {
2125+
// This Runtime Decorator is used to test the default implementation of
2126+
// Runtime::detached
2127+
class RD : public RuntimeDecorator<Runtime, Runtime> {
2128+
public:
2129+
explicit RD(Runtime& rt) : RuntimeDecorator(rt) {}
2130+
2131+
bool detached(const ArrayBuffer& ab) override {
2132+
return Runtime::detached(ab);
2133+
}
2134+
};
2135+
RD rd = RD(rt);
2136+
2137+
// Test that a normal ArrayBuffer is not detached.
2138+
auto ab = eval("var buf = new ArrayBuffer(10); buf")
2139+
.getObject(rd)
2140+
.getArrayBuffer(rd);
2141+
2142+
// The default Runtime::detached reads the JS "detached" property. If the
2143+
// runtime doesn't support ArrayBuffer.prototype.detached, it will throw
2144+
// JSINativeException.
2145+
try {
2146+
EXPECT_FALSE(ab.detached(rd));
2147+
} catch (const JSINativeException&) {
2148+
// Runtime doesn't support ArrayBuffer.prototype.detached, skip the rest.
2149+
return;
2150+
}
2151+
2152+
// Detach the ArrayBuffer. Use transfer() if available, otherwise fall back
2153+
// to HermesInternal.detach for Hermes runtime.
2154+
eval(
2155+
"if (typeof buf.transfer === 'function') {"
2156+
" buf.transfer();"
2157+
"} else if (typeof HermesInternal !== 'undefined' && "
2158+
" typeof HermesInternal.detachArrayBuffer === 'function') {"
2159+
" HermesInternal.detachArrayBuffer(buf);"
2160+
"}");
2161+
EXPECT_TRUE(ab.detached(rd));
2162+
}
2163+
21242164
INSTANTIATE_TEST_CASE_P(
21252165
Runtimes,
21262166
JSITest,

0 commit comments

Comments
 (0)