Skip to content

Commit 16f42c8

Browse files
committed
Allow to execute some code before cloning.
1 parent 11c36e9 commit 16f42c8

File tree

8 files changed

+310
-15
lines changed

8 files changed

+310
-15
lines changed

src/njs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ typedef enum {
139139
NJS_ENUM_STRING = 8,
140140
NJS_ENUM_SYMBOL = 16,
141141
NJS_ENUM_ENUMERABLE_ONLY = 32,
142+
NJS_ENUM_NON_SHARED_ONLY = 64,
142143
} njs_object_enum_t;
143144

144145

@@ -302,6 +303,7 @@ NJS_EXPORT njs_mod_t *njs_vm_add_module(njs_vm_t *vm, njs_str_t *name,
302303
njs_value_t *value);
303304
NJS_EXPORT njs_mod_t *njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name,
304305
u_char **start, u_char *end);
306+
NJS_EXPORT njs_int_t njs_vm_reuse(njs_vm_t *vm);
305307
NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external);
306308

307309
NJS_EXPORT njs_int_t njs_vm_enqueue_job(njs_vm_t *vm, njs_function_t *function,

src/njs_builtin.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,8 @@ njs_top_level_object(njs_vm_t *vm, njs_object_prop_t *self,
873873
if (njs_slow_path(object == NULL)) {
874874
return NJS_ERROR;
875875
}
876+
877+
object->__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT);
876878
}
877879

878880
prop = njs_object_prop_alloc(vm, &self->name, retval, 1);
@@ -920,6 +922,8 @@ njs_top_level_constructor(njs_vm_t *vm, njs_object_prop_t *self,
920922
ctor = &njs_vm_ctor(vm, njs_prop_magic16(self));
921923

922924
njs_set_function(retval, ctor);
925+
926+
return NJS_OK;
923927
}
924928

925929
prop = njs_object_prop_alloc(vm, &self->name, retval, 1);

src/njs_object.c

Lines changed: 217 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,45 @@ njs_object_t *
6565
njs_object_value_copy(njs_vm_t *vm, njs_value_t *value)
6666
{
6767
size_t size;
68-
njs_object_t *object;
68+
njs_object_t *object, *proto;
6969

7070
object = njs_object(value);
7171

7272
if (!object->shared) {
7373
return object;
7474
}
7575

76-
size = njs_is_object_value(value) ? sizeof(njs_object_value_t)
77-
: sizeof(njs_object_t);
76+
switch (object->type) {
77+
case NJS_OBJECT:
78+
size = sizeof(njs_object_t);
79+
proto = (object->__proto__ != NULL)
80+
? njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT)
81+
: NULL;
82+
break;
83+
case NJS_ARRAY:
84+
size = sizeof(njs_array_t);
85+
njs_assert_msg(!object->fast_array,
86+
"shared fast_array is not supported");
87+
proto = (object->__proto__ != NULL)
88+
? njs_vm_proto(vm, NJS_OBJ_TYPE_ARRAY)
89+
: NULL;
90+
break;
91+
case NJS_OBJECT_VALUE:
92+
size = sizeof(njs_object_value_t);
93+
proto = (object->__proto__ != NULL)
94+
? njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT)
95+
: NULL;
96+
break;
97+
default:
98+
njs_internal_error(vm, "unexpected object type to copy");
99+
return NULL;
100+
}
101+
78102
object = njs_mp_alloc(vm->mem_pool, size);
79103

