mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
ECMA_GET_POINTER is removed from:
- property list iteration
- lexical environment chain iteration
- prototype chain iteration
For all these iteration the compressed pointer can be used to get the elements and only decompressed them if it is necessary.
- Properly guard ecma property hashmap routines
- Remove the redundant NULL pointer check from ecma_create_property
- Remove ecma_gc_get_object_next since it became unnecessary
- Substitute ECMA_{GET,SET}_POINTER with ECMA_{GET,SET}_NON_NULL pointer when we can assume the pointer is not NULL
- Remove ecma_get_object_prototype and ecma_get_lex_env_outer_reference helper function the reduce the number of NULL pointer checks during decompressing the pointers
- Remove ecma_get_named_accessor_property_{getter,setter} helper functions for also reduce the number of NULL pointer check/decompressions
- Remove ECMA_PROPERTY_SEARCH_DEPTH_LIMIT since in ES5 there is no way to create circular prototype chain, and the ES2015 setPrototypeOf method can resolve this error so this check during the property lookup can be eliminated.
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
282 lines
8.3 KiB
C
282 lines
8.3 KiB
C
/* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* Implementation of ECMA GetValue and PutValue
|
|
*/
|
|
|
|
#include "ecma-builtins.h"
|
|
#include "ecma-exceptions.h"
|
|
#include "ecma-gc.h"
|
|
#include "ecma-helpers.h"
|
|
#include "ecma-lex-env.h"
|
|
#include "ecma-objects.h"
|
|
#include "ecma-function-object.h"
|
|
#include "ecma-objects-general.h"
|
|
#include "ecma-try-catch-macro.h"
|
|
|
|
/** \addtogroup ecma ECMA
|
|
* @{
|
|
*
|
|
* \addtogroup lexicalenvironment Lexical environment
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* GetValue operation part
|
|
*
|
|
* See also: ECMA-262 v5, 8.7.1, sections 3 and 5
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value.
|
|
*/
|
|
ecma_value_t
|
|
ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
|
|
ecma_object_t **ref_base_lex_env_p, /**< [out] reference's base (lexical environment) */
|
|
ecma_string_t *name_p) /**< variable name */
|
|
{
|
|
JERRY_ASSERT (lex_env_p != NULL
|
|
&& ecma_is_lexical_environment (lex_env_p));
|
|
|
|
while (true)
|
|
{
|
|
switch (ecma_get_lex_env_type (lex_env_p))
|
|
{
|
|
case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
|
|
{
|
|
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
|
|
|
|
if (property_p != NULL)
|
|
{
|
|
*ref_base_lex_env_p = lex_env_p;
|
|
return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value);
|
|
}
|
|
break;
|
|
}
|
|
#if ENABLED (JERRY_ES2015_CLASS)
|
|
case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND:
|
|
{
|
|
break;
|
|
}
|
|
#endif /* ENABLED (JERRY_ES2015_CLASS) */
|
|
default:
|
|
{
|
|
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
|
|
|
|
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
|
|
|
|
ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p);
|
|
|
|
if (ecma_is_value_found (result))
|
|
{
|
|
*ref_base_lex_env_p = lex_env_p;
|
|
return result;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
|
|
}
|
|
|
|
*ref_base_lex_env_p = NULL;
|
|
#if ENABLED (JERRY_ERROR_MESSAGES)
|
|
return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
|
|
"% is not defined",
|
|
ecma_make_string_value (name_p));
|
|
#else /* ENABLED (JERRY_ERROR_MESSAGES) */
|
|
return ecma_raise_reference_error (NULL);
|
|
#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
|
|
|
|
} /* ecma_op_get_value_lex_env_base */
|
|
|
|
/**
|
|
* GetValue operation part (object base).
|
|
*
|
|
* See also: ECMA-262 v5, 8.7.1, section 4
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value.
|
|
*/
|
|
ecma_value_t
|
|
ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
|
|
ecma_string_t *property_name_p) /**< property name */
|
|
{
|
|
if (ecma_is_value_object (base_value))
|
|
{
|
|
ecma_object_t *obj_p = ecma_get_object_from_value (base_value);
|
|
JERRY_ASSERT (obj_p != NULL
|
|
&& !ecma_is_lexical_environment (obj_p));
|
|
|
|
return ecma_op_object_get (obj_p, property_name_p);
|
|
}
|
|
|
|
JERRY_ASSERT (ecma_is_value_boolean (base_value)
|
|
|| ecma_is_value_number (base_value)
|
|
|| ECMA_ASSERT_VALUE_IS_SYMBOL (base_value)
|
|
|| ecma_is_value_string (base_value));
|
|
|
|
/* Fast path for the strings length property. The length of the string
|
|
can be obtained directly from the ecma-string. */
|
|
if (ecma_is_value_string (base_value) && ecma_string_is_length (property_name_p))
|
|
{
|
|
ecma_string_t *string_p = ecma_get_string_from_value (base_value);
|
|
|
|
return ecma_make_uint32_value (ecma_string_get_length (string_p));
|
|
}
|
|
|
|
ecma_value_t object_base = ecma_op_to_object (base_value);
|
|
JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (object_base));
|
|
|
|
ecma_object_t *object_p = ecma_get_object_from_value (object_base);
|
|
JERRY_ASSERT (object_p != NULL
|
|
&& !ecma_is_lexical_environment (object_p));
|
|
|
|
ecma_value_t ret_value = ECMA_VALUE_UNDEFINED;
|
|
|
|
while (true)
|
|
{
|
|
ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p);
|
|
|
|
if (ecma_is_value_found (value))
|
|
{
|
|
ret_value = value;
|
|
break;
|
|
}
|
|
|
|
if (object_p->u2.prototype_cp == JMEM_CP_NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp);
|
|
}
|
|
|
|
ecma_free_value (object_base);
|
|
|
|
return ret_value;
|
|
} /* ecma_op_get_value_object_base */
|
|
|
|
/**
|
|
* PutValue operation part
|
|
*
|
|
* See also: ECMA-262 v5, 8.7.2, sections 3 and 5
|
|
*
|
|
* @return ecma value
|
|
* Returned value must be freed with ecma_free_value.
|
|
*/
|
|
ecma_value_t
|
|
ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
|
|
ecma_string_t *name_p, /**< variable name */
|
|
bool is_strict, /**< flag indicating strict mode */
|
|
ecma_value_t value) /**< ECMA-value */
|
|
{
|
|
JERRY_ASSERT (lex_env_p != NULL
|
|
&& ecma_is_lexical_environment (lex_env_p));
|
|
|
|
while (true)
|
|
{
|
|
switch (ecma_get_lex_env_type (lex_env_p))
|
|
{
|
|
case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
|
|
{
|
|
ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
|
|
|
|
if (property_p != NULL)
|
|
{
|
|
if (ecma_is_property_writable (*property_p))
|
|
{
|
|
ecma_named_data_property_assign_value (lex_env_p, ECMA_PROPERTY_VALUE_PTR (property_p), value);
|
|
}
|
|
else if (is_strict)
|
|
{
|
|
return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set."));
|
|
}
|
|
return ECMA_VALUE_EMPTY;
|
|
}
|
|
break;
|
|
}
|
|
#if ENABLED (JERRY_ES2015_CLASS)
|
|
case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND:
|
|
{
|
|
break;
|
|
}
|
|
#endif /* ENABLED (JERRY_ES2015_CLASS) */
|
|
default:
|
|
{
|
|
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
|
|
|
|
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
|
|
|
|
if (ecma_op_object_has_property (binding_obj_p, name_p))
|
|
{
|
|
ecma_value_t completion = ecma_op_object_put (binding_obj_p,
|
|
name_p,
|
|
value,
|
|
is_strict);
|
|
|
|
if (ECMA_IS_VALUE_ERROR (completion))
|
|
{
|
|
return completion;
|
|
}
|
|
|
|
JERRY_ASSERT (ecma_is_value_boolean (completion));
|
|
return ECMA_VALUE_EMPTY;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
|
|
}
|
|
|
|
if (is_strict)
|
|
{
|
|
#if ENABLED (JERRY_ERROR_MESSAGES)
|
|
return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
|
|
"% is not defined",
|
|
ecma_make_string_value (name_p));
|
|
#else /* !ENABLED (JERRY_ERROR_MESSAGES) */
|
|
return ecma_raise_reference_error (NULL);
|
|
#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
|
|
}
|
|
|
|
ecma_value_t completion = ecma_op_object_put (ecma_builtin_get_global (),
|
|
name_p,
|
|
value,
|
|
false);
|
|
|
|
JERRY_ASSERT (ecma_is_value_boolean (completion));
|
|
|
|
return ECMA_VALUE_EMPTY;
|
|
} /* ecma_op_put_value_lex_env_base */
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|