Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions API/hermes/TracingRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ class TracingRuntime : public jsi::RuntimeDecorator<jsi::Runtime>
jsi::Value getPrototypeOf(const jsi::Object &object) override;

jsi::Array getPropertyNames(const jsi::Object &o) override;
// Uses the default implementation of jsi::Runtime, which calls the traced
// getPropertyNames and the other traced methods, so replay sees the same
// calls.
std::vector<jsi::PropNameID> getPropertyNameIDs(
const jsi::Object &o) override {
return jsi::Runtime::getPropertyNameIDs(o);
}

jsi::WeakObject createWeakObject(const jsi::Object &o) override;

Expand Down
45 changes: 45 additions & 0 deletions API/hermes/hermes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,8 @@ class HermesRuntimeImpl final : public HermesRuntime,
bool isHostObject(const jsi::Object &) const override;
bool isHostFunction(const jsi::Function &) const override;
jsi::Array getPropertyNames(const jsi::Object &) override;
std::vector<jsi::PropNameID> getPropertyNameIDs(
const jsi::Object &obj) override;

void setPrototypeOf(const jsi::Object &object, const jsi::Value &prototype)
override;
Expand Down Expand Up @@ -3118,6 +3120,49 @@ jsi::Array HermesRuntimeImpl::getPropertyNames(const jsi::Object &obj) {
return ret;
}

std::vector<jsi::PropNameID> HermesRuntimeImpl::getPropertyNameIDs(
const jsi::Object &obj) {
ExecutionScopeRAII scopeRAII(mutatorScope);
vm::GCScope gcScope(runtime_);
uint32_t beginIndex;
uint32_t endIndex;
vm::CallResult<vm::Handle<vm::ArrayStorageSmall>> cr =
vm::getForInPropertyNames(runtime_, handle(obj), beginIndex, endIndex);
checkStatus(cr.getStatus());
vm::Handle<vm::ArrayStorageSmall> names = *cr;

std::vector<jsi::PropNameID> result;
result.reserve(endIndex - beginIndex);
for (uint32_t i = beginIndex; i < endIndex; ++i) {
vm::GCScopeMarkerRAII marker{runtime_};
vm::SmallHermesValue name = names->at(i);
if (name.isSymbol()) {
// for-in keeps the names of ordinary objects as symbols, which are what
// a PropNameID holds.
result.push_back(add<jsi::PropNameID>(
vm::HermesValue::encodeSymbolValue(name.getSymbol())));
continue;
}
vm::StringPrimitive *str;
if (name.isString()) {
str = name.getString(runtime_);
} else if (name.isNumber()) {
// May allocate. 'name' must not be used afterwards.
auto strRes =
vm::numberToStringPrimitive(runtime_, name.getNumber(runtime_));
checkStatus(strRes.getStatus());
str = strRes->get();
} else {
llvm_unreachable("property name is not String, Symbol or Number");
}
auto symbolRes =
vm::stringToSymbolID(runtime_, vm::createPseudoHandle(str));
checkStatus(symbolRes.getStatus());
result.push_back(add<jsi::PropNameID>(symbolRes->getHermesValue()));
}
return result;
}

