[njs] Querying global object when variable cannot be resolved.
Dmitry Volyntsev
xeioex at nginx.com
Fri Oct 18 14:00:10 UTC 2019
details: https://hg.nginx.org/njs/rev/5f192dbb694e
branches:
changeset: 1188:5f192dbb694e
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Oct 18 16:34:50 2019 +0300
description:
Querying global object when variable cannot be resolved.
diffstat:
src/njs_disassembler.c | 2 +
src/njs_generator.c | 97 ++++++++++++++++++++++++++++++++++-------------
src/njs_vmcode.c | 17 ++++++++
src/njs_vmcode.h | 1 +
src/test/njs_unit_test.c | 22 ++++++++++
5 files changed, 111 insertions(+), 28 deletions(-)
diffs (285 lines):
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_disassembler.c
--- a/src/njs_disassembler.c Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_disassembler.c Fri Oct 18 16:34:50 2019 +0300
@@ -34,6 +34,8 @@ static njs_code_name_t code_names[] = {
{ NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t),
njs_str("PROP GET ") },
+ { NJS_VMCODE_GLOBAL_GET, sizeof(njs_vmcode_prop_get_t),
+ njs_str("GLOBAL GET ") },
{ NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
njs_str("PROP INIT ") },
{ NJS_VMCODE_PROTO_INIT, sizeof(njs_vmcode_prop_set_t),
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_generator.c
--- a/src/njs_generator.c Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_generator.c Fri Oct 18 16:34:50 2019 +0300
@@ -62,7 +62,7 @@ static njs_int_t njs_generate_name(njs_v
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_parser_node_t *node, njs_reference_type_t type);
static njs_int_t njs_generate_var_statement(njs_vm_t *vm,
njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_if_statement(njs_vm_t *vm,
@@ -176,6 +176,8 @@ static njs_int_t njs_generate_node_index
njs_generator_t *generator, njs_parser_node_t *node);
static njs_int_t njs_generate_index_release(njs_vm_t *vm,
njs_generator_t *generator, njs_index_t index);
+static njs_int_t njs_generate_global_reference(njs_vm_t *vm,
+ njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception);
static njs_int_t njs_generate_reference_error(njs_vm_t *vm,
njs_generator_t *generator, njs_parser_node_t *node);
@@ -577,11 +579,8 @@ njs_generate_name(njs_vm_t *vm, njs_gene
njs_vmcode_object_copy_t *copy;
var = njs_variable_resolve(vm, node);
- if (njs_slow_path(var == NULL)) {
- return njs_generate_reference_error(vm, generator, node);
- }
-
- if (var->type == NJS_VARIABLE_FUNCTION) {
+
+ if (var != NULL && var->type == NJS_VARIABLE_FUNCTION) {
node->index = njs_generate_dest_index(vm, generator, node);
if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
@@ -596,7 +595,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
return NJS_OK;
}
- return njs_generate_variable(vm, generator, node);
+ return njs_generate_variable(vm, generator, node, NJS_REFERENCE);
}
@@ -628,13 +627,22 @@ njs_generate_builtin_object(njs_vm_t *vm
static njs_int_t
njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
- njs_parser_node_t *node)
+ njs_parser_node_t *node, njs_reference_type_t type)
{
njs_index_t index;
index = njs_variable_index(vm, node);
if (njs_slow_path(index == NJS_INDEX_NONE)) {
- return njs_generate_reference_error(vm, generator, node);
+
+ switch (type) {
+ case NJS_DECLARATION:
+ return njs_generate_reference_error(vm, generator, node);
+
+ case NJS_REFERENCE:
+ case NJS_TYPEOF:
+ return njs_generate_global_reference(vm, generator, node,
+ type == NJS_REFERENCE);
+ }
}
node->index = index;
@@ -1682,7 +1690,7 @@ njs_generate_assignment(njs_vm_t *vm, nj
if (lvalue->token == NJS_TOKEN_NAME) {
- ret = njs_generate_variable(vm, generator, lvalue);
+ ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -1805,7 +1813,7 @@ njs_generate_operation_assignment(njs_vm
if (lvalue->token == NJS_TOKEN_NAME) {
- ret = njs_generate_variable(vm, generator, lvalue);
+ ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -2239,17 +2247,9 @@ njs_generate_typeof_operation(njs_vm_t *
expr = node->left;
if (expr->token == NJS_TOKEN_NAME) {
- expr->index = njs_variable_typeof(vm, expr);
-
- if (expr->u.reference.variable) {
- ret = njs_generate_variable(vm, generator, expr);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
-
- } else {
- expr->index = njs_value_index(vm, &njs_value_undefined,
- generator->runtime);
+ ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
}
} else {
@@ -2291,7 +2291,7 @@ njs_generate_inc_dec_operation(njs_vm_t
if (lvalue->token == NJS_TOKEN_NAME) {
- ret = njs_generate_variable(vm, generator, lvalue);
+ ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -2668,7 +2668,7 @@ njs_generate_function_call(njs_vm_t *vm,
name = node->left;
} else {
- ret = njs_generate_variable(vm, generator, node);
+ ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
@@ -2676,10 +2676,6 @@ njs_generate_function_call(njs_vm_t *vm,
name = node;
}
- if (node->u.reference.not_defined) {
- return NJS_OK;
- }
-
njs_generate_code(generator, njs_vmcode_function_frame_t, func,
NJS_VMCODE_FUNCTION_FRAME, 2);
func_offset = njs_code_offset(generator, func);
@@ -3361,6 +3357,51 @@ njs_generate_index_release(njs_vm_t *vm,
static njs_int_t
+njs_generate_global_reference(njs_vm_t *vm, njs_generator_t *generator,
+ njs_parser_node_t *node, njs_bool_t exception)
+{
+ njs_str_t *name;
+ njs_int_t ret;
+ njs_index_t index;
+ njs_value_t property;
+ njs_vmcode_prop_get_t *prop_get;
+
+ index = njs_generate_dest_index(vm, generator, node);
+ if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+ return NJS_ERROR;
+ }
+
+ njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
+ exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET, 3);
+
+ prop_get->value = index;
+ prop_get->object = NJS_INDEX_GLOBAL_OBJECT;
+
+ /* FIXME: cache keys in a hash. */
+
+ name = &node->u.reference.name;
+
+ ret = njs_string_set(vm, &property, name->start, name->length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ prop_get->property = njs_value_index(vm, &property, generator->runtime);
+ if (njs_slow_path(prop_get->property == NJS_INDEX_NONE)) {
+ return NJS_ERROR;
+ }
+
+ node->index = index;
+
+ if (!exception) {
+ return NJS_OK;
+ }
+
+ return njs_generate_reference_error(vm, generator, node);
+}
+
+
+static njs_int_t
njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *node)
{
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.c
--- a/src/njs_vmcode.c Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_vmcode.c Fri Oct 18 16:34:50 2019 +0300
@@ -209,6 +209,23 @@ next:
pc += sizeof(njs_vmcode_3addr_t);
goto next;
+ case NJS_VMCODE_GLOBAL_GET:
+ get = (njs_vmcode_prop_get_t *) pc;
+ retval = njs_vmcode_operand(vm, get->value);
+
+ ret = njs_value_property(vm, value1, value2, retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ goto error;
+ }
+
+ pc += sizeof(njs_vmcode_prop_get_t);
+
+ if (ret == NJS_OK) {
+ pc += sizeof(njs_vmcode_reference_error_t);
+ }
+
+ goto next;
+
/*
* njs_vmcode_try_return() saves a return value to use it later by
* njs_vmcode_finally(), and jumps to the nearest try_break block.
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.h
--- a/src/njs_vmcode.h Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_vmcode.h Fri Oct 18 16:34:50 2019 +0300
@@ -72,6 +72,7 @@ typedef uint8_t
#define NJS_VMCODE_DECREMENT VMCODE1(4)
#define NJS_VMCODE_POST_DECREMENT VMCODE1(5)
#define NJS_VMCODE_TRY_RETURN VMCODE1(6)
+#define NJS_VMCODE_GLOBAL_GET VMCODE1(7)
#define NJS_VMCODE_LESS VMCODE1(8)
#define NJS_VMCODE_GREATER VMCODE1(9)
diff -r 10c10102cad0 -r 5f192dbb694e src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Fri Oct 18 16:28:16 2019 +0300
+++ b/src/test/njs_unit_test.c Fri Oct 18 16:34:50 2019 +0300
@@ -2694,6 +2694,10 @@ static njs_unit_test_t njs_test[] =
"}; t"),
njs_str("A") },
+ { njs_str("[isNaN, undefined, isFinite]."
+ "map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"),
+ njs_str("1,0,0") },
+
/* continue. */
{ njs_str("continue"),
@@ -9319,6 +9323,18 @@ static njs_unit_test_t njs_test[] =
{ njs_str("this.a = 1; this.a"),
njs_str("1") },
+ { njs_str("this.a = 1; a"),
+ njs_str("1") },
+
+ { njs_str("this.a = 2; this.b = 3; a * b - a"),
+ njs_str("4") },
+
+ { njs_str("this.a = 1; a()"),
+ njs_str("TypeError: number is not a function") },
+
+ { njs_str("this.a = ()=>1; a()"),
+ njs_str("1") },
+
{ njs_str("this.undefined = 42"),
njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") },
@@ -13084,6 +13100,12 @@ static njs_unit_test_t njs_test[] =
{ njs_str("isNaN.length"),
njs_str("1") },
+ { njs_str("typeof isNaN"),
+ njs_str("function") },
+
+ { njs_str("typeof isNaN.length"),
+ njs_str("number") },
+
{ njs_str("isNaN()"),
njs_str("true") },
More information about the nginx-devel
mailing list