Implement realm object and support realms for built-ins and JS functions (#4354)

- Type for realm objects is introduced (ecma_global_object_t)
- Realm reference is added to built-in objects and ECMAScript functions
- Resolving built-ins, global environments, and scopes require realm object
- Unnecessary global object accesses are removed from the code

Missing: external functions and static snapshot functions have no realm reference

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-12-08 14:36:36 +01:00
committed by GitHub
parent 7cb9f808f7
commit df92c86ecf
32 changed files with 1128 additions and 188 deletions
+109 -11
View File
@@ -149,6 +149,34 @@ ecma_deref_object (ecma_object_t *object_p) /**< object */
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs - ECMA_OBJECT_REF_ONE);
} /* ecma_deref_object */
/**
* Mark objects referenced by global object
*/
static void
ecma_gc_mark_global_object (ecma_global_object_t *global_object_p) /**< global object */
{
JERRY_ASSERT (global_object_p->extended_object.u.built_in.routine_id == 0);
ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, global_object_p->global_env_cp));
#if ENABLED (JERRY_ESNEXT)
if (global_object_p->global_scope_cp != global_object_p->global_env_cp)
{
ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, global_object_p->global_scope_cp));
}
#endif /* ENABLED (JERRY_ESNEXT) */
jmem_cpointer_t *builtin_objects_p = global_object_p->builtin_objects;
for (int i = 0; i < ECMA_BUILTIN_OBJECTS_COUNT; i++)
{
if (builtin_objects_p[i] != JMEM_CP_NULL)
{
ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER (ecma_object_t, builtin_objects_p[i]));
}
}
} /* ecma_gc_mark_global_object */
/**
* Mark objects referenced by arguments object
*/
@@ -620,14 +648,52 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
ecma_gc_set_object_visited (binding_object_p);
return;
}
}
else
{
switch (ecma_get_object_type (object_p))
ecma_object_type_t object_type = ecma_get_object_type (object_p);
#if ENABLED (JERRY_BUILTIN_REALMS)
if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p)))
{
ecma_value_t realm_value;
if (ECMA_BUILTIN_IS_EXTENDED_BUILT_IN (object_type))
{
realm_value = ((ecma_extended_built_in_object_t *) object_p)->built_in.realm_value;
}
else
{
ecma_extended_object_t *extended_object_p = (ecma_extended_object_t *) object_p;
if (object_type == ECMA_OBJECT_TYPE_GENERAL
&& extended_object_p->u.built_in.id == ECMA_BUILTIN_ID_GLOBAL)
{
ecma_gc_mark_global_object ((ecma_global_object_t *) object_p);
}
realm_value = extended_object_p->u.built_in.realm_value;
}
ecma_gc_set_object_visited (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, realm_value));
}
#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
switch (object_type)
{
#if !ENABLED (JERRY_BUILTIN_REALMS)
case ECMA_OBJECT_TYPE_GENERAL:
{
if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p))
&& ((ecma_extended_object_t *) object_p)->u.built_in.id == ECMA_BUILTIN_ID_GLOBAL)
{
ecma_gc_mark_global_object ((ecma_global_object_t *) object_p);
}
break;
}
#endif /* !ENABLED (JERRY_BUILTIN_REALMS) */
case ECMA_OBJECT_TYPE_CLASS:
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
@@ -823,9 +889,11 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_gc_set_object_visited (ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t,
ext_func_p->u.function.scope_cp));
#if ENABLED (JERRY_ESNEXT)
#if ENABLED (JERRY_ESNEXT) || ENABLED (JERRY_BUILTIN_REALMS)
const ecma_compiled_code_t *byte_code_p = ecma_op_function_get_compiled_code (ext_func_p);
#endif /* ENABLED (JERRY_ESNEXT) || ENABLED (JERRY_BUILTIN_REALMS) */
#if ENABLED (JERRY_ESNEXT)
if (CBC_FUNCTION_IS_ARROW (byte_code_p->status_flags))
{
ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p;
@@ -842,6 +910,30 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
}
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_BUILTIN_REALMS)
#if ENABLED (JERRY_SNAPSHOT_EXEC)
if (ext_func_p->u.function.bytecode_cp == JMEM_CP_NULL)
{
/* Static snapshot functions have a global realm */
break;
}
#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
ecma_value_t realm_value;
if (byte_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_code_p;
realm_value = args_p->realm_value;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_code_p;
realm_value = args_p->realm_value;
}
ecma_gc_set_object_visited (ecma_get_object_from_value (realm_value));
#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
break;
}
#if ENABLED (JERRY_ESNEXT)
@@ -1305,7 +1397,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{
uint8_t length_and_bitset_size;
if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY)
if (ECMA_BUILTIN_IS_EXTENDED_BUILT_IN (object_type))
{
ext_object_size = sizeof (ecma_extended_built_in_object_t);
length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.u.length_and_bitset_size;
@@ -1313,15 +1405,16 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
}
else
{
if (object_type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION
&& ecma_builtin_function_is_routine (object_p))
{
#if ENABLED (JERRY_ESNEXT)
ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
ecma_extended_object_t *extended_object_p = (ecma_extended_object_t *) object_p;
if (ext_obj_p->u.built_in.id == ECMA_BUILTIN_ID_HANDLER)
if (extended_object_p->u.built_in.routine_id > 0)
{
JERRY_ASSERT (object_type == ECMA_OBJECT_TYPE_NATIVE_FUNCTION);
#if ENABLED (JERRY_ESNEXT)
if (extended_object_p->u.built_in.id == ECMA_BUILTIN_ID_HANDLER)
{
switch (ext_obj_p->u.built_in.routine_id)
switch (extended_object_p->u.built_in.routine_id)
{
case ECMA_NATIVE_HANDLER_PROMISE_RESOLVE:
case ECMA_NATIVE_HANDLER_PROMISE_REJECT:
@@ -1367,6 +1460,11 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
}
#endif /* ENABLED (JERRY_ESNEXT) */
}
else if (extended_object_p->u.built_in.id == ECMA_BUILTIN_ID_GLOBAL)
{
JERRY_ASSERT (object_type == ECMA_OBJECT_TYPE_GENERAL);
ext_object_size = sizeof (ecma_global_object_t);
}
else
{
length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.u.length_and_bitset_size;
+22
View File
@@ -864,14 +864,30 @@ typedef struct
uint8_t instantiated_bitset[1]; /**< instantiated property bit set for generic built-ins */
uint8_t routine_flags; /**< flags for built-in routines */
} u2;
#if ENABLED (JERRY_BUILTIN_REALMS)
ecma_value_t realm_value; /**< realm value */
#else /* !ENABLED (JERRY_BUILTIN_REALMS) */
uint32_t continue_instantiated_bitset[1]; /**< bit set for instantiated properties */
#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
} ecma_built_in_props_t;
#if ENABLED (JERRY_BUILTIN_REALMS)
/**
* Number of bits available in the instantiated bitset without allocation
*/
#define ECMA_BUILTIN_INSTANTIATED_BITSET_MIN_SIZE (8)
#else /* !ENABLED (JERRY_BUILTIN_REALMS) */
/**
* Number of bits available in the instantiated bitset without allocation
*/
#define ECMA_BUILTIN_INSTANTIATED_BITSET_MIN_SIZE (8 + 32)
#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
/**
* Builtin routine function object status flags
*/
@@ -992,6 +1008,12 @@ typedef struct
ecma_built_in_props_t built_in; /**< built-in object part */
} ecma_extended_built_in_object_t;
/**
* Checks whether the built-in is an ecma_extended_built_in_object_t
*/
#define ECMA_BUILTIN_IS_EXTENDED_BUILT_IN(object_type) \
((object_type) == ECMA_OBJECT_TYPE_CLASS || (object_type) == ECMA_OBJECT_TYPE_ARRAY)
/**
* Flags for array.length_prop_and_hole_count
*/
+1 -1
View File
@@ -250,7 +250,7 @@ ecma_get_object_builtin_id (ecma_object_t *object_p) /**< object */
ecma_built_in_props_t *built_in_props_p;
ecma_object_type_t object_type = ecma_get_object_type (object_p);
if (object_type == ECMA_OBJECT_TYPE_CLASS || object_type == ECMA_OBJECT_TYPE_ARRAY)
if (ECMA_BUILTIN_IS_EXTENDED_BUILT_IN (object_type))
{
built_in_props_p = &((ecma_extended_built_in_object_t *) object_p)->built_in;
}
+2 -1
View File
@@ -77,9 +77,9 @@ ecma_finalize (void)
ecma_finalize_global_environment ();
uint8_t runs = 0;
do
{
ecma_finalize_builtins ();
ecma_gc_run ();
if (++runs >= JERRY_GC_LOOP_LIMIT)
{
@@ -87,6 +87,7 @@ ecma_finalize (void)
}
}
while (JERRY_CONTEXT (ecma_gc_new_objects) != 0);
ecma_finalize_lit_storage ();
} /* ecma_finalize */
+8 -1
View File
@@ -485,8 +485,15 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */
return ECMA_VALUE_EMPTY;
}
#if ENABLED (JERRY_BUILTIN_REALMS)
ecma_object_t *global_object_p;
global_object_p = ecma_get_object_from_value (ecma_op_function_get_realm (module_p->compiled_code_p));
#else /* !ENABLED (JERRY_BUILTIN_REALMS) */
ecma_object_t *global_object_p = ecma_builtin_get_global ();
#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
module_p->state = ECMA_MODULE_STATE_EVALUATING;
module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ());
module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p));
module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p);
JERRY_CONTEXT (module_top_context_p) = module_p->context_p;