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