Skip to content

Commit 2ade072

Browse files
authored
Optimize lexenv binding creation (#4502)
- Declarative environment no longer need to lookup the created binding for setting it's value - Unfold vm_decl_var and vm_set_var into vm_loop to reduce error checks - Reduce code duplication in ecma_module_connect_imports - Fix deleted binding setting in `ecma_op_set_mutable_binding` (fixes #4468) JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik [email protected]
1 parent 3b77117 commit 2ade072

File tree

8 files changed

+104
-119
lines changed

8 files changed

+104
-119
lines changed

jerry-core/ecma/base/ecma-globals.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,11 @@ do \
21482148
*/
21492149
#define ECMA_OBJECT_POINTER_ERROR ((ecma_object_t *) 0x01)
21502150

2151+
/**
2152+
* Invalid property pointer which represents abrupt completion
2153+
*/
2154+
#define ECMA_PROPERTY_POINTER_ERROR ((ecma_property_t *) 0x01)
2155+
21512156
#if ENABLED (JERRY_BUILTIN_PROXY)
21522157
/**
21532158
* Description of Proxy objects.

jerry-core/ecma/base/ecma-module.c

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,8 @@ ecma_module_connect_imports (ecma_module_t *module_p)
806806
const bool is_namespace_import = ecma_compare_ecma_string_to_magic_id (import_names_p->imex_name_p,
807807
LIT_MAGIC_STRING_ASTERIX_CHAR);
808808

809+
ecma_value_t prop_value;
810+
809811
if (is_namespace_import)
810812
{
811813
result = ecma_module_create_namespace_object (import_node_p->module_request_p);
@@ -814,11 +816,8 @@ ecma_module_connect_imports (ecma_module_t *module_p)
814816
return result;
815817
}
816818

817-
ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
818-
ecma_op_set_mutable_binding (local_env_p,
819-
import_names_p->local_name_p,
820-
ecma_make_object_value (import_node_p->module_request_p->namespace_object_p),
821-
false /* is_strict */);
819+
ecma_ref_object (import_node_p->module_request_p->namespace_object_p);
820+
prop_value = ecma_make_object_value (import_node_p->module_request_p->namespace_object_p);
822821
}
823822
else /* !is_namespace_import */
824823
{
@@ -838,18 +837,8 @@ ecma_module_connect_imports (ecma_module_t *module_p)
838837
if (record.module_p->state == ECMA_MODULE_STATE_NATIVE)
839838
{
840839
ecma_object_t *object_p = record.module_p->namespace_object_p;
841-
ecma_value_t prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p),
842-
object_p,
843-
record.name_p);
840+
prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p), object_p, record.name_p);
844841
JERRY_ASSERT (ecma_is_value_found (prop_value));
845-
846-
ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
847-
ecma_op_set_mutable_binding (local_env_p,
848-
import_names_p->local_name_p,
849-
prop_value,
850-
false /* is_strict */);
851-
852-
ecma_free_value (prop_value);
853842
}
854843
else
855844
{
@@ -861,20 +850,33 @@ ecma_module_connect_imports (ecma_module_t *module_p)
861850
}
862851

863852
ecma_object_t *ref_base_lex_env_p;
864-
ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p,
865-
&ref_base_lex_env_p,
866-
record.name_p);
853+
prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p,
854+
&ref_base_lex_env_p,
855+
record.name_p);
867856

868-
ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
869-
ecma_op_set_mutable_binding (local_env_p,
870-
import_names_p->local_name_p,
871-
prop_value,
872-
false /* is_strict */);
873-
874-
ecma_free_value (prop_value);
875857
}
876858
}
877859

860+
ecma_property_t *prop_p = ecma_op_create_mutable_binding (local_env_p,
861+
import_names_p->local_name_p,
862+
true /* is_deletable */);
863+
JERRY_ASSERT (prop_p != ECMA_PROPERTY_POINTER_ERROR);
864+
865+
if (prop_p != NULL)
866+
{
867+
JERRY_ASSERT (ecma_is_value_undefined (ECMA_PROPERTY_VALUE_PTR (prop_p)->value));
868+
ECMA_PROPERTY_VALUE_PTR (prop_p)->value = prop_value;
869+
ecma_deref_if_object (prop_value);
870+
}
871+
else
872+
{
873+
ecma_op_set_mutable_binding (local_env_p,
874+
import_names_p->local_name_p,
875+
prop_value,
876+
false /* is_strict */);
877+
ecma_free_value (prop_value);
878+
}
879+
878880
import_names_p = import_names_p->next_p;
879881
}
880882

jerry-core/ecma/operations/ecma-lex-env.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */
144144
*
145145
* See also: ECMA-262 v5, 10.2.1
146146
*
147-
* @return ecma value
148-
* Returned value must be freed with ecma_free_value
147+
* @return ECMA_PROPERTY_POINTER_ERROR - if the operation raises error
148+
* pointer to the created property - if the binding was created into a declerative environment
149+
* NULL - otherwise
149150
*/
150-
ecma_value_t
151+
ecma_property_t *
151152
ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */
152153
ecma_string_t *name_p, /**< argument N */
153154
bool is_deletable) /**< argument D */
@@ -165,10 +166,13 @@ ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environme
165166
prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_CONFIGURABLE);
166167
}
167168

