#define NJS_FUNCTION_MAX_DEPTH 128
+#define NJS_PRESERVATION_MAX_DEPTH 128
typedef struct njs_generator_patch_s njs_generator_patch_t;
}
+static njs_bool_t
+njs_generate_expr_requires_preservation_depth(njs_parser_node_t *node,
+ uint32_t depth)
+{
+ uint32_t i;
+ njs_bool_t preserve;
+ njs_parser_array_item_t *item;
+
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (depth >= NJS_PRESERVATION_MAX_DEPTH) {
+ return 1;
+ }
+
+ if (node->token_type >= NJS_TOKEN_ASSIGNMENT
+ && node->token_type <= NJS_TOKEN_LAST_ASSIGNMENT)
+ {
+ return 1;
+ }
+
+ if (node->token_type == NJS_TOKEN_FUNCTION_CALL
+ || node->token_type == NJS_TOKEN_METHOD_CALL)
+ {
+ return 1;
+ }
+
+ if (node->token_type == NJS_TOKEN_ARRAY && node->u.array.items != NULL) {
+ for (i = 0; i < node->u.array.items->items; i++) {
+ item = njs_arr_item(node->u.array.items, i);
+
+ if (njs_generate_expr_requires_preservation_depth(item->value,
+ depth + 1))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ preserve = njs_generate_expr_requires_preservation_depth(node->left,
+ depth + 1);
+
+ if (njs_fast_path(!preserve)) {
+ return njs_generate_expr_requires_preservation_depth(node->right,
+ depth + 1);
+ }
+
+ return preserve;
+}
+
+
+static njs_bool_t
+njs_generate_expr_requires_preservation(njs_parser_node_t *node)
+{
+ return njs_generate_expr_requires_preservation_depth(node, 0);
+}
+
+
static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator,
size_t size);
static njs_int_t njs_generate_code_map(njs_vm_t *vm, njs_generator_t *generator,
njs_parser_node_t *object, *property;
njs_vmcode_move_t *move;
- if (!njs_slow_path(njs_parser_has_side_effect(expr))) {
+ if (!njs_slow_path(njs_generate_expr_requires_preservation(expr))) {
return NJS_OK;
}
index = lvalue->index;
expr = node->right;
- if (njs_slow_path(njs_parser_has_side_effect(expr))) {
+ if (njs_slow_path(njs_generate_expr_requires_preservation(expr))) {
/* Preserve variable value if it may be changed by expression. */
njs_generate_code(generator, njs_vmcode_move_t, move,
left = node->left;
- if (njs_slow_path(njs_parser_has_side_effect(node->right))) {
+ if (njs_slow_path(njs_generate_expr_requires_preservation(node->right)))
+ {
njs_generate_code(generator, njs_vmcode_move_t, move,
NJS_VMCODE_MOVE, node);
move->src = left->index;
}
-njs_bool_t
-njs_parser_has_side_effect(njs_parser_node_t *node)
-{
- uint32_t i;
- njs_bool_t side_effect;
- njs_parser_array_item_t *item;
-
- if (node == NULL) {
- return 0;
- }
-
- if (node->token_type >= NJS_TOKEN_ASSIGNMENT
- && node->token_type <= NJS_TOKEN_LAST_ASSIGNMENT)
- {
- return 1;
- }
-
- if (node->token_type == NJS_TOKEN_FUNCTION_CALL
- || node->token_type == NJS_TOKEN_METHOD_CALL)
- {
- return 1;
- }
-
- if (node->token_type == NJS_TOKEN_ARRAY && node->u.array.items != NULL) {
- for (i = 0; i < node->u.array.items->items; i++) {
- item = njs_arr_item(node->u.array.items, i);
-
- if (njs_parser_has_side_effect(item->value)) {
- return 1;
- }
- }
-
- return 0;
- }
-
- side_effect = njs_parser_has_side_effect(node->left);
-
- if (njs_fast_path(!side_effect)) {
- return njs_parser_has_side_effect(node->right);
- }
-
- return side_effect;
-}
-
-
njs_int_t
njs_parser_variable_reference(njs_parser_t *parser, njs_parser_scope_t *scope,
njs_parser_node_t *node, uintptr_t atom_id)
njs_parser_scope_t *scope);
njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node);
njs_index_t njs_variable_index(njs_vm_t *vm, njs_parser_node_t *node);
-njs_bool_t njs_parser_has_side_effect(njs_parser_node_t *node);
njs_int_t njs_parser_variable_reference(njs_parser_t *parser,
njs_parser_scope_t *scope, njs_parser_node_t *node, uintptr_t atom_id);
njs_token_type_t njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser,
{ njs_str("var a = 1; function f(x) { a = x; return 2 }; a += f(5)"),
njs_str("3") },
+ { njs_str("var src = 'var a=1;return a+' + '('.repeat(256)"
+ "+ '0+'.repeat(256) + '(a=2)' + ')'.repeat(256);"
+ "(new Function(src))()"),
+ njs_str("3") },
+
+ { njs_str("var src = 'var a=1;a+=' + '('.repeat(256)"
+ "+ '0+'.repeat(256) + '(a=2)' + ')'.repeat(256) + ';return a';"
+ "(new Function(src))()"),
+ njs_str("3") },
+
+ { njs_str("var src = 'var i=0,a=[];a[i]=' + '['.repeat(256)"
+ "+ '(i=1)' + ']'.repeat(256)"
+ "+ ';return a[0] !== undefined && a[1] === undefined';"
+ "(new Function(src))()"),
+ njs_str("true") },
+
{ njs_str("var x; x in (x = 1, [1, 2, 3])"),
njs_str("false") },