Skip to content

Implement the core of the generator functions. #3368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions jerry-core/ecma/base/ecma-gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */

#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER)

/**
* Mark objects referenced by Map/Set built-in.
*/
Expand Down Expand Up @@ -359,6 +360,73 @@ ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */

#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */

#if ENABLED (JERRY_ES2015)

/**
* Mark objects referenced by inactive generator functions, async functions, etc.
*/
static void
ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */
{
vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;

if (!ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info))
{
/* All objects referenced by running executable objects are strong roots,
* and a finished executable object cannot refer to other values. */
return;
}

ecma_gc_set_object_visited (executable_object_p->frame_ctx.lex_env_p);

if (ecma_is_value_object (executable_object_p->frame_ctx.this_binding))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (executable_object_p->frame_ctx.this_binding));
}

const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p;
size_t register_end;

if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
register_end = args_p->register_end;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
register_end = args_p->register_end;
}

ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
ecma_value_t *register_end_p = register_p + register_end;

while (register_p < register_end_p)
{
if (ecma_is_value_object (*register_p))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p));
}

register_p++;
}

register_p += executable_object_p->frame_ctx.context_depth;
register_end_p = executable_object_p->frame_ctx.stack_top_p;

while (register_p < register_end_p)
{
if (ecma_is_value_object (*register_p))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (*register_p));
}

register_p++;
}
} /* ecma_gc_mark_executable_object */

#endif /* ENABLED (JERRY_ES2015) */

/**
* Mark objects as visited starting from specified object as root
*/
Expand Down Expand Up @@ -435,6 +503,13 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
break;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */
#if ENABLED (JERRY_ES2015)
case LIT_MAGIC_STRING_GENERATOR_UL:
{
ecma_gc_mark_executable_object (object_p);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
break;
Expand Down Expand Up @@ -641,6 +716,100 @@ ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode arra
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
} /* ecma_free_fast_access_array */

#if ENABLED (JERRY_ES2015)

/**
* Free non-objects referenced by inactive generator functions, async functions, etc.
*
* @return total object size
*/
static size_t
ecma_gc_free_executable_object (ecma_object_t *object_p) /**< object */
{
vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;

const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p;
size_t size, register_end;

if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;

register_end = args_p->register_end;
size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t);
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;

register_end = args_p->register_end;
size = (register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t);
}

size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t));

JERRY_ASSERT (!(executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING));

ecma_bytecode_deref ((ecma_compiled_code_t *) bytecode_header_p);

if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED)
{
return size;
}

ecma_free_value_if_not_object (executable_object_p->frame_ctx.this_binding);

ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
ecma_value_t *register_end_p = register_p + register_end;

while (register_p < register_end_p)
{
ecma_free_value_if_not_object (*register_p++);
}

if (executable_object_p->frame_ctx.context_depth > 0)
{
ecma_value_t *context_end_p = register_p;

register_p += executable_object_p->frame_ctx.context_depth;

ecma_value_t *context_top_p = register_p;

do
{
context_top_p[-1] &= (uint32_t) ~VM_CONTEXT_HAS_LEX_ENV;

uint32_t offsets = vm_get_context_value_offsets (context_top_p);

while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets))
{
int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets);

if (ecma_is_value_object (context_top_p[offset]))
{
context_top_p[offset] = ECMA_VALUE_UNDEFINED;
}

offsets >>= VM_CONTEXT_OFFSET_SHIFT;
}

context_top_p = vm_stack_context_abort (&executable_object_p->frame_ctx, context_top_p);
}
while (context_top_p > context_end_p);
}

register_end_p = executable_object_p->frame_ctx.stack_top_p;

while (register_p < register_end_p)
{
ecma_free_value_if_not_object (*register_p++);
}

return size;
} /* ecma_gc_free_executable_object */

#endif /* ENABLED (JERRY_ES2015) */

/**
* Free properties of an object
*/
Expand Down Expand Up @@ -930,6 +1099,13 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
break;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */
#if ENABLED (JERRY_ES2015)
case LIT_MAGIC_STRING_GENERATOR_UL:
{
ext_object_size = ecma_gc_free_executable_object (object_p);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
/* The undefined id represents an uninitialized class. */
Expand Down
29 changes: 29 additions & 0 deletions jerry-core/ecma/base/ecma-globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,35 @@ typedef struct

#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */

#if ENABLED (JERRY_ES2015)

/**
* Executable (e.g. generator, async) object flags.
*/
typedef enum
{
ECMA_EXECUTABLE_OBJECT_COMPLETED = (1u << 0), /**< executable object is completed and cannot be resumed */
ECMA_EXECUTABLE_OBJECT_RUNNING = (1u << 1), /**< executable object is currently running */
} ecma_executable_object_flags_t;

/**
* Checks whether the executable object is waiting for resuming.
*/
#define ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED(extra_info) \
(!((extra_info) & (ECMA_EXECUTABLE_OBJECT_COMPLETED | ECMA_EXECUTABLE_OBJECT_RUNNING)))

/**
* Executable (e.g. generator, async) object flags.
*/
typedef enum
{
ECMA_GENERATOR_NEXT, /**< generator should continue its execution */
ECMA_GENERATOR_RETURN, /**< generator should perform a return operation */
ECMA_GENERATOR_THROW, /**< generator should perform a throw operation */
} ecma_generator_yield_mode_t;

#endif /* ENABLED (JERRY_ES2015) */

#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
/**
* Description of DataView objects.
Expand Down
28 changes: 26 additions & 2 deletions jerry-core/ecma/base/ecma-helpers-value.c
Original file line number Diff line number Diff line change
Expand Up @@ -855,17 +855,41 @@ ecma_fast_copy_value (ecma_value_t value) /**< value description */
*
* @return copy of the given value
*/
ecma_value_t
inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE
ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */
{
if (ecma_get_value_type_field (value) != ECMA_TYPE_OBJECT)
if (!ecma_is_value_object (value))
{
return ecma_copy_value (value);
}

return value;
} /* ecma_copy_value_if_not_object */

/**
* Increase reference counter of a value if it is an object.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
ecma_ref_if_object (ecma_value_t value) /**< value description */
{
if (ecma_is_value_object (value))
{
ecma_ref_object (ecma_get_object_from_value (value));
}
} /* ecma_ref_if_object */

/**
* Decrease reference counter of a value if it is an object.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
ecma_deref_if_object (ecma_value_t value) /**< value description */
{
if (ecma_is_value_object (value))
{
ecma_deref_object (ecma_get_object_from_value (value));
}
} /* ecma_deref_if_object */

/**
* Assign a new value to an ecma-value
*
Expand Down
2 changes: 2 additions & 0 deletions jerry-core/ecma/base/ecma-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ ecma_value_t JERRY_ATTR_CONST ecma_invert_boolean_value (ecma_value_t value);
ecma_value_t ecma_copy_value (ecma_value_t value);
ecma_value_t ecma_fast_copy_value (ecma_value_t value);
ecma_value_t ecma_copy_value_if_not_object (ecma_value_t value);
void ecma_ref_if_object (ecma_value_t value);
void ecma_deref_if_object (ecma_value_t value);
ecma_value_t ecma_update_float_number (ecma_value_t float_value, ecma_number_t new_number);
void ecma_value_assign_value (ecma_value_t *value_p, ecma_value_t ecma_value);
void ecma_value_assign_number (ecma_value_t *value_p, ecma_number_t ecma_number);
Expand Down
Loading