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 */
39void
40ecma_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 */
56void
57ecma_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 */
76ecma_object_t *
77ecma_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 */
87void
88ecma_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 */
105ecma_object_t *
106ecma_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 */
127ecma_value_t
128ecma_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 */
158ecma_value_t
159ecma_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 */
221ecma_value_t
222ecma_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 */
283ecma_value_t
284ecma_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 */
336ecma_value_t
337ecma_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 */
389ecma_value_t
390ecma_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 */
415void
416ecma_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 */
442void
443ecma_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 */
466void
467ecma_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 */
488ecma_property_t *
489ecma_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 */
519ecma_value_t
520ecma_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 */
545void
546ecma_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 */
564bool
565ecma_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