169+
ecma_property_t *prop_p;
170+
168171
ecma_create_named_data_property (lex_env_p,
169172
name_p,
170173
prop_attributes,
171-
NULL);
174+
&prop_p);
175+
return prop_p;
172176
}
173177
else
174178
{
@@ -183,22 +187,22 @@ ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environme
183187

184188
if (ECMA_IS_VALUE_ERROR (result))
185189
{
186-
return result;
190+
return ECMA_PROPERTY_POINTER_ERROR;
187191
}
188192

189193
if (result == ECMA_VALUE_FALSE)
190194
{
191-
return ECMA_VALUE_EMPTY;
195+
return NULL;
192196
}
193197
}
194198
else if (!ecma_op_ordinary_object_is_extensible (binding_obj_p))
195199
{
196-
return ECMA_VALUE_EMPTY;
200+
return NULL;
197201
}
198202
#else /* !ENABLED (JERRY_BUILTIN_PROXY) || !ENABLED (JERRY_BUILTIN_REALMS) */
199203
if (!ecma_op_ordinary_object_is_extensible (binding_obj_p))
200204
{
201-
return ECMA_VALUE_EMPTY;
205+
return NULL;
202206
}
203207
#endif /* ENABLED (JERRY_BUILTIN_PROXY) && ENABLED (JERRY_BUILTIN_REALMS) */
204208

@@ -212,15 +216,15 @@ ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environme
212216

213217
if (ECMA_IS_VALUE_ERROR (completion))
214218
{
215-
return completion;
219+
return ECMA_PROPERTY_POINTER_ERROR;
216220
}
217221
else
218222
{
219223
JERRY_ASSERT (ecma_is_value_boolean (completion));
220224
}
221225
}
222226

223-
return ECMA_VALUE_EMPTY;
227+
return NULL;
224228
} /* ecma_op_create_mutable_binding */
225229

226230
/**
@@ -245,6 +249,12 @@ ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment
245249
{
246250
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
247251

252+
if (JERRY_UNLIKELY (property_p == NULL))
253+
{
254+
property_p = ecma_op_create_mutable_binding (lex_env_p, name_p, is_strict);
255+
JERRY_ASSERT (property_p != ECMA_PROPERTY_POINTER_ERROR);
256+
}
257+
248258
JERRY_ASSERT (property_p != NULL && ECMA_PROPERTY_IS_RAW_DATA (*property_p));
249259

250260
if (ecma_is_property_writable (*property_p))

jerry-core/ecma/operations/ecma-lex-env.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ ecma_value_t ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, ecma_stri
5656

5757
/* ECMA-262 v5, Table 17. Abstract methods of Environment Records */
5858
ecma_value_t ecma_op_has_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p);
59-
ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, bool is_deletable);
59+
ecma_property_t *ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, bool is_deletable);
6060
ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value,
6161
bool is_strict);
6262
ecma_value_t ecma_op_get_binding_value (ecma_object_t *lex_env_p, ecma_string_t *name_p, bool is_strict);

