Skip to content

Commit 9858f3a

Browse files
authored
Merge pull request #64 from Distributive-Network/caleb/perf/pyproxyhandler
Perf: return underlying dict during re-entrance rather than wrapping it with a JSObjectProxy
2 parents 50b7569 + bf3dcf7 commit 9858f3a

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

include/PyProxyHandler.hh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323
struct PyBaseProxyHandler : public js::BaseProxyHandler {
2424
public:
25-
PyBaseProxyHandler(PyObject *pyObj) : js::BaseProxyHandler(NULL), pyObject(pyObj) {};
25+
PyBaseProxyHandler(PyObject *pyObj, const void *family) : js::BaseProxyHandler(family), pyObject(pyObj) {};
2626
PyObject *pyObject; // @TODO (Caleb Aikens) Consider putting this in a private slot
2727

2828
bool getPrototypeIfOrdinary(JSContext *cx, JS::HandleObject proxy, bool *isOrdinary, JS::MutableHandleObject protop) const override final;
@@ -36,7 +36,8 @@ public:
3636
*/
3737
struct PyProxyHandler : public PyBaseProxyHandler {
3838
public:
39-
PyProxyHandler(PyObject *pyObj) : PyBaseProxyHandler(pyObj) {};
39+
PyProxyHandler(PyObject *pyObj) : PyBaseProxyHandler(pyObj, &family) {};
40+
static const char family;
4041

4142
/**
4243
* @brief [[OwnPropertyKeys]]
@@ -163,7 +164,8 @@ public:
163164
*/
164165
struct PyListProxyHandler : public PyBaseProxyHandler {
165166
public:
166-
PyListProxyHandler(PyObject *pyObj) : PyBaseProxyHandler(pyObj) {};
167+
PyListProxyHandler(PyObject *pyObj) : PyBaseProxyHandler(pyObj, &family) {};
168+
static const char family;
167169

168170
bool getOwnPropertyDescriptor(
169171
JSContext *cx, JS::HandleObject proxy, JS::HandleId id,

src/PyProxyHandler.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ bool idToIndex(JSContext *cx, JS::HandleId id, Py_ssize_t *index) {
4545
}
4646
}
4747

48+
const char PyProxyHandler::family = 0;
49+
4850
bool PyProxyHandler::ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleIdVector props) const {
4951
PyObject *keys = PyDict_Keys(pyObject);
5052
size_t length = PyList_Size(keys);
@@ -153,6 +155,8 @@ bool PyBaseProxyHandler::isExtensible(JSContext *cx, JS::HandleObject proxy,
153155
return true;
154156
}
155157

158+
const char PyListProxyHandler::family = 0;
159+
156160
bool PyListProxyHandler::getOwnPropertyDescriptor(
157161
JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
158162
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc

src/pyTypeFactory.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "include/NoneType.hh"
2525
#include "include/NullType.hh"
2626
#include "include/PromiseType.hh"
27+
#include "include/PyProxyHandler.hh"
2728
#include "include/PyType.hh"
2829
#include "include/setSpiderMonkeyException.hh"
2930
#include "include/StrType.hh"
@@ -95,8 +96,12 @@ PyType *pyTypeFactory(JSContext *cx, JS::Rooted<JSObject *> *thisObj, JS::Rooted
9596
JS::Rooted<JSObject *> obj(cx);
9697
JS_ValueToObject(cx, *rval, &obj);
9798
if (JS::GetClass(obj)->isProxyObject()) {
98-
// @TODO (Caleb Aikens) need to determine if this is one of OUR ProxyObjects somehow
99-
// consider putting a special value in one of the private slots when creating a PyProxyHandler
99+
if (js::GetProxyHandler(obj)->family() == &PyProxyHandler::family) { // this is one of our proxies for python dicts
100+
return new DictType(((PyProxyHandler *)js::GetProxyHandler(obj))->pyObject);
101+
}
102+
if (js::GetProxyHandler(obj)->family() == &PyListProxyHandler::family) { // this is one of our proxies for python lists
103+
return new ListType(((PyListProxyHandler *)js::GetProxyHandler(obj))->pyObject);
104+
}
100105
}
101106
js::ESClass cls;
102107
JS::GetBuiltinClass(cx, obj, &cls);

tests/python/test_dicts_lists.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
import pythonmonkey as pm
22

3+
def test_eval_dicts():
4+
d = {"a":1}
5+
proxy_d = pm.eval("(dict) => { return dict; }")(d)
6+
assert d is proxy_d
7+
8+
def test_eval_dicts_subdicts():
9+
d = {"a":1, "b":{"c": 2}}
10+
11+
assert pm.eval("(dict) => { return dict.a; }")(d) == 1.0
12+
assert pm.eval("(dict) => { return dict.b; }")(d) is d["b"]
13+
assert pm.eval("(dict) => { return dict.b.c; }")(d) == 2.0
14+
15+
def test_eval_dicts_cycle():
16+
d: dict = {"a":1, "b":2}
17+
d["recursive"] = d
18+
19+
assert pm.eval("(dict) => { return dict.a; }")(d) == 1.0
20+
assert pm.eval("(dict) => { return dict.b; }")(d) == 2.0
21+
assert pm.eval("(dict) => { return dict.recursive; }")(d) is d["recursive"]
22+
323
def test_eval_objects():
424
pyObj = pm.eval("Object({a:1.0})")
525
assert pyObj == {'a':1.0}

0 commit comments

Comments
 (0)