80104
if (njs_fast_path(object != NULL)) {
81105
memcpy(object, njs_object(value), size);
82-
object->__proto__ = njs_vm_proto(vm, NJS_OBJ_TYPE_OBJECT);
106+
object->__proto__ = proto;
83107
object->shared = 0;
84108
value->data.u.object = object;
85109
return object;
@@ -917,6 +941,10 @@ njs_get_own_ordered_keys(njs_vm_t *vm, const njs_object_t *object,
917941
njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
918942
hash = &object->shared_hash;
919943

944+
if (flags & NJS_ENUM_NON_SHARED_ONLY) {
945+
goto local_hash;
946+
}
947+
920948
for ( ;; ) {
921949
prop = njs_lvlhsh_each(hash, &lhe);
922950

@@ -984,6 +1012,8 @@ njs_get_own_ordered_keys(njs_vm_t *vm, const njs_object_t *object,
9841012
}
9851013
}
9861014

1015+
local_hash:
1016+
9871017
njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
9881018
hash = &object->hash;
9891019

@@ -1187,6 +1217,189 @@ njs_traverse_visited(njs_arr_t *list, const njs_value_t *value)
11871217
}
11881218

11891219

1220+
static njs_int_t
1221+
njs_object_copy_shared_hash(njs_vm_t *vm, njs_object_t *object)
1222+
{
1223+
njs_int_t ret;
1224+
njs_flathsh_t new_hash, *shared_hash;
1225+
njs_object_prop_t *prop;
1226+
njs_flathsh_each_t fhe;
1227+
njs_flathsh_query_t fhq;
1228+
1229+
fhq.replace = 0;
1230+
fhq.proto = &njs_object_hash_proto;
1231+
fhq.pool = vm->mem_pool;
1232+
1233+
njs_flathsh_init(&new_hash);
1234+
shared_hash = &object->shared_hash;
1235+
1236+
njs_flathsh_each_init(&fhe, &njs_object_hash_proto);
1237+
1238+
for ( ;; ) {
1239+
prop = njs_flathsh_each(shared_hash, &fhe);
1240+
1241+
if (prop == NULL) {
1242+
break;
1243+
}
1244+
1245+
if (njs_is_symbol(&prop->name)) {
1246+
fhq.key_hash = njs_symbol_key(&prop->name);
1247+
fhq.key.start = NULL;
1248+
1249+
} else {
1250+
njs_string_get(&prop->name, &fhq.key);
1251+
fhq.key_hash = njs_djb_hash(fhq.key.start, fhq.key.length);
1252+
}
1253+
1254+
fhq.value = prop;
1255+
1256+
ret = njs_flathsh_insert(&new_hash, &fhq);
1257+
if (njs_slow_path(ret != NJS_OK)) {
1258+
njs_internal_error(vm, "flathsh insert failed");
1259+
return NJS_ERROR;
1260+
}
1261+
}
1262+
1263+
object->shared_hash = new_hash;
1264+
1265+
return NJS_OK;
1266+
}
1267+
1268+
1269+
njs_int_t
1270+
njs_object_make_shared(njs_vm_t *vm, njs_object_t *object)
1271+
{
1272+
njs_int_t ret;
1273+
njs_arr_t visited;
1274+
njs_object_t **start;
1275+
njs_value_t value, *key;
1276+
njs_traverse_t *s;
1277+
njs_object_prop_t *prop;
1278+
njs_property_query_t pq;
1279+
njs_traverse_t state[NJS_TRAVERSE_MAX_DEPTH];
1280+
1281+
s = &state[0];
1282+
s->parent = NULL;
1283+
s->index = 0;
1284+
njs_set_object(&s->value, object);
1285+
1286+
s->keys = njs_value_own_enumerate(vm, &s->value, NJS_ENUM_KEYS
1287+
| NJS_ENUM_STRING
1288+
| NJS_ENUM_NON_SHARED_ONLY);
1289+
if (njs_slow_path(s->keys == NULL)) {
1290+
return NJS_ERROR;
1291+
}
1292+
1293+
if (s->keys->length != 0
1294+
&& !njs_flathsh_is_empty(&object->shared_hash))
1295+
{
1296+
/*
1297+
* object->shared_hash can be shared with other objects
1298+
* and we do not want to modify other objects.
1299+
*/
1300+
1301+
ret = njs_object_copy_shared_hash(vm, object);
1302+
if (njs_slow_path(ret != NJS_OK)) {
1303+
return NJS_ERROR;
1304+
}
1305+
}
1306+
1307+
start = njs_arr_init(vm->mem_pool, &visited, NULL, 8, sizeof(void *));
1308+
if (njs_slow_path(start == NULL)) {
1309+
return NJS_ERROR;
1310+
}
1311+
1312+
(void) njs_traverse_visit(&visited, &s->value);
1313+
1314+
pq.lhq.replace = 0;
1315+
pq.lhq.pool = vm->mem_pool;
1316+
1317+
for ( ;; ) {
1318+
1319+
if (s->index >= s->keys->length) {
1320+
njs_flathsh_init(&njs_object(&s->value)->hash);
1321+
njs_object(&s->value)->shared = 1;
1322+
njs_array_destroy(vm, s->keys);
1323+
s->keys = NULL;
1324+
1325+
if (s == &state[0]) {
1326+
goto done;
1327+
}
1328+
1329+
s--;
1330+
continue;
1331+
}
1332+
1333+
1334+
njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0, 0);
1335+
key = &s->keys->start[s->index++];
1336+
1337+
ret = njs_property_query(vm, &pq, &s->value, key);
1338+
if (njs_slow_path(ret != NJS_OK)) {
1339+
if (ret == NJS_DECLINED) {
1340+
continue;
1341+
}
1342+
1343+
return NJS_ERROR;
1344+
}
1345+
1346+
1347+
prop = pq.lhq.value;
1348+
1349+
ret = njs_flathsh_insert(&njs_object(&s->value)->shared_hash, &pq.lhq);
1350+
if (njs_slow_path(ret != NJS_OK)) {
1351+
njs_internal_error(vm, "flathsh insert failed");
1352+
return NJS_ERROR;
1353+
}
1354+
1355+
njs_value_assign(&value, njs_prop_value(prop));
1356+
1357+
if (njs_is_object(&value)
1358+
&& !njs_object(&value)->shared
1359+
&& !njs_traverse_visited(&visited, &value))
1360+
{
1361+
ret = njs_traverse_visit(&visited, &value);
1362+
if (njs_slow_path(ret != NJS_OK)) {
1363+
return NJS_ERROR;
1364+
}
1365+
1366+
if (s == &state[NJS_TRAVERSE_MAX_DEPTH - 1]) {
1367+
njs_type_error(vm, "njs_object_traverse() recursion limit:%d",
1368+
NJS_TRAVERSE_MAX_DEPTH);
1369+
return NJS_ERROR;
1370+
}
1371+
1372+
s++;
1373+
s->prop = NULL;
1374+
s->parent = &s[-1];
1375+
s->index = 0;
1376+
njs_value_assign(&s->value, &value);
1377+
s->keys = njs_value_own_enumerate(vm, &s->value, NJS_ENUM_KEYS
1378+
| NJS_ENUM_STRING
1379+
| NJS_ENUM_NON_SHARED_ONLY);
1380+
if (njs_slow_path(s->keys == NULL)) {
1381+
return NJS_ERROR;
1382+
}
1383+
1384+
if (s->keys->length != 0
1385+
&& !njs_flathsh_is_empty(&njs_object(&s->value)->shared_hash))
1386+
{
1387+
ret = njs_object_copy_shared_hash(vm, njs_object(&s->value));
1388+
if (njs_slow_path(ret != NJS_OK)) {
1389+
return NJS_ERROR;
1390+
}
1391+
}
1392+
}
1393+
}
1394+
1395+
done:
1396+
1397+
njs_arr_destroy(&visited);
1398+
1399+
return NJS_OK;
1400+
}
1401+
1402+
11901403
njs_int_t
11911404
njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
11921405
njs_object_traverse_cb_t cb)