jerry-core/vm/opcodes.c

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -40,78 +40,6 @@
4040
* @{
4141
*/
4242

43-
/**
44-
* 'Variable declaration' opcode handler.
45-
*
46-
* See also: ECMA-262 v5, 10.5 - Declaration binding instantiation (block 8).
47-
*
48-
* @return ECMA_VALUE_ERROR - if no the operation fails
49-
* ECMA_VALUE_EMPTY - otherwise
50-
*/
51-
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
52-
vm_var_decl (ecma_object_t *lex_env_p, /**< target lexical environment */
53-
ecma_string_t *var_name_str_p, /**< variable name */
54-
bool is_configurable_bindings) /**< true if the binding can be deleted */
55-
{
56-
ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, var_name_str_p);
57-
58-
#if ENABLED (JERRY_BUILTIN_PROXY)
59-
if (ECMA_IS_VALUE_ERROR (has_binding))
60-
{
61-
return has_binding;
62-
}
63-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
64-
65-
if (ecma_is_value_false (has_binding))
66-
{
67-
ecma_value_t completion_value = ecma_op_create_mutable_binding (lex_env_p,
68-
var_name_str_p,
69-
is_configurable_bindings);
70-
71-
#if ENABLED (JERRY_BUILTIN_PROXY)
72-
if (ECMA_IS_VALUE_ERROR (completion_value))
73-
{
74-
return completion_value;
75-
}
76-
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
77-
78-
JERRY_ASSERT (ecma_is_value_empty (completion_value));
79-
80-
/* Skipping SetMutableBinding as we have already checked that there were not
81-
* any binding with specified name in current lexical environment
82-
* and CreateMutableBinding sets the created binding's value to undefined */
83-
JERRY_ASSERT (ecma_is_value_undefined (ecma_op_get_binding_value (lex_env_p,
84-
var_name_str_p,
85-
vm_is_strict_mode ())));
86-
}
87-
88-
return ECMA_VALUE_EMPTY;
89-
} /* vm_var_decl */
90-
91-
/**
92-
* Set var binding to a function literal value.
93-
*
94-
* @return ECMA_VALUE_ERROR - if no the operation fails
95-
* ECMA_VALUE_EMPTY - otherwise
96-
*/
97-
extern inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
98-
vm_set_var (ecma_object_t *lex_env_p, /**< target lexical environment */
99-
ecma_string_t *var_name_str_p, /**< variable name */
100-
bool is_strict, /**< true, if the engine is in strict mode */
101-
ecma_value_t lit_value) /**< function value */
102-
{
103-
ecma_value_t put_value_result;
104-
put_value_result = ecma_op_put_value_lex_env_base (lex_env_p, var_name_str_p, is_strict, lit_value);
105-
106-
JERRY_ASSERT (ecma_is_value_boolean (put_value_result)
107-
|| ecma_is_value_empty (put_value_result)
108-
|| ECMA_IS_VALUE_ERROR (put_value_result));
109-
110-
ecma_free_value (lit_value);
111-
112-
return put_value_result;
113-
} /* vm_set_var */
114-
11543
/**
11644
* 'typeof' opcode handler.
11745
*

jerry-core/vm/opcodes.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,6 @@ typedef enum
7171
*/
7272
#define OPFUNC_HAS_SPREAD_ELEMENT (1 << 8)
7373

74-
ecma_value_t
75-
vm_var_decl (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_configurable_bindings);
76-
77-
ecma_value_t
78-
vm_set_var (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_strict, ecma_value_t lit_value);
79-
8074
ecma_value_t
8175
opfunc_equality (ecma_value_t left_value, ecma_value_t right_value);
8276

jerry-core/vm/vm.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,23 +1395,52 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
13951395
}
13961396
#endif /* ENABLED (JERRY_ESNEXT) && !JERRY_NDEBUG */
13971397

1398-
result = vm_var_decl (lex_env_p, name_p, (frame_ctx_p->status_flags & VM_FRAME_CTX_DIRECT_EVAL) != 0);
1398+
/* 'Variable declaration' */
1399+
result = ecma_op_has_binding (lex_env_p, name_p);
13991400

1401+
#if ENABLED (JERRY_BUILTIN_PROXY)
14001402
if (ECMA_IS_VALUE_ERROR (result))
14011403
{
14021404
goto error;
14031405
}
1406+
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
14041407

1405-
if (lit_value != ECMA_VALUE_UNDEFINED)
1408+
ecma_property_t *prop_p = NULL;
1409+
1410+
if (ecma_is_value_false (result))
14061411
{
1407-
result = vm_set_var (lex_env_p, name_p, is_strict, lit_value);
1412+
bool is_configurable = (frame_ctx_p->status_flags & VM_FRAME_CTX_DIRECT_EVAL) != 0;
1413+
prop_p = ecma_op_create_mutable_binding (lex_env_p, name_p, is_configurable);
14081414

1409-
if (ECMA_IS_VALUE_ERROR (result))
1415+
if (JERRY_UNLIKELY (prop_p == ECMA_PROPERTY_POINTER_ERROR))
14101416
{
1417+
result = ECMA_VALUE_ERROR;
14111418
goto error;
14121419
}
14131420
}
14141421

1422+
if (lit_value != ECMA_VALUE_UNDEFINED)
1423+
{
1424+
JERRY_ASSERT (ecma_is_value_object (lit_value));
1425+
1426+
if (prop_p != NULL)
1427+
{
1428+
JERRY_ASSERT (ecma_is_value_undefined (ECMA_PROPERTY_VALUE_PTR (prop_p)->value));
1429+
JERRY_ASSERT (ecma_is_property_writable (*prop_p));
1430+
ECMA_PROPERTY_VALUE_PTR (prop_p)->value = lit_value;
1431+
ecma_free_object (lit_value);
1432+
}
1433+
else
1434+
{
1435+
result = ecma_op_put_value_lex_env_base (lex_env_p, name_p, is_strict, lit_value);
1436+
ecma_free_object (lit_value);
1437+
1438+
if (ECMA_IS_VALUE_ERROR (result))
1439+
{
1440+
goto error;
1441+
}
1442+
}
1443+
}
14151444
continue;
14161445
}
14171446
#if ENABLED (JERRY_ESNEXT)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
var str = 'for (let i=0; i<(eval("1; function x() { }; 2;")); x - i++) { x += delete x;}'
16+
17+
assert(eval(str) === 'function(){/* ecmascript */}true');

0 commit comments

Comments
 (0)