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
16 #include "ecma-builtin-helpers.h"
17 #include "ecma-builtins.h"
18 #include "ecma-exceptions.h"
19 #include "ecma-gc.h"
20 #include "ecma-globals.h"
21 #include "ecma-helpers.h"
22 #include "ecma-lex-env.h"
23 #include "ecma-objects.h"
24 #include "jcontext.h"
25
26 /** \addtogroup ecma ECMA
27 * @{
28 *
29 * \addtogroup lexicalenvironment Lexical environment
30 * @{
31 *
32 * \addtogroup globallexicalenvironment Global lexical environment
33 * @{
34 */
35
36 /**
37 * Initialize Global environment
38 */
39 void
ecma_init_global_environment(void)40 ecma_init_global_environment (void)
41 {
42 ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL);
43
44 ecma_object_t *global_lex_env_p = ecma_create_object_lex_env (NULL,
45 glob_obj_p,
46 ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
47 ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_env_cp), global_lex_env_p);
48 #if ENABLED (JERRY_ES2015)
49 ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_lex_env_p);
50 #endif /* ENABLED (JERRY_ES2015) */
51 } /* ecma_init_global_environment */
52
53 /**
54 * Finalize Global environment
55 */
56 void
ecma_finalize_global_environment(void)57 ecma_finalize_global_environment (void)
58 {
59 #if ENABLED (JERRY_ES2015)
60 if (JERRY_CONTEXT (ecma_global_scope_cp) != JERRY_CONTEXT (ecma_global_env_cp))
61 {
62 ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp)));
63 }
64 JERRY_CONTEXT (ecma_global_scope_cp) = JMEM_CP_NULL;
65 #endif /* ENABLED (JERRY_ES2015) */
66 ecma_deref_object (ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp)));
67 JERRY_CONTEXT (ecma_global_env_cp) = JMEM_CP_NULL;
68 } /* ecma_finalize_global_environment */
69
70 /**
71 * Get reference to Global lexical environment
72 * without increasing its reference count.
73 *
74 * @return pointer to the object's instance
75 */
76 ecma_object_t *
ecma_get_global_environment(void)77 ecma_get_global_environment (void)
78 {
79 JERRY_ASSERT (JERRY_CONTEXT (ecma_global_env_cp) != JMEM_CP_NULL);
80 return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_env_cp));
81 } /* ecma_get_global_environment */
82
83 #if ENABLED (JERRY_ES2015)
84 /**
85 * Create the global lexical block on top of the global environment.
86 */
87 void
ecma_create_global_lexical_block(void)88 ecma_create_global_lexical_block (void)
89 {
90 if (JERRY_CONTEXT (ecma_global_scope_cp) == JERRY_CONTEXT (ecma_global_env_cp))
91 {
92 ecma_object_t *global_scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ());
93 global_scope_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_BLOCK;
94 ECMA_SET_NON_NULL_POINTER (JERRY_CONTEXT (ecma_global_scope_cp), global_scope_p);
95 }
96 } /* ecma_create_global_lexical_block */
97 #endif /* ENABLED (JERRY_ES2015) */
98
99 /**
100 * Get reference to Global lexical scope
101 * without increasing its reference count.
102 *
103 * @return pointer to the object's instance
104 */
105 ecma_object_t *
ecma_get_global_scope(void)106 ecma_get_global_scope (void)
107 {
108 #if ENABLED (JERRY_ES2015)
109 JERRY_ASSERT (JERRY_CONTEXT (ecma_global_scope_cp) != JMEM_CP_NULL);
110 return ECMA_GET_NON_NULL_POINTER (ecma_object_t, JERRY_CONTEXT (ecma_global_scope_cp));
111 #else /* !ENABLED (JERRY_ES2015) */
112 return ecma_get_global_environment ();
113 #endif /* !ENABLED (JERRY_ES2015) */
114 } /* ecma_get_global_scope */
115
116 /**
117 * @}
118 */
119
120 /**
121 * HasBinding operation.
122 *
123 * See also: ECMA-262 v5, 10.2.1
124 *
125 * @return true / false
126 */
127 ecma_value_t
ecma_op_has_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p)128 ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */
129 ecma_string_t *name_p) /**< argument N */
130 {
131 JERRY_ASSERT (lex_env_p != NULL
132 && ecma_is_lexical_environment (lex_env_p));
133
134 ecma_lexical_environment_type_t lex_env_type = ecma_get_lex_env_type (lex_env_p);
135
136 if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
137 {
138 ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
139
140 return ecma_make_boolean_value (property_p != NULL);
141 }
142
143 JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
144
145 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
146
147 return ecma_op_object_has_property (binding_obj_p, name_p);
148 } /* ecma_op_has_binding */
149
150 /**
151 * CreateMutableBinding operation.
152 *
153 * See also: ECMA-262 v5, 10.2.1
154 *
155 * @return ecma value
156 * Returned value must be freed with ecma_free_value
157 */
158 ecma_value_t
ecma_op_create_mutable_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p,bool is_deletable)159 ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */
160 ecma_string_t *name_p, /**< argument N */
161 bool is_deletable) /**< argument D */
162 {
163 JERRY_ASSERT (lex_env_p != NULL
164 && ecma_is_lexical_environment (lex_env_p));
165 JERRY_ASSERT (name_p != NULL);
166
167 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
168 {
169 uint8_t prop_attributes = ECMA_PROPERTY_FLAG_WRITABLE;
170
171 if (is_deletable)
172 {
173 prop_attributes = (uint8_t) (prop_attributes | ECMA_PROPERTY_FLAG_CONFIGURABLE);
174 }
175
176 ecma_create_named_data_property (lex_env_p,
177 name_p,
178 prop_attributes,
179 NULL);
180 }
181 else
182 {
183 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
184
185 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
186
187 if (!ecma_op_ordinary_object_is_extensible (binding_obj_p))
188 {
189 return ECMA_VALUE_EMPTY;
190 }
191
192 const uint32_t flags = ECMA_PROPERTY_ENUMERABLE_WRITABLE | ECMA_IS_THROW;
193
194 ecma_value_t completion = ecma_builtin_helper_def_prop (binding_obj_p,
195 name_p,
196 ECMA_VALUE_UNDEFINED,
197 is_deletable ? flags | ECMA_PROPERTY_FLAG_CONFIGURABLE
198 : flags);
199
200 if (ECMA_IS_VALUE_ERROR (completion))
201 {
202 return completion;
203 }
204 else
205 {
206 JERRY_ASSERT (ecma_is_value_boolean (completion));
207 }
208 }
209
210 return ECMA_VALUE_EMPTY;
211 } /* ecma_op_create_mutable_binding */
212
213 /**
214 * SetMutableBinding operation.
215 *
216 * See also: ECMA-262 v5, 10.2.1
217 *
218 * @return ecma value
219 * Returned value must be freed with ecma_free_value.
220 */
221 ecma_value_t
ecma_op_set_mutable_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p,ecma_value_t value,bool is_strict)222 ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */
223 ecma_string_t *name_p, /**< argument N */
224 ecma_value_t value, /**< argument V */
225 bool is_strict) /**< argument S */
226 {
227 JERRY_ASSERT (lex_env_p != NULL
228 && ecma_is_lexical_environment (lex_env_p));
229 JERRY_ASSERT (name_p != NULL);
230
231 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
232 {
233 ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
234
235 JERRY_ASSERT (property_p != NULL
236 && ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
237
238 if (ecma_is_property_writable (*property_p))
239 {
240 ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
241 }
242 #if ENABLED (JERRY_ES2015)
243 else if (ecma_is_property_enumerable (*property_p))
244 {
245 return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned."));
246 }
247 #endif /* ENABLED (JERRY_ES2015) */
248 else if (is_strict)
249 {
250 return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set."));
251 }
252 }
253 else
254 {
255 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
256
257 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
258
259 ecma_value_t completion = ecma_op_object_put (binding_obj_p,
260 name_p,
261 value,
262 is_strict);
263
264 if (ECMA_IS_VALUE_ERROR (completion))
265 {
266 return completion;
267 }
268
269 JERRY_ASSERT (ecma_is_value_boolean (completion));
270 }
271
272 return ECMA_VALUE_EMPTY;
273 } /* ecma_op_set_mutable_binding */
274
275 /**
276 * GetBindingValue operation.
277 *
278 * See also: ECMA-262 v5, 10.2.1
279 *
280 * @return ecma value
281 * Returned value must be freed with ecma_free_value.
282 */
283 ecma_value_t
ecma_op_get_binding_value(ecma_object_t * lex_env_p,ecma_string_t * name_p,bool is_strict)284 ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */
285 ecma_string_t *name_p, /**< argument N */
286 bool is_strict) /**< argument S */
287 {
288 JERRY_ASSERT (lex_env_p != NULL
289 && ecma_is_lexical_environment (lex_env_p));
290 JERRY_ASSERT (name_p != NULL);
291
292 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
293 {
294 ecma_property_value_t *prop_value_p = ecma_get_named_data_property (lex_env_p, name_p);
295
296 return ecma_copy_value (prop_value_p->value);
297 }
298 else
299 {
300 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
301
302 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
303
304 ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p);
305
306 if (ECMA_IS_VALUE_ERROR (result))
307 {
308 return result;
309 }
310
311 if (!ecma_is_value_found (result))
312 {
313 if (is_strict)
314 {
315 result = ecma_raise_reference_error (ECMA_ERR_MSG ("Binding does not exist or is uninitialised."));
316 }
317 else
318 {
319 result = ECMA_VALUE_UNDEFINED;
320 }
321 }
322
323 return result;
324 }
325 } /* ecma_op_get_binding_value */
326
327 /**
328 * DeleteBinding operation.
329 *
330 * See also: ECMA-262 v5, 10.2.1
331 *
332 * @return ecma value
333 * Return ECMA_VALUE_ERROR - if the operation fails
334 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the binding can be deleted
335 */
336 ecma_value_t
ecma_op_delete_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p)337 ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */
338 ecma_string_t *name_p) /**< argument N */
339 {
340 JERRY_ASSERT (lex_env_p != NULL
341 && ecma_is_lexical_environment (lex_env_p));
342 JERRY_ASSERT (name_p != NULL);
343
344 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
345 {
346 ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p);
347 ecma_value_t ret_val;
348
349 if (prop_p == NULL)
350 {
351 ret_val = ECMA_VALUE_TRUE;
352 }
353 else
354 {
355 JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
356
357 if (!ecma_is_property_configurable (*prop_p))
358 {
359 ret_val = ECMA_VALUE_FALSE;
360 }
361 else
362 {
363 ecma_delete_property (lex_env_p, ECMA_PROPERTY_VALUE_PTR (prop_p));
364
365 ret_val = ECMA_VALUE_TRUE;
366 }
367 }
368
369 return ret_val;
370 }
371 else
372 {
373 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
374
375 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
376
377 return ecma_op_object_delete (binding_obj_p, name_p, false);
378 }
379 } /* ecma_op_delete_binding */
380
381 /**
382 * ImplicitThisValue operation.
383 *
384 * See also: ECMA-262 v5, 10.2.1
385 *
386 * @return ecma value
387 * Returned value must be freed with ecma_free_value.
388 */
389 ecma_value_t
ecma_op_implicit_this_value(ecma_object_t * lex_env_p)390 ecma_op_implicit_this_value (ecma_object_t *lex_env_p) /**< lexical environment */
391 {
392 JERRY_ASSERT (lex_env_p != NULL
393 && ecma_is_lexical_environment (lex_env_p));
394
395 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
396 {
397 return ECMA_VALUE_UNDEFINED;
398 }
399 else
400 {
401 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
402
403 ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
404 ecma_ref_object (binding_obj_p);
405
406 return ecma_make_object_value (binding_obj_p);
407 }
408 } /* ecma_op_implicit_this_value */
409
410 /**
411 * CreateImmutableBinding operation.
412 *
413 * See also: ECMA-262 v5, 10.2.1
414 */
415 void
ecma_op_create_immutable_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p,ecma_value_t value)416 ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environment */
417 ecma_string_t *name_p, /**< argument N */
418 ecma_value_t value) /**< argument V */
419 {
420 JERRY_ASSERT (lex_env_p != NULL
421 && ecma_is_lexical_environment (lex_env_p));
422 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
423
424 /*
425 * Warning:
426 * Whether immutable bindings are deletable seems not to be defined by ECMA v5.
427 */
428 ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p,
429 name_p,
430 ECMA_PROPERTY_FIXED,
431 NULL);
432
433 prop_value_p->value = ecma_copy_value_if_not_object (value);
434 } /* ecma_op_create_immutable_binding */
435
436 #if ENABLED (JERRY_ES2015)
437 /**
438 * InitializeBinding operation.
439 *
440 * See also: ECMA-262 v6, 8.1.1.1.4
441 */
442 void
ecma_op_initialize_binding(ecma_object_t * lex_env_p,ecma_string_t * name_p,ecma_value_t value)443 ecma_op_initialize_binding (ecma_object_t *lex_env_p, /**< lexical environment */
444 ecma_string_t *name_p, /**< argument N */
445 ecma_value_t value) /**< argument V */
446 {
447 JERRY_ASSERT (lex_env_p != NULL
448 && ecma_is_lexical_environment (lex_env_p));
449 JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
450
451 ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p);
452 JERRY_ASSERT (prop_p != NULL);
453 JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
454
455 ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p);
456 JERRY_ASSERT (prop_value_p->value == ECMA_VALUE_UNINITIALIZED);
457
458 prop_value_p->value = ecma_copy_value_if_not_object (value);
459 } /* ecma_op_initialize_binding */
460
461 /**
462 * BindThisValue operation for an empty lexical environment
463 *
464 * See also: ECMA-262 v6, 8.1.1.3.1
465 */
466 void
ecma_op_init_this_binding(ecma_object_t * lex_env_p,ecma_value_t this_binding)467 ecma_op_init_this_binding (ecma_object_t *lex_env_p, /**< lexical environment */
468 ecma_value_t this_binding) /**< this binding value */
469 {
470 JERRY_ASSERT (lex_env_p != NULL);
471 JERRY_ASSERT (ecma_is_value_object (this_binding) || this_binding == ECMA_VALUE_UNINITIALIZED);
472 ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE);
473
474 ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p,
475 prop_name_p,
476 ECMA_PROPERTY_FIXED,
477 NULL);
478 prop_value_p->value = this_binding;
479 } /* ecma_op_init_this_binding */
480
481 /**
482 * GetThisEnvironment operation.
483 *
484 * See also: ECMA-262 v6, 8.3.2
485 *
486 * @return property pointer for the internal [[ThisBindingValue]] property
487 */
488 ecma_property_t *
ecma_op_get_this_property(ecma_object_t * lex_env_p)489 ecma_op_get_this_property (ecma_object_t *lex_env_p) /**< lexical environment */
490 {
491 JERRY_ASSERT (lex_env_p != NULL);
492
493 ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE);
494 while (true)
495 {
496 if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
497 {
498 ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, prop_name_p);
499
500 if (prop_p != NULL)
501 {
502 return prop_p;
503 }
504 }
505
506 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
507 lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
508 }
509 } /* ecma_op_get_this_property */
510
511 /**
512 * GetThisBinding operation.
513 *
514 * See also: ECMA-262 v6, 8.1.1.3.4
515 *
516 * @return ECMA_VALUE_ERROR - if the operation fails
517 * ecma-object - otherwise
518 */
519 ecma_value_t
ecma_op_get_this_binding(ecma_object_t * lex_env_p)520 ecma_op_get_this_binding (ecma_object_t *lex_env_p) /**< lexical environment */
521 {
522 JERRY_ASSERT (lex_env_p != NULL);
523
524 ecma_property_t *prop_p = ecma_op_get_this_property (lex_env_p);
525 JERRY_ASSERT (prop_p != NULL);
526
527 ecma_value_t this_value = ECMA_PROPERTY_VALUE_PTR (prop_p)->value;
528
529 if (this_value == ECMA_VALUE_UNINITIALIZED)
530 {
531 return ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
532 "accessing 'this' or returning from it."));
533 }
534
535 ecma_ref_object (ecma_get_object_from_value (this_value));
536
537 return this_value;
538 } /* ecma_op_get_this_binding */
539
540 /**
541 * BindThisValue operation.
542 *
543 * See also: ECMA-262 v6, 8.1.1.3.1
544 */
545 void
ecma_op_bind_this_value(ecma_property_t * prop_p,ecma_value_t this_binding)546 ecma_op_bind_this_value (ecma_property_t *prop_p, /**< [[ThisBindingValue]] internal property */
547 ecma_value_t this_binding) /**< this binding value */
548 {
549 JERRY_ASSERT (prop_p != NULL);
550 JERRY_ASSERT (ecma_is_value_object (this_binding));
551 JERRY_ASSERT (!ecma_op_this_binding_is_initialized (prop_p));
552
553 ECMA_PROPERTY_VALUE_PTR (prop_p)->value = this_binding;
554 } /* ecma_op_bind_this_value */
555
556 /**
557 * Get the environment record [[ThisBindingStatus]] internal property.
558 *
559 * See also: ECMA-262 v6, 8.1.1.3
560 *
561 * @return true - if the status is "initialzed"
562 * false - otherwise
563 */
564 bool
ecma_op_this_binding_is_initialized(ecma_property_t * prop_p)565 ecma_op_this_binding_is_initialized (ecma_property_t *prop_p) /**< [[ThisBindingValue]] internal property */
566 {
567 JERRY_ASSERT (prop_p != NULL);
568
569 return ECMA_PROPERTY_VALUE_PTR (prop_p)->value != ECMA_VALUE_UNINITIALIZED;
570 } /* ecma_op_this_binding_is_initialized */
571
572 #endif /* ENABLED (JERRY_ES2015) */
573
574 /**
575 * @}
576 * @}
577 */
578