src/njs_object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
7272
uint32_t flags);
7373
njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
7474
njs_object_traverse_cb_t cb);
75+
njs_int_t njs_object_make_shared(njs_vm_t *vm, njs_object_t *object);
7576
njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
7677
const njs_object_prop_t *prop, njs_uint_t n);
7778
njs_int_t njs_primitive_prototype_get_proto(njs_vm_t *vm,

src/njs_object_prop.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq,
694694

695695
switch (value->type) {
696696
case NJS_OBJECT:
697+
case NJS_ARRAY:
697698
case NJS_OBJECT_VALUE:
698699
object = njs_object_value_copy(vm, value);
699700
if (njs_slow_path(object == NULL)) {

src/njs_vm.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,17 @@ njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
378378
}
379379

380380

381+
njs_int_t
382+
njs_vm_reuse(njs_vm_t *vm)
383+
{
384+
vm->active_frame = NULL;
385+
vm->top_frame = NULL;
386+
vm->modules = NULL;
387+
388+
return njs_object_make_shared(vm, njs_object(&vm->global_value));
389+
}
390+
391+
381392
njs_vm_t *
382393
njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external)
383394
{
@@ -464,17 +475,19 @@ njs_vm_runtime_init(njs_vm_t *vm)
464475
njs_int_t ret;
465476
njs_frame_t *frame;
466477

467-
frame = (njs_frame_t *) njs_function_frame_alloc(vm, NJS_FRAME_SIZE);
468-
if (njs_slow_path(frame == NULL)) {
469-
njs_memory_error(vm);
470-
return NJS_ERROR;
471-
}
478+
if (vm->active_frame == NULL) {
479+
frame = (njs_frame_t *) njs_function_frame_alloc(vm, NJS_FRAME_SIZE);
480+
if (njs_slow_path(frame == NULL)) {
481+
njs_memory_error(vm);
482+
return NJS_ERROR;
483+
}
472484

473-
frame->exception.catch = NULL;
474-
frame->exception.next = NULL;
475-
frame->previous_active_frame = NULL;
485+
frame->exception.catch = NULL;
486+
frame->exception.next = NULL;
487+
frame->previous_active_frame = NULL;
476488

477-
vm->active_frame = frame;
489+
vm->active_frame = frame;
490+
}
478491

479492
ret = njs_regexp_init(vm);
480493
if (njs_slow_path(ret != NJS_OK)) {

src/njs_vmcode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,6 +2600,8 @@ njs_vmcode_import(njs_vm_t *vm, njs_mod_t *module, njs_value_t *retval)
26002600
njs_memzero(m->start, m->items * sizeof(njs_value_t));
26012601
}
26022602

2603+
njs_assert(module->index < vm->modules->items);
2604+
26032605
value = njs_arr_item(vm->modules, module->index);
26042606

26052607
if (!njs_is_null(value)) {

0 commit comments

Comments
 (0)