jsi::WeakObject HermesRuntimeImpl::createWeakObject(const jsi::Object &obj) {
ExecutionScopeRAII scopeRAII(mutatorScope);
return addWeak(
Expand Down
7 changes: 7 additions & 0 deletions API/jsi/jsi/decorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
Array getPropertyNames(const Object& o) override {
return plain_.getPropertyNames(o);
}
std::vector<PropNameID> getPropertyNameIDs(const Object& o) override {
return plain_.getPropertyNameIDs(o);
}

WeakObject createWeakObject(const Object& o) override {
return plain_.createWeakObject(o);
Expand Down Expand Up @@ -1043,6 +1046,10 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
Around around{with_};
return RD::getPropertyNames(o);
}
std::vector<PropNameID> getPropertyNameIDs(const Object& o) override {
Around around{with_};
return RD::getPropertyNameIDs(o);
}

WeakObject createWeakObject(const Object& o) override {
Around around{with_};
Expand Down
5 changes: 5 additions & 0 deletions API/jsi/jsi/jsi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ inline Array Object::getPropertyNames(IRuntime& runtime) const {
return runtime.getPropertyNames(*this);
}

inline std::vector<PropNameID> Object::getPropertyNameIDs(
IRuntime& runtime) const {
return runtime.getPropertyNameIDs(*this);
}

inline Value WeakObject::lock(IRuntime& runtime) const {
return runtime.lockWeakObject(*this);
}
Expand Down
12 changes: 12 additions & 0 deletions API/jsi/jsi/jsi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,18 @@ void Runtime::deleteProperty(const Object& object, const Value& name) {
}
}

std::vector<PropNameID> Runtime::getPropertyNameIDs(const Object& object) {
Array names = getPropertyNames(object);
size_t count = names.size(*this);
std::vector<PropNameID> result;
result.reserve(count);
for (size_t i = 0; i < count; ++i) {
result.push_back(PropNameID::forString(
*this, names.getValueAtIndex(*this, i).getString(*this)));
}
return result;
}

size_t Runtime::push(const Array& arr, const Value* elements, size_t count) {
size_t newSize = size(arr);
for (size_t i = 0; i < count; i++) {
Expand Down
9 changes: 9 additions & 0 deletions API/jsi/jsi/jsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ class JSI_EXPORT IRuntime : public ICast {
virtual bool isHostObject(const jsi::Object&) const = 0;
virtual bool isHostFunction(const jsi::Function&) const = 0;
virtual Array getPropertyNames(const Object&) = 0;
/// Returns the same names as getPropertyNames, in the same order, as
/// PropNameIDs and without creating a JS array.
virtual std::vector<PropNameID> getPropertyNameIDs(const Object& object) = 0;

virtual WeakObject createWeakObject(const Object&) = 0;
virtual Value lockWeakObject(const WeakObject&) = 0;
Expand Down Expand Up @@ -731,6 +734,7 @@ class JSI_EXPORT Runtime : public IRuntime {
void deleteProperty(const Object&, const PropNameID& name) override;
void deleteProperty(const Object&, const String& name) override;
void deleteProperty(const Object&, const Value& name) override;
std::vector<PropNameID> getPropertyNameIDs(const Object& object) override;

void setRuntimeDataImpl(
const UUID& uuid,
Expand Down Expand Up @@ -1419,6 +1423,11 @@ class JSI_EXPORT Object : public Pointer {
/// works. I only need it in one place.)
Array getPropertyNames(IRuntime& runtime) const;

/// \return the names of all enumerable properties in the object and its
/// prototype chain, as getPropertyNames does, but as PropNameIDs, which can
/// be used to get the property values without converting the names again.
std::vector<PropNameID> getPropertyNameIDs(IRuntime& runtime) const;

/// Inform the runtime that there is additional memory associated with a given
/// JavaScript object that is not visible to the GC. This can be used if an
/// object is known to retain some native memory, and may be used to guide
Expand Down
41 changes: 41 additions & 0 deletions API/jsi/jsi/test/testlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,47 @@ TEST_P(JSITest, GetStringDataTest) {
EXPECT_EQ(buf, str.utf16(rd));
}

TEST_P(JSITest, GetPropertyNameIDsTest) {
// This Runtime Decorator is used to test the default getPropertyNameIDs
// implementation for VMs that do not provide their own implementation
class RD : public RuntimeDecorator<Runtime, Runtime> {
public:
explicit RD(Runtime& rt) : RuntimeDecorator(rt) {}

std::vector<PropNameID> getPropertyNameIDs(const Object& object) override {
return Runtime::getPropertyNameIDs(object);
}
};
RD rd(rt);

for (const char* source :
{"({title: 1, 7: 2, '\\u00e9t\\u00e9': 3, [Symbol('s')]: 4, x: null})",
"[10, 20, 30]",
"(function() {"
" var o = Object.create({inherited: 1});"
" o.own = 2;"
" Object.defineProperty(o, 'getter', {"
" get: function() { return 3; }, enumerable: true});"
" Object.defineProperty(o, 'hidden', {value: 4, enumerable: false});"
" return o;"
"})()",
"({})"}) {
Object obj = eval(source).getObject(rt);
Array names = obj.getPropertyNames(rt);
for (Runtime* runtime : {static_cast<Runtime*>(&rt), static_cast<Runtime*>(&rd)}) {
std::vector<PropNameID> ids = obj.getPropertyNameIDs(*runtime);
ASSERT_EQ(ids.size(), names.size(rt)) << source;
for (size_t i = 0; i < ids.size(); ++i) {
String name = names.getValueAtIndex(rt, i).getString(rt);
EXPECT_EQ(ids[i].utf8(rt), name.utf8(rt)) << source;
EXPECT_TRUE(Value::strictEquals(
rt, obj.getProperty(rt, ids[i]), obj.getProperty(rt, name)))
<< source;
}
}
}
}

TEST_P(JSITest, ObjectSetPrototype) {
// This Runtime Decorator is used to test the default implementation of
// Object.setPrototypeOf
Expand Down