[njs] Moving top-level objects to global object.
Dmitry Volyntsev
xeioex at nginx.com
Thu Oct 31 15:18:02 UTC 2019
details: https://hg.nginx.org/njs/rev/ba6f17a75b3a
branches:
changeset: 1210:ba6f17a75b3a
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Thu Oct 31 18:17:31 2019 +0300
description:
Moving top-level objects to global object.
diffstat:
src/njs_builtin.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++
src/njs_generator.c | 34 -----------------
src/njs_lexer.h | 9 +----
src/njs_lexer_keyword.c | 9 +----
src/njs_object_hash.h | 34 +++++++++++++++++
src/njs_parser_terminal.c | 50 --------------------------
src/njs_value.h | 15 ++++++-
src/test/njs_unit_test.c | 37 +++++++++++++++++++
test/njs_expect_test.exp | 4 +-
9 files changed, 178 insertions(+), 104 deletions(-)
diffs (448 lines):
diff -r 796870eab669 -r ba6f17a75b3a src/njs_builtin.c
--- a/src/njs_builtin.c Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_builtin.c Thu Oct 31 18:17:31 2019 +0300
@@ -1042,8 +1042,58 @@ njs_dump_value(njs_vm_t *vm, njs_value_t
}
+static njs_int_t
+njs_top_level_object(njs_vm_t *vm, njs_object_prop_t *self,
+ njs_value_t *global, njs_value_t *setval, njs_value_t *retval)
+{
+ njs_int_t ret;
+ njs_object_t *object;
+ njs_object_prop_t *prop;
+ njs_lvlhsh_query_t lhq;
+
+ if (njs_slow_path(setval != NULL)) {
+ *retval = *setval;
+
+ } else {
+ njs_set_object(retval, &vm->shared->objects[self->value.data.magic16]);
+
+ object = njs_object_value_copy(vm, retval);
+ if (njs_slow_path(object == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ prop = njs_object_prop_alloc(vm, &self->name, retval, 1);
+ if (njs_slow_path(prop == NULL)) {
+ return NJS_ERROR;
+ }
+
+ /* GC */
+
+ prop->value = *retval;
+ prop->enumerable = 0;
+
+ lhq.value = prop;
+ njs_string_get(&self->name, &lhq.key);
+ lhq.key_hash = self->value.data.magic32;
+ lhq.replace = 1;
+ lhq.pool = vm->mem_pool;
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_internal_error(vm, "lvlhsh insert/replace failed");
+ return NJS_ERROR;
+ }
+
+ return NJS_OK;
+}
+
+
static const njs_object_prop_t njs_global_this_object_properties[] =
{
+ /* Global constants. */
+
{
.type = NJS_PROPERTY,
.name = njs_string("NaN"),
@@ -1062,6 +1112,8 @@ static const njs_object_prop_t njs_glob
.value = njs_value(NJS_UNDEFINED, 0, NAN),
},
+ /* Global functions. */
+
{
.type = NJS_PROPERTY,
.name = njs_string("isFinite"),
@@ -1174,6 +1226,44 @@ static const njs_object_prop_t njs_glob
.configurable = 1,
},
+ /* Global objects. */
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("njs"),
+ .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_NJS,
+ NJS_NJS_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("process"),
+ .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_PROCESS,
+ NJS_PROCESS_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Math"),
+ .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_MATH,
+ NJS_MATH_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("JSON"),
+ .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_JSON,
+ NJS_JSON_HASH),
+ .writable = 1,
+ .configurable = 1,
+ },
+
};
diff -r 796870eab669 -r ba6f17a75b3a src/njs_generator.c
--- a/src/njs_generator.c Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_generator.c Thu Oct 31 18:17:31 2019 +0300
@@ -59,8 +59,6 @@ static u_char *njs_generate_reserve(njs_
size_t size);
static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node);
-static njs_int_t njs_generate_builtin_object(njs_vm_t *vm,
- njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node, njs_reference_type_t type);
static njs_int_t njs_generate_var_statement(njs_vm_t *vm,
@@ -460,12 +458,6 @@ njs_generate(njs_vm_t *vm, njs_generator
return NJS_OK;
- case NJS_TOKEN_NJS:
- case NJS_TOKEN_PROCESS:
- case NJS_TOKEN_MATH:
- case NJS_TOKEN_JSON:
- return njs_generate_builtin_object(vm, generator, node);
-
case NJS_TOKEN_FUNCTION:
return njs_generate_function_declaration(vm, generator, node);
@@ -587,32 +579,6 @@ njs_generate_name(njs_vm_t *vm, njs_gene
static njs_int_t
-njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator,
- njs_parser_node_t *node)
-{
- njs_index_t index;
- njs_vmcode_object_copy_t *copy;
-
- index = njs_variable_index(vm, node);
- if (njs_slow_path(index == NJS_INDEX_NONE)) {
- return NJS_ERROR;
- }
-
- node->index = njs_generate_dest_index(vm, generator, node);
- if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
- return NJS_ERROR;
- }
-
- njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
- NJS_VMCODE_OBJECT_COPY, 2);
- copy->retval = node->index;
- copy->object = index;
-
- return NJS_OK;
-}
-
-
-static njs_int_t
njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node, njs_reference_type_t type)
{
diff -r 796870eab669 -r ba6f17a75b3a src/njs_lexer.h
--- a/src/njs_lexer.h Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_lexer.h Thu Oct 31 18:17:31 2019 +0300
@@ -166,18 +166,11 @@ typedef enum {
NJS_TOKEN_THROW,
NJS_TOKEN_THIS,
+ NJS_TOKEN_GLOBAL_OBJECT,
NJS_TOKEN_NON_LOCAL_THIS,
NJS_TOKEN_ARGUMENTS,
NJS_TOKEN_EVAL,
-#define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_OBJECT
-
- NJS_TOKEN_GLOBAL_OBJECT,
- NJS_TOKEN_NJS,
- NJS_TOKEN_PROCESS,
- NJS_TOKEN_MATH,
- NJS_TOKEN_JSON,
-
NJS_TOKEN_OBJECT_CONSTRUCTOR,
NJS_TOKEN_ARRAY_CONSTRUCTOR,
NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
diff -r 796870eab669 -r ba6f17a75b3a src/njs_lexer_keyword.c
--- a/src/njs_lexer_keyword.c Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_lexer_keyword.c Thu Oct 31 18:17:31 2019 +0300
@@ -47,14 +47,6 @@ static const njs_keyword_t njs_keywords
{ njs_str("finally"), NJS_TOKEN_FINALLY, 0 },
{ njs_str("throw"), NJS_TOKEN_THROW, 0 },
- /* Builtin objects. */
-
- { njs_str("this"), NJS_TOKEN_THIS, 0 },
- { njs_str("njs"), NJS_TOKEN_NJS, 0 },
- { njs_str("process"), NJS_TOKEN_PROCESS, 0 },
- { njs_str("Math"), NJS_TOKEN_MATH, 0 },
- { njs_str("JSON"), NJS_TOKEN_JSON, 0 },
-
/* Builtin functions. */
{ njs_str("Object"), NJS_TOKEN_OBJECT_CONSTRUCTOR, 0 },
@@ -82,6 +74,7 @@ static const njs_keyword_t njs_keywords
/* Reserved words. */
+ { njs_str("this"), NJS_TOKEN_THIS, 0 },
{ njs_str("arguments"), NJS_TOKEN_ARGUMENTS, 0 },
{ njs_str("eval"), NJS_TOKEN_EVAL, 0 },
diff -r 796870eab669 -r ba6f17a75b3a src/njs_object_hash.h
--- a/src/njs_object_hash.h Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_object_hash.h Thu Oct 31 18:17:31 2019 +0300
@@ -146,6 +146,14 @@
'j'), 'o'), 'i'), 'n')
+#define NJS_JSON_HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'J'), 'S'), 'O'), 'N')
+
+
#define NJS_LENGTH_HASH \
njs_djb_hash_add( \
njs_djb_hash_add( \
@@ -164,6 +172,21 @@
'n'), 'a'), 'm'), 'e')
+#define NJS_NJS_HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'n'), 'j'), 's')
+
+
+#define NJS_MATH_HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'M'), 'a'), 't'), 'h')
+
+
#define NJS_MESSAGE_HASH \
njs_djb_hash_add( \
njs_djb_hash_add( \
@@ -202,6 +225,17 @@
'p'), 'a'), 't'), 'h')
+#define NJS_PROCESS_HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ 'p'), 'r'), 'o'), 'c'), 'e'), 's'), 's')
+
+
#define NJS_PROTOTYPE_HASH \
njs_djb_hash_add( \
njs_djb_hash_add( \
diff -r 796870eab669 -r ba6f17a75b3a src/njs_parser_terminal.c
--- a/src/njs_parser_terminal.c Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_parser_terminal.c Thu Oct 31 18:17:31 2019 +0300
@@ -11,9 +11,6 @@
static njs_parser_node_t *njs_parser_reference(njs_vm_t *vm,
njs_parser_t *parser, njs_token_t token, njs_str_t *name, uint32_t hash,
uint32_t token_line);
-static njs_int_t njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *node, njs_value_type_t type, njs_str_t *name,
- uint32_t hash);
static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *obj);
static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
@@ -259,17 +256,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p
break;
- case NJS_TOKEN_NJS:
- case NJS_TOKEN_PROCESS:
- case NJS_TOKEN_MATH:
- case NJS_TOKEN_JSON:
- ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash);
- if (njs_slow_path(ret != NJS_OK)) {
- return NULL;
- }
-
- break;
-
case NJS_TOKEN_OBJECT_CONSTRUCTOR:
node->index = NJS_INDEX_OBJECT;
break;
@@ -399,42 +385,6 @@ njs_parser_reference(njs_vm_t *vm, njs_p
}
-static njs_int_t
-njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
- njs_value_type_t type, njs_str_t *name, uint32_t hash)
-{
- njs_int_t ret;
- njs_uint_t index;
- njs_variable_t *var;
- njs_parser_scope_t *scope;
-
- scope = njs_parser_global_scope(vm);
-
- var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR);
- if (njs_slow_path(var == NULL)) {
- return NJS_ERROR;
- }
-
- /* TODO: once */
- switch (type) {
- case NJS_OBJECT:
- index = node->token - NJS_TOKEN_FIRST_OBJECT;
- njs_set_object(&var->value, &vm->shared->objects[index]);
- break;
-
- default:
- return NJS_ERROR;
- }
-
- ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
-
- return NJS_OK;
-}
-
-
static njs_token_t
njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
{
diff -r 796870eab669 -r ba6f17a75b3a src/njs_value.h
--- a/src/njs_value.h Thu Oct 31 18:17:30 2019 +0300
+++ b/src/njs_value.h Thu Oct 31 18:17:31 2019 +0300
@@ -128,8 +128,8 @@ union njs_value_s {
*/
uint8_t truth;
- uint16_t _spare1;
- uint32_t _spare2;
+ uint16_t magic16;
+ uint32_t magic32;
union {
double number;
@@ -409,6 +409,17 @@ typedef struct {
}
+#define njs_prop_handler2(_handler, _magic16, _magic32) { \
+ .data = { \
+ .type = NJS_INVALID, \
+ .truth = 1, \
+ .magic16 = _magic16, \
+ .magic32 = _magic32, \
+ .u = { .prop_handler = _handler } \
+ } \
+}
+
+
#define njs_is_null(value) \
((value)->type == NJS_NULL)
diff -r 796870eab669 -r ba6f17a75b3a src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Thu Oct 31 18:17:30 2019 +0300
+++ b/src/test/njs_unit_test.c Thu Oct 31 18:17:31 2019 +0300
@@ -13227,6 +13227,43 @@ static njs_unit_test_t njs_test[] =
{ njs_str("parseFloat('-5.7e+abc')"),
njs_str("-5.7") },
+ /* Top-level objects. */
+
+ { njs_str("var global = this;"
+ "function isMutableObject(v) {"
+ " var d = Object.getOwnPropertyDescriptor(global, v);"
+ " return d.writable && !d.enumerable && d.configurable;"
+ "};"
+ "['njs', 'process', 'Math', 'JSON'].every((v)=>isMutableObject(v))"),
+ njs_str("true") },
+
+ { njs_str("njs === njs"),
+ njs_str("true") },
+
+ { njs_str("this.njs = 1; njs"),
+ njs_str("1") },
+
+ { njs_str("process === process"),
+ njs_str("true") },
+
+ { njs_str("this.process = 1; process"),
+ njs_str("1") },
+
+ { njs_str("Math === Math"),
+ njs_str("true") },
+
+ { njs_str("this.Math = 1; Math"),
+ njs_str("1") },
+
+ { njs_str("JSON === JSON"),
+ njs_str("true") },
+
+ { njs_str("this.JSON = 1; JSON"),
+ njs_str("1") },
+
+ { njs_str("delete this.JSON; JSON"),
+ njs_str("ReferenceError: \"JSON\" is not defined in 1") },
+
/* JSON.parse() */
{ njs_str("JSON.parse('null')"),
diff -r 796870eab669 -r ba6f17a75b3a test/njs_expect_test.exp
--- a/test/njs_expect_test.exp Thu Oct 31 18:17:30 2019 +0300
+++ b/test/njs_expect_test.exp Thu Oct 31 18:17:31 2019 +0300
@@ -120,8 +120,8 @@ njs_test {
njs_test {
{"Ma\t"
- "Ma\a*th"}
- {".\t\t"
+ "Ma\a*th."}
+ {"\t\t"
"Math.abs*Math.atan2"}
}
More information about the nginx-devel
mailing list