Implement the core of the generator functions. (#3368)

Some things are missing:
 - yield* support
 - generator definition in object literal
 - the hidden GeneratorFunction

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg 2019-11-28 11:54:27 +01:00 committed by Dániel Bátyai
parent 14e95a4775
commit 110f75c99d
35 changed files with 1535 additions and 85 deletions

View File

@ -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.
*/
@ -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
*/
@ -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;
@ -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
*/
@ -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. */

View File

@ -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.

View File

@ -855,10 +855,10 @@ 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);
}
@ -866,6 +866,30 @@ ecma_copy_value_if_not_object (ecma_value_t value) /**< value description */
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
*

View File

@ -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);

View File

@ -0,0 +1,156 @@
/* 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.
*/
#include "ecma-builtins.h"
#include "ecma-exceptions.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-iterator-object.h"
#include "opcodes.h"
#include "vm-defines.h"
#if ENABLED (JERRY_ES2015)
#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-generator-prototype.inc.h"
#define BUILTIN_UNDERSCORED_ID generator_prototype
#include "ecma-builtin-internal-routines-template.inc.h"
/** \addtogroup ecma ECMA
* @{
*
* \addtogroup ecmabuiltins
* @{
*
* \addtogroup generator ECMA Generator object built-in
* @{
*/
/**
* Helper function for next / return / throw
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_generator_prototype_object_do (ecma_value_t this_arg, /**< this argument */
ecma_value_t arg, /**< argument */
uint8_t yield_mode) /**< yield mode */
{
vm_executable_object_t *executable_object_p = NULL;
if (ecma_is_value_object (this_arg))
{
ecma_object_t *object_p = ecma_get_object_from_value (this_arg);
if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS)
{
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_GENERATOR_UL)
{
executable_object_p = (vm_executable_object_t *) ext_object_p;
}
}
}
if (executable_object_p == NULL)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a generator object."));
}
if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_RUNNING)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Generator is currently under execution."));
}
if (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED)
{
return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE);
}
executable_object_p->frame_ctx.call_operation = yield_mode;
ecma_value_t value = opfunc_resume_executable_object (executable_object_p, arg);
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (value)))
{
return value;
}
bool done = (executable_object_p->extended_object.u.class_prop.extra_info & ECMA_EXECUTABLE_OBJECT_COMPLETED);
ecma_value_t result = ecma_create_iter_result_object (value, ecma_make_boolean_value (done));
ecma_fast_free_value (value);
return result;
} /* ecma_builtin_generator_prototype_object_do */
/**
* The Generator.prototype object's 'next' routine
*
* See also:
* ECMA-262 v6, 25.3.1.2
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_generator_prototype_object_next (ecma_value_t this_arg, /**< this argument */
ecma_value_t next_arg) /**< next argument */
{
return ecma_builtin_generator_prototype_object_do (this_arg, next_arg, ECMA_GENERATOR_NEXT);
} /* ecma_builtin_generator_prototype_object_next */
/**
* The Generator.prototype object's 'return' routine
*
* See also:
* ECMA-262 v6, 25.3.1.3
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_generator_prototype_object_return (ecma_value_t this_arg, /**< this argument */
ecma_value_t return_arg) /**< return argument */
{
return ecma_builtin_generator_prototype_object_do (this_arg, return_arg, ECMA_GENERATOR_RETURN);
} /* ecma_builtin_generator_prototype_object_return */
/**
* The Generator.prototype object's 'throw' routine
*
* See also:
* ECMA-262 v6, 25.3.1.4
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_generator_prototype_object_throw (ecma_value_t this_arg, /**< this argument */
ecma_value_t throw_arg) /**< throw argument */
{
return ecma_builtin_generator_prototype_object_do (this_arg, throw_arg, ECMA_GENERATOR_THROW);
} /* ecma_builtin_generator_prototype_object_throw */
/**
* @}
* @}
* @}
*/
#endif /* ENABLED (JERRY_ES2015) */

View File

@ -0,0 +1,40 @@
/* 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.
*/
/*
* Generator.prototype built-in description
*/
#include "ecma-builtin-helpers-macro-defines.inc.h"
#if ENABLED (JERRY_ES2015)
/* Object properties:
* (property name, object pointer getter) */
/* ECMA-262 v6, 25.3.1.5 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_GENERATOR_UL,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_NEXT, ecma_builtin_generator_prototype_object_next, 1, 1)
ROUTINE (LIT_MAGIC_STRING_RETURN, ecma_builtin_generator_prototype_object_return, 1, 1)
ROUTINE (LIT_MAGIC_STRING_THROW, ecma_builtin_generator_prototype_object_throw, 1, 1)
#endif /* ENABLED (JERRY_ES2015) */
#include "ecma-builtin-helpers-macro-undefs.inc.h"

View File

@ -524,7 +524,14 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SYMBOL,
true,
symbol)
BUILTIN (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE,
ECMA_OBJECT_TYPE_GENERAL,
ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE,
true,
generator_prototype)
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
/* The %IteratorPrototype% object (ECMA-262 v6, 25.1.2) */
BUILTIN (ECMA_BUILTIN_ID_ITERATOR_PROTOTYPE,

View File

@ -789,21 +789,24 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
bool free_this_binding = false;
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p);
uint16_t status_flags = bytecode_data_p->status_flags;
#if ENABLED (JERRY_ES2015)
bool is_class_constructor = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) != 0;
if (is_class_constructor && !ecma_op_function_has_construct_flag (arguments_list_p))
if (JERRY_UNLIKELY (status_flags & (CBC_CODE_FLAGS_CONSTRUCTOR | CBC_CODE_FLAGS_GENERATOR)))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
if ((status_flags & CBC_CODE_FLAGS_CONSTRUCTOR) && !ecma_op_function_has_construct_flag (arguments_list_p))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
if ((status_flags & CBC_CODE_FLAGS_GENERATOR) && ecma_op_function_has_construct_flag (arguments_list_p))
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Generator functions cannot be invoked with 'new'."));
}
}
#endif /* ENABLED (JERRY_ES2015) */
bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0;
bool is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) != 0;
/* 1. */
if (!is_strict)
if (!(status_flags & CBC_CODE_FLAGS_STRICT_MODE))
{
if (ecma_is_value_undefined (this_binding)
|| ecma_is_value_null (this_binding))
@ -825,7 +828,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
/* 5. */
ecma_object_t *local_env_p;
if (is_no_lex_env)
if (status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED)
{
local_env_p = scope_p;
}
@ -841,7 +844,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
bytecode_data_p);
}
#if ENABLED (JERRY_ES2015)
if (JERRY_UNLIKELY (is_class_constructor))
if (JERRY_UNLIKELY (status_flags & CBC_CODE_FLAGS_CONSTRUCTOR))
{
ecma_op_set_class_this_binding (local_env_p, this_binding);
}
@ -854,7 +857,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
arguments_list_p,
arguments_list_len);
if (!is_no_lex_env)
if (!(status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED))
{
ecma_deref_object (local_env_p);
}

View File

@ -30,7 +30,7 @@ extern "C"
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (31u)
#define JERRY_SNAPSHOT_VERSION (32u)
/**
* Flags for jerry_generate_snapshot and jerry_generate_function_snapshot.

View File

@ -149,7 +149,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_JOIN, "join")
#endif
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_KEYS, "keys")
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAME, "name")
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \
#if ENABLED (JERRY_ES2015) \
|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \
|| ENABLED (JERRY_ES2015_BUILTIN_MAP) \
|| ENABLED (JERRY_ES2015_BUILTIN_SET)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NEXT, "next")
@ -246,6 +247,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLICE, "slice")
|| ENABLED (JERRY_ES2015)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPLIT, "split")
#endif
#if ENABLED (JERRY_ES2015)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_THROW, "throw")
#endif
#if ENABLED (JERRY_BUILTIN_MATH) && ENABLED (JERRY_ES2015_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TRUNC, "trunc")
#endif
@ -322,7 +326,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REJECT, "reject")
#if ENABLED (JERRY_BUILTIN_STRING) && ENABLED (JERRY_ES2015_BUILTIN)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPEAT, "repeat")
#endif
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
#if ENABLED (JERRY_ES2015) \
|| ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RETURN, "return")
#endif
#if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \
@ -521,6 +526,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARGUMENTS_UL, "Arguments")
#if ENABLED (JERRY_BUILTIN_ERRORS)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EVAL_ERROR_UL, "EvalError")
#endif
#if ENABLED (JERRY_ES2015)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GENERATOR_UL, "Generator")
#endif
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INT8_ARRAY_UL, "Int8Array")
#endif

View File

@ -113,6 +113,7 @@ LIT_MAGIC_STRING_ROUND = "round"
LIT_MAGIC_STRING_SHIFT = "shift"
LIT_MAGIC_STRING_SLICE = "slice"
LIT_MAGIC_STRING_SPLIT = "split"
LIT_MAGIC_STRING_THROW = "throw"
LIT_MAGIC_STRING_TRUNC = "trunc"
LIT_MAGIC_STRING_VALUE = "value"
LIT_MAGIC_STRING_RESOURCE_EVAL = "<eval>"
@ -226,6 +227,7 @@ LIT_MAGIC_STRING_ARGUMENTS = "arguments"
LIT_MAGIC_STRING_DECODE_URI = "decodeURI"
LIT_MAGIC_STRING_ENCODE_URI = "encodeURI"
LIT_MAGIC_STRING_FIND_INDEX = "findIndex"
LIT_MAGIC_STRING_GENERATOR_UL = "Generator"
LIT_MAGIC_STRING_GET_UTC_DAY_UL = "getUTCDay"
LIT_MAGIC_STRING_GET_UINT16_UL = "getUint16"
LIT_MAGIC_STRING_GET_UINT32_UL = "getUint32"

View File

@ -188,18 +188,18 @@
/* Stack consumption of opcodes with context. */
/* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1
/* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 3
/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
/* PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_BLOCK_CONTEXT_STACK_ALLOCATION 1
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION 1
/**
* Opcode definitions.
@ -654,6 +654,12 @@
VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_SPREAD_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 0, \
VM_OC_CREATE_GENERATOR) \
CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, -1, \
VM_OC_YIELD | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_CONTINUE_EXEC, CBC_NO_FLAG, 1, \
VM_OC_CONTINUE_EXEC) \
\
/* Last opcode (not a real opcode). */ \
CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \
@ -743,7 +749,8 @@ typedef enum
CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */
CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */
CBC_CODE_FLAGS_CONSTRUCTOR = (1u << 10), /**< this function is a constructor */
CBC_CODE_FLAGS_REST_PARAMETER = (1u << 11), /**< this function has rest parameter */
CBC_CODE_FLAGS_GENERATOR = (1u << 11), /**< this function is a generator */
CBC_CODE_FLAGS_REST_PARAMETER = (1u << 12), /**< this function has rest parameter */
} cbc_code_flags;
/**

View File

@ -604,6 +604,19 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
{
if (JERRY_UNLIKELY (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD))
{
#if ENABLED (JERRY_ES2015)
if (keyword_p->type == LEXER_KEYW_YIELD && (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION))
{
if (context_p->status_flags & PARSER_DISALLOW_YIELD)
{
parser_raise_error (context_p, PARSER_ERR_YIELD_NOT_ALLOWED);
}
context_p->token.type = (uint8_t) LEXER_KEYW_YIELD;
break;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->status_flags & PARSER_IS_STRICT)
{
parser_raise_error (context_p, PARSER_ERR_STRICT_IDENT_NOT_ALLOWED);
@ -1521,6 +1534,38 @@ lexer_check_arrow_param (parser_context_t *context_p) /**< context */
|| context_p->source_p[1] != LIT_CHAR_EQUALS);
} /* lexer_check_arrow_param */
/**
* Checks whether the yield expression has no argument.
*
* @return true if it has no argument
*/
bool
lexer_check_yield_no_arg (parser_context_t *context_p) /**< context */
{
if (context_p->token.flags & LEXER_WAS_NEWLINE)
{
return true;
}
switch (context_p->token.type)
{
case LEXER_RIGHT_BRACE:
case LEXER_RIGHT_PAREN:
case LEXER_RIGHT_SQUARE:
case LEXER_COMMA:
case LEXER_COLON:
case LEXER_SEMICOLON:
case LEXER_EOS:
{
return true;
}
default:
{
return false;
}
}
} /* lexer_check_yield_no_arg */
#endif /* ENABLED (JERRY_ES2015) */
/**

View File

@ -983,6 +983,22 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
parser_line_counter_t debugger_column = context_p->token.column;
#endif /* ENABLED (JERRY_DEBUGGER) */
#if ENABLED (JERRY_ES2015)
uint32_t parent_status_flags = context_p->status_flags;
if (lexer_check_next_character (context_p, LIT_CHAR_ASTERISK))
{
/* The name of the function cannot be yield. */
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD;
status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD;
lexer_consume_next_character (context_p);
}
else
{
context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD);
}
#endif /* ENABLED (JERRY_ES2015) */
if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
lexer_next_token (context_p);
@ -1019,6 +1035,10 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
function_name_index = context_p->lit_object.index;
}
#if ENABLED (JERRY_ES2015)
context_p->status_flags = parent_status_flags;
#endif /* ENABLED (JERRY_ES2015) */
}
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
@ -1513,6 +1533,29 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS);
return parser_abort_parsing_after_arrow (context_p);
}
case LEXER_KEYW_YIELD:
{
JERRY_ASSERT ((context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)
&& !(context_p->status_flags & PARSER_DISALLOW_YIELD));
parser_check_assignment_expr (context_p);
lexer_next_token (context_p);
if (!lexer_check_yield_no_arg (context_p))
{
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
}
else
{
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
}
parser_emit_cbc_ext (context_p, CBC_EXT_YIELD);
parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC);
return (context_p->token.type != LEXER_RIGHT_PAREN
&& context_p->token.type != LEXER_COMMA);
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{

View File

@ -55,32 +55,33 @@ typedef enum
PARSER_INSIDE_WITH = (1u << 9), /**< code block is inside a with statement */
PARSER_RESOLVE_BASE_FOR_CALLS = (1u << 10), /**< the this object must be resolved when
* a function without a base object is called */
PARSER_HAS_INITIALIZED_VARS = (1u << 11), /**< a CBC_INITIALIZE_VARS instruction must be emitted */
PARSER_HAS_LATE_LIT_INIT = (1u << 12), /**< allocate memory for this string after
PARSER_HAS_LATE_LIT_INIT = (1u << 11), /**< allocate memory for this string after
* the local parser data is freed */
PARSER_NO_END_LABEL = (1u << 13), /**< return instruction must be inserted
PARSER_NO_END_LABEL = (1u << 12), /**< return instruction must be inserted
* after the last byte code */
PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 14), /**< pending (unsent) breakpoint
PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 13), /**< pending (unsent) breakpoint
* info is available */
#if ENABLED (JERRY_ES2015)
PARSER_INSIDE_BLOCK = (1u << 15), /**< script has a lexical environment for let and const */
PARSER_IS_ARROW_FUNCTION = (1u << 16), /**< an arrow function is parsed */
PARSER_ARROW_PARSE_ARGS = (1u << 17), /**< parse the argument list of an arrow function */
PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 18), /**< function has a non simple parameter */
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
PARSER_INSIDE_BLOCK = (1u << 14), /**< script has a lexical environment for let and const */
PARSER_IS_ARROW_FUNCTION = (1u << 15), /**< an arrow function is parsed */
PARSER_ARROW_PARSE_ARGS = (1u << 16), /**< parse the argument list of an arrow function */
PARSER_IS_GENERATOR_FUNCTION = (1u << 17), /**< a generator function is parsed */
PARSER_DISALLOW_YIELD = (1u << 18), /**< throw SyntaxError for yield expression */
PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 19), /**< function has a non simple parameter */
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 20), /**< function has rest parameter */
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
PARSER_CLASS_CONSTRUCTOR = (1u << 21), /**< a class constructor is parsed (this value must be kept in
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */
PARSER_CLASS_IMPLICIT_SUPER = (1u << 22), /**< class has implicit parent class */
PARSER_CLASS_STATIC_FUNCTION = (1u << 23), /**< this function is a static class method */
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 24), /**< super property call or assignment */
PARSER_IS_EVAL = (1u << 25), /**< eval code */
PARSER_CLASS_HAS_SUPER = (1u << 22), /**< class has super reference */
PARSER_CLASS_IMPLICIT_SUPER = (1u << 23), /**< class has implicit parent class */
PARSER_CLASS_STATIC_FUNCTION = (1u << 24), /**< this function is a static class method */
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 25), /**< super property call or assignment */
PARSER_IS_EVAL = (1u << 26), /**< eval code */
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
PARSER_IS_MODULE = (1u << 26), /**< an export / import keyword is encountered */
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 27), /**< parsing a function or class default export */
PARSER_MODULE_STORE_IDENT = (1u << 28), /**< store identifier of the current export statement */
PARSER_IS_MODULE = (1u << 27), /**< an export / import keyword is encountered */
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 28), /**< parsing a function or class default export */
PARSER_MODULE_STORE_IDENT = (1u << 29), /**< store identifier of the current export statement */
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
#ifndef JERRY_NDEBUG
PARSER_SCANNING_SUCCESSFUL = (1u << 30), /**< scanning process was successful */
@ -624,6 +625,7 @@ uint8_t lexer_consume_next_character (parser_context_t *context_p);
void lexer_skip_empty_statements (parser_context_t *context_p);
bool lexer_check_arrow (parser_context_t *context_p);
bool lexer_check_arrow_param (parser_context_t *context_p);
bool lexer_check_yield_no_arg (parser_context_t *context_p);
#endif /* ENABLED (JERRY_ES2015) */
void lexer_parse_string (parser_context_t *context_p);
void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type);

View File

@ -627,9 +627,6 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */
static void
parser_parse_function_statement (parser_context_t *context_p) /**< context */
{
uint32_t status_flags;
lexer_literal_t *literal_p;
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION);
#if ENABLED (JERRY_ES2015)
@ -646,6 +643,16 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
parser_line_counter_t debugger_column = context_p->token.column;
#endif /* ENABLED (JERRY_DEBUGGER) */
#if ENABLED (JERRY_ES2015)
bool is_generator_function = false;
if (lexer_check_next_character (context_p, LIT_CHAR_ASTERISK))
{
is_generator_function = true;
lexer_consume_next_character (context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
lexer_expect_identifier (context_p, LEXER_NEW_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
@ -663,13 +670,19 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT);
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
if (context_p->lit_object.type != LEXER_LITERAL_OBJECT_ANY)
{
JERRY_ASSERT (context_p->lit_object.type == LEXER_LITERAL_OBJECT_EVAL
|| context_p->lit_object.type == LEXER_LITERAL_OBJECT_ARGUMENTS);
status_flags |= PARSER_HAS_NON_STRICT_ARG;
}
#if ENABLED (JERRY_ES2015)
if (is_generator_function)
{
status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD;
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_DEBUGGER)
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
@ -700,7 +713,7 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */
JERRY_ASSERT (scope_stack_p[1].map_from == PARSER_SCOPE_STACK_FUNC);
literal_p = PARSER_GET_LITERAL ((size_t) scope_stack_p[1].map_to);
lexer_literal_t *literal_p = PARSER_GET_LITERAL ((size_t) scope_stack_p[1].map_to);
JERRY_ASSERT ((literal_p->type == LEXER_UNUSED_LITERAL || literal_p->type == LEXER_FUNCTION_LITERAL)
&& literal_p->status_flags == 0);

View File

@ -932,6 +932,12 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Arguments is not allowed to be used here in strict mode.";
}
#if ENABLED (JERRY_ES2015)
case PARSER_ERR_YIELD_NOT_ALLOWED:
{
return "Incorrect use of yield keyword.";
}
#endif /* ENABLED (JERRY_ES2015) */
case PARSER_ERR_DELETE_IDENT_NOT_ALLOWED:
{
return "Deleting identifier is not allowed in strict mode.";

View File

@ -679,6 +679,11 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code
{
JERRY_DEBUG_MSG (",constructor");
}
if (compiled_code_p->status_flags & CBC_CODE_FLAGS_GENERATOR)
{
JERRY_DEBUG_MSG (",generator");
}
#endif /* ENABLED (JERRY_ES2015) */
JERRY_DEBUG_MSG ("]\n");
@ -1276,6 +1281,11 @@ parser_post_processing (parser_context_t *context_p) /**< context */
compiled_code_p->status_flags |= CBC_CODE_FLAGS_CONSTRUCTOR;
}
if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)
{
compiled_code_p->status_flags |= CBC_CODE_FLAGS_GENERATOR;
}
if (context_p->status_flags & PARSER_FUNCTION_HAS_REST_PARAM)
{
compiled_code_p->status_flags |= CBC_CODE_FLAGS_REST_PARAMETER;
@ -1622,6 +1632,16 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
if (context_p->token.type == end_type)
{
#if ENABLED (JERRY_ES2015)
if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)
{
parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR);
parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC);
parser_emit_cbc (context_p, CBC_POP);
}
context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_YIELD;
#endif /* ENABLED (JERRY_ES2015) */
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
return;
}
@ -1786,6 +1806,17 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, error);
}
#if ENABLED (JERRY_ES2015)
if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)
{
parser_emit_cbc_ext (context_p, CBC_EXT_CREATE_GENERATOR);
parser_emit_cbc_ext (context_p, CBC_EXT_CONTINUE_EXEC);
parser_emit_cbc (context_p, CBC_POP);
}
context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_YIELD;
#endif /* ENABLED (JERRY_ES2015) */
scanner_revert_active (context_p);
scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_BODY);
} /* parser_parse_function_arguments */

View File

@ -73,6 +73,9 @@ typedef enum
PARSER_ERR_STRICT_IDENT_NOT_ALLOWED, /**< identifier name is reserved in strict mode */
PARSER_ERR_EVAL_NOT_ALLOWED, /**< eval is not allowed here in strict mode */
PARSER_ERR_ARGUMENTS_NOT_ALLOWED, /**< arguments is not allowed here in strict mode */
#if ENABLED (JERRY_ES2015)
PARSER_ERR_YIELD_NOT_ALLOWED, /**< yield keyword is not allowed */
#endif /* ENABLED (JERRY_ES2015) */
PARSER_ERR_DELETE_IDENT_NOT_ALLOWED, /**< identifier delete is not allowed in strict mode */
PARSER_ERR_EVAL_CANNOT_ASSIGNED, /**< eval cannot be assigned in strict mode */
PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED, /**< arguments cannot be assigned in strict mode */

View File

@ -175,6 +175,9 @@ typedef enum
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
SCANNER_LITERAL_POOL_IN_EXPORT = (1 << 6), /**< the declared variables are exported by the module system */
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
#if ENABLED (JERRY_ES2015)
SCANNER_LITERAL_POOL_GENERATOR = (1 << 7), /**< generator function */
#endif /* ENABLED (JERRY_ES2015) */
} scanner_literal_pool_flags_t;
/**

View File

@ -402,10 +402,13 @@ scanner_push_literal_pool (parser_context_t *context_p, /**< context */
JERRY_ASSERT (prev_literal_pool_p != NULL);
status_flags |= SCANNER_LITERAL_POOL_NO_ARGUMENTS;
if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
status_flags |= SCANNER_LITERAL_POOL_IN_WITH;
}
#if ENABLED (JERRY_ES2015)
const uint16_t copied_flags = SCANNER_LITERAL_POOL_IN_WITH | SCANNER_LITERAL_POOL_GENERATOR;
#else /* !ENABLED (JERRY_ES2015) */
const uint16_t copied_flags = SCANNER_LITERAL_POOL_IN_WITH;
#endif /* ENABLED (JERRY_ES2015) */
status_flags |= (uint16_t) (prev_literal_pool_p->status_flags & copied_flags);
}
parser_list_init (&literal_pool_p->literal_pool,
@ -775,6 +778,20 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */
prev_literal_pool_p->no_declarations = (uint16_t) no_declarations;
}
#if ENABLED (JERRY_ES2015)
if (is_function && prev_literal_pool_p != NULL)
{
if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_GENERATOR)
{
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
else
{
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
}
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->active_literal_pool_p = literal_pool_p->prev_p;
parser_list_free (&literal_pool_p->literal_pool);

View File

@ -179,7 +179,9 @@ scanner_process_arrow (parser_context_t *context_p, /**< context */
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS;
literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_WITH;
literal_pool_p->status_flags &= (uint16_t) ~(SCANNER_LITERAL_POOL_IN_WITH | SCANNER_LITERAL_POOL_GENERATOR);
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
scanner_filter_arguments (context_p, scanner_context_p);
@ -208,6 +210,8 @@ scanner_process_simple_arrow (parser_context_t *context_p, /**< context */
PARSER_PLUS_EQUAL_LC (context_p->column, 2);
context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES);
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
scanner_check_arrow_body (context_p, scanner_context_p);
} /* scanner_process_simple_arrow */
@ -480,7 +484,21 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
#if ENABLED (JERRY_ES2015)
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_MULTIPLY)
{
scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_GENERATOR;
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
lexer_next_token (context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
@ -609,6 +627,19 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */
#endif /* ENABLED (JERRY_ES2015) */
break;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_YIELD:
{
lexer_next_token (context_p);
if (lexer_check_yield_no_arg (context_p))
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
}
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_RIGHT_PAREN:
{
if (stack_top == SCAN_STACK_PAREN_EXPRESSION)
@ -1590,6 +1621,23 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
case LEXER_KEYW_FUNCTION:
{
lexer_next_token (context_p);
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION;
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_MULTIPLY)
{
status_flags |= SCANNER_LITERAL_POOL_GENERATOR;
lexer_next_token (context_p);
/* This flag should be set after the function name is read. */
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
else
{
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
@ -1618,7 +1666,7 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
scanner_push_literal_pool (context_p, scanner_context_p, status_flags);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT);
@ -3102,6 +3150,7 @@ scan_completed:
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (scanner_context.active_binding_list_p == NULL);
JERRY_ASSERT (!(context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION));
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (scanner_context.active_literal_pool_p == NULL);
@ -3147,6 +3196,10 @@ scan_completed:
}
}
PARSER_TRY_END
#if ENABLED (JERRY_ES2015)
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
#endif /* ENABLED (JERRY_ES2015) */
}
PARSER_TRY_END

View File

@ -118,12 +118,15 @@ defined to `1`.
Enables or disable the [module system](http://www.ecma-international.org/ecma-262/6.0/#sec-modules) language element.
* `JERRY_ES2015`: Enables or disable all of the implemented [ECMAScript2015 features](http://www.ecma-international.org/ecma-262/6.0/).
* [arrow functions](http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions) language element.
* [symbol](https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects) language element.
* [class](https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions) language element.
* [for of](https://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements) language element.
* [default value](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) for formal parameters.
* [rest parameter](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) language element.
* [destructuring assignment](http://www.ecma-international.org/ecma-262/6.0/#sec-destructuring-assignment) language element.
* [destructuring binding pattern](http://www.ecma-international.org/ecma-262/6.0/#sec-destructuring-binding-patterns) declarations.
* [enhanced object initializer](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) language element.
* [for-of](https://www.ecma-international.org/ecma-262/6.0/#sec-for-in-and-for-of-statements) language element.
* [generator functions](http://www.ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions) language element.
* [rest parameter](http://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions) language element.
* [symbol](https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects) language element.
* [template strings](http://www.ecma-international.org/ecma-262/6.0/#sec-static-semantics-templatestrings) language element.
This option is evaulated first, any other `JERRY_ES2015_<name>` defines will override that specific entry.
Equivalent with setting the following defines to the `JERRY_ES2015` value:

View File

@ -30,6 +30,7 @@
#include "jcontext.h"
#include "opcodes.h"
#include "vm-defines.h"
#include "vm-stack.h"
/** \addtogroup vm Virtual machine
* @{
@ -280,6 +281,7 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */
} /* opfunc_for_in */
#if ENABLED (JERRY_ES2015)
/**
* 'VM_OC_APPEND_ARRAY' opcode handler specialized for spread objects
*
@ -454,6 +456,7 @@ opfunc_spread_arguments (ecma_value_t *stack_top_p, /**< pointer to the current
return buff_p;
} /* opfunc_spread_arguments */
#endif /* ENABLED (JERRY_ES2015) */
/**
@ -539,6 +542,176 @@ opfunc_append_array (ecma_value_t *stack_top_p, /**< current stack top */
return ECMA_VALUE_EMPTY;
} /* opfunc_append_array */
#if ENABLED (JERRY_ES2015)
/**
* Create an executable object using the current frame context
*
* @return executable object
*/
ecma_value_t
opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p;
size_t size;
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_header_p);
if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p;
size = ((size_t) args_p->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;
size = ((size_t) args_p->register_end + (size_t) args_p->stack_limit) * sizeof (ecma_value_t);
}
size_t total_size = JERRY_ALIGNUP (sizeof (vm_executable_object_t) + size, sizeof (uintptr_t));
ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_GENERATOR_PROTOTYPE),
total_size,
ECMA_OBJECT_TYPE_CLASS);
vm_executable_object_t *executable_object_p = (vm_executable_object_t *) object_p;
executable_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_GENERATOR_UL;
executable_object_p->extended_object.u.class_prop.extra_info = 0;
JERRY_ASSERT (!frame_ctx_p->is_eval_code);
JERRY_ASSERT (frame_ctx_p->context_depth == 0);
vm_frame_ctx_t *new_frame_ctx_p = &(executable_object_p->frame_ctx);
*new_frame_ctx_p = *frame_ctx_p;
/* The old register values are discarded. */
ecma_value_t *new_registers_p = VM_GET_REGISTERS (new_frame_ctx_p);
memcpy (new_registers_p, VM_GET_REGISTERS (frame_ctx_p), size);
size_t stack_top = (size_t) (frame_ctx_p->stack_top_p - VM_GET_REGISTERS (frame_ctx_p));
ecma_value_t *new_stack_top_p = new_registers_p + stack_top;
new_frame_ctx_p->stack_top_p = new_stack_top_p;
/* Initial state is "not running", so all object references are released. */
while (new_registers_p < new_stack_top_p)
{
ecma_deref_if_object (*new_registers_p++);
}
new_frame_ctx_p->this_binding = ecma_copy_value_if_not_object (new_frame_ctx_p->this_binding);
JERRY_CONTEXT (vm_top_context_p) = new_frame_ctx_p->prev_context_p;
return ecma_make_object_value (object_p);
} /* opfunc_create_executable_object */
/**
* Resume the execution of an inactive executable object
*
* @return value provided by the execution
*/
ecma_value_t
opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /**< executable object */
ecma_value_t value) /**< value pushed onto the stack */
{
const ecma_compiled_code_t *bytecode_header_p = executable_object_p->frame_ctx.bytecode_header_p;
ecma_value_t *register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
ecma_value_t *register_end_p;
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_p = register_p + args_p->register_end;
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p;
register_end_p = register_p + args_p->register_end;
}
while (register_p < register_end_p)
{
ecma_ref_if_object (*register_p++);
}
if (executable_object_p->frame_ctx.context_depth > 0)
{
vm_ref_lex_env_chain (executable_object_p->frame_ctx.lex_env_p,
executable_object_p->frame_ctx.context_depth,
register_p,
true);
register_p += executable_object_p->frame_ctx.context_depth;
}
ecma_value_t *stack_top_p = executable_object_p->frame_ctx.stack_top_p;
while (register_p < stack_top_p)
{
ecma_ref_if_object (*register_p++);
}
uint8_t *byte_code_p = executable_object_p->frame_ctx.byte_code_p;
JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE && byte_code_p[1] == CBC_EXT_CONTINUE_EXEC);
*register_p++ = ecma_copy_value (value);
executable_object_p->frame_ctx.stack_top_p = register_p;
JERRY_ASSERT (ECMA_EXECUTABLE_OBJECT_IS_SUSPENDED (executable_object_p->extended_object.u.class_prop.extra_info));
executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_RUNNING;
executable_object_p->frame_ctx.prev_context_p = JERRY_CONTEXT (vm_top_context_p);
JERRY_CONTEXT (vm_top_context_p) = &executable_object_p->frame_ctx;
ecma_value_t result = vm_execute (&executable_object_p->frame_ctx);
executable_object_p->extended_object.u.class_prop.extra_info &= (uint16_t) ~ECMA_EXECUTABLE_OBJECT_RUNNING;
if (executable_object_p->frame_ctx.call_operation != VM_EXEC_RETURN)
{
JERRY_ASSERT (executable_object_p->frame_ctx.call_operation == VM_NO_EXEC_OP);
/* All resources are released. */
executable_object_p->extended_object.u.class_prop.extra_info |= ECMA_EXECUTABLE_OBJECT_COMPLETED;
return result;
}
JERRY_CONTEXT (vm_top_context_p) = executable_object_p->frame_ctx.prev_context_p;
register_p = VM_GET_REGISTERS (&executable_object_p->frame_ctx);
while (register_p < register_end_p)
{
ecma_deref_if_object (*register_p++);
}
if (executable_object_p->frame_ctx.context_depth > 0)
{
vm_ref_lex_env_chain (executable_object_p->frame_ctx.lex_env_p,
executable_object_p->frame_ctx.context_depth,
register_p,
false);
register_p += executable_object_p->frame_ctx.context_depth;
}
stack_top_p = executable_object_p->frame_ctx.stack_top_p;
while (register_p < stack_top_p)
{
ecma_deref_if_object (*register_p++);
}
return result;
} /* opfunc_resume_executable_object */
#endif /* ENABLED (JERRY_ES2015) */
/**
* @}
* @}

View File

@ -101,12 +101,20 @@ vm_op_delete_var (ecma_value_t name_literal, ecma_object_t *lex_env_p);
ecma_collection_t *
opfunc_for_in (ecma_value_t left_value, ecma_value_t *result_obj_p);
#if ENABLED (JERRY_ES2015)
ecma_collection_t *
opfunc_spread_arguments (ecma_value_t *stack_top_p, uint8_t argument_list_len);
#endif /* ENABLED (JERRY_ES2015) */
ecma_value_t
opfunc_append_array (ecma_value_t *stack_top_p, uint16_t values_length);
#if ENABLED (JERRY_ES2015)
ecma_collection_t *
opfunc_spread_arguments (ecma_value_t *stack_top_p, uint8_t argument_list_len);
ecma_value_t
opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p);
ecma_value_t
opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ecma_value_t value);
#endif /* ENABLED (JERRY_ES2015) */
/**

View File

@ -64,12 +64,21 @@ typedef struct vm_frame_ctx_t
/**
* Get register list corresponding to the frame context.
*/
#define VM_GET_REGISTERS(frame_ctx_p) ((ecma_value_t *) (frame_ctx_p + 1))
#define VM_GET_REGISTERS(frame_ctx_p) ((ecma_value_t *) ((frame_ctx_p) + 1))
/**
* Read or write a specific register.
*/
#define VM_GET_REGISTER(frame_ctx_p, i) (((ecma_value_t *) (frame_ctx_p + 1))[i])
#define VM_GET_REGISTER(frame_ctx_p, i) (((ecma_value_t *) ((frame_ctx_p) + 1))[i])
/**
* Generator frame context.
*/
typedef struct
{
ecma_extended_object_t extended_object; /**< extended object part */
vm_frame_ctx_t frame_ctx; /**< frame context part */
} vm_executable_object_t;
/**
* @}

View File

@ -56,35 +56,21 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
case VM_CONTEXT_FINALLY_RETURN:
{
ecma_free_value (vm_stack_top_p[-2]);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
break;
/* FALLTHRU */
}
case VM_CONTEXT_FINALLY_JUMP:
case VM_CONTEXT_TRY:
case VM_CONTEXT_CATCH:
{
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
break;
}
case VM_CONTEXT_CATCH:
{
JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION > PARSER_WITH_CONTEXT_STACK_ALLOCATION);
const uint16_t size_diff = PARSER_TRY_CONTEXT_STACK_ALLOCATION - PARSER_WITH_CONTEXT_STACK_ALLOCATION;
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, size_diff);
vm_stack_top_p -= size_diff;
/* FALLTHRU */
}
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_BLOCK:
#endif /* ENABLED (JERRY_ES2015) */
case VM_CONTEXT_WITH:
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_SUPER_CLASS:
#endif /* ENABLED (JERRY_ES2015) */
case VM_CONTEXT_WITH:
{
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_WITH_CONTEXT_STACK_ALLOCATION;
@ -116,7 +102,7 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_collection_destroy (collection_p);
ecma_deref_object (ecma_get_object_from_value (vm_stack_top_p[-4]));
ecma_free_value (vm_stack_top_p[-4]);
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
@ -296,6 +282,109 @@ vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
return false;
} /* vm_stack_find_finally */
#if ENABLED (JERRY_ES2015)
/**
* Get the offsets of ecma values from the specified item of a context.
*
* @return array of offsets, last item represents the size of the context item
*/
uint32_t
vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a context */
{
switch (VM_GET_CONTEXT_TYPE (context_item_p[-1]))
{
case VM_CONTEXT_FINALLY_THROW:
case VM_CONTEXT_FINALLY_RETURN:
{
return (2 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_TRY_CONTEXT_STACK_ALLOCATION;
}
case VM_CONTEXT_FINALLY_JUMP:
case VM_CONTEXT_TRY:
case VM_CONTEXT_CATCH:
{
return PARSER_TRY_CONTEXT_STACK_ALLOCATION;
}
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_BLOCK:
case VM_CONTEXT_SUPER_CLASS:
#endif /* ENABLED (JERRY_ES2015) */
case VM_CONTEXT_WITH:
{
return PARSER_WITH_CONTEXT_STACK_ALLOCATION;
}
#if ENABLED (JERRY_ES2015)
case VM_CONTEXT_FOR_OF:
{
return ((3 << (VM_CONTEXT_OFFSET_SHIFT * 2))
| (2 << (VM_CONTEXT_OFFSET_SHIFT))
| PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
return (4 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
}
}
} /* vm_get_context_value_offsets */
/**
* Ref / deref lexical environments in the chain using the current context.
*/
void
vm_ref_lex_env_chain (ecma_object_t *lex_env_p, /**< top of lexical environment */
uint16_t context_depth, /**< depth of function context */
ecma_value_t *context_end_p, /**< end of function context */
bool do_ref) /**< ref or deref lexical environments */
{
ecma_value_t *context_top_p = context_end_p + context_depth;
JERRY_ASSERT (context_top_p > context_end_p);
do
{
if (context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV)
{
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
ecma_object_t *next_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
if (do_ref)
{
ecma_ref_object (lex_env_p);
}
else
{
ecma_deref_object (lex_env_p);
}
lex_env_p = next_lex_env_p;
}
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 (do_ref)
{
ecma_ref_if_object (context_top_p[offset]);
}
else
{
ecma_deref_if_object (context_top_p[offset]);
}
offsets >>= VM_CONTEXT_OFFSET_SHIFT;
}
JERRY_ASSERT (context_top_p >= context_end_p + offsets);
context_top_p -= offsets;
}
while (context_top_p > context_end_p);
} /* vm_ref_lex_env_chain */
#endif /* ENABLED (JERRY_ES2015) */
/**
* @}
* @}

View File

@ -79,9 +79,27 @@ typedef enum
#define VM_CONTEXT_IS_FINALLY(context_type) \
((context_type) <= VM_CONTEXT_FINALLY_RETURN)
/**
* Shift needs to be applied to get the next item of the offset array.
*/
#define VM_CONTEXT_OFFSET_SHIFT 4
/**
* Checks whether an offset is available.
*/
#define VM_CONTEXT_HAS_NEXT_OFFSET(offsets) ((offsets) >= (1 << VM_CONTEXT_OFFSET_SHIFT))
/**
* Gets the next offset from the offset array.
*/
#define VM_CONTEXT_GET_NEXT_OFFSET(offsets) (-((int32_t) ((offsets) & ((1 << VM_CONTEXT_OFFSET_SHIFT) - 1))))
ecma_value_t *vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, ecma_value_t *vm_stack_top_p);
bool vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top_ref_p,
vm_stack_context_type_t finally_type, uint32_t search_limit);
uint32_t vm_get_context_value_offsets (ecma_value_t *context_item_p);
void vm_ref_lex_env_chain (ecma_object_t *lex_env_p, uint16_t context_depth,
ecma_value_t *context_end_p, bool do_ref);
/**
* @}

View File

@ -2062,7 +2062,47 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
frame_ctx_p->stack_top_p = stack_top_p;
return ECMA_VALUE_UNDEFINED;
}
#endif /* ENABLED (JERRY_ES2015) */
case VM_OC_CREATE_GENERATOR:
{
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
return opfunc_create_executable_object (frame_ctx_p);
}
case VM_OC_YIELD:
{
frame_ctx_p->call_operation = VM_EXEC_RETURN;
frame_ctx_p->byte_code_p = byte_code_p;
frame_ctx_p->stack_top_p = stack_top_p;
return left_value;
}
case VM_OC_CONTINUE_EXEC:
{
if (JERRY_UNLIKELY (frame_ctx_p->call_operation == ECMA_GENERATOR_RETURN))
{
ecma_value_t *stack_bottom_p = VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth;
result = *(--stack_top_p);
while (stack_top_p > stack_bottom_p)
{
ecma_fast_free_value (*(--stack_top_p));
}
goto error;
}
if (JERRY_UNLIKELY (frame_ctx_p->call_operation == ECMA_GENERATOR_THROW))
{
JERRY_CONTEXT (error_value) = *(--stack_top_p);
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
result = ECMA_VALUE_ERROR;
goto error;
}
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
case VM_OC_PUSH_ELISON:
{
*stack_top_p++ = ECMA_VALUE_ARRAY_HOLE;
@ -3804,8 +3844,8 @@ free_both_values:
free_left_value:
ecma_fast_free_value (left_value);
}
error:
error:
ecma_fast_free_value (left_value);
ecma_fast_free_value (right_value);
@ -4031,7 +4071,7 @@ vm_init_exec (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
*
* @return ecma value
*/
static ecma_value_t JERRY_ATTR_NOINLINE
ecma_value_t JERRY_ATTR_NOINLINE
vm_execute (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
{
while (true)
@ -4056,6 +4096,10 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
vm_spread_operation (frame_ctx_p);
break;
}
case VM_EXEC_RETURN:
{
return completion_value;
}
#endif /* ENABLED (JERRY_ES2015) */
case VM_EXEC_CONSTRUCT:
{

View File

@ -255,6 +255,9 @@ typedef enum
VM_OC_REST_INITIALIZER, /**< create rest object inside an array pattern */
VM_OC_INITIALIZER_PUSH_PROP, /**< push property for object initializer */
VM_OC_SPREAD_ARGUMENTS, /**< perform function call/construct with spreaded arguments */
VM_OC_CREATE_GENERATOR, /**< create a generator object */
VM_OC_YIELD, /**< yield operation */
VM_OC_CONTINUE_EXEC, /**< first byte code after a function is resumed */
#endif /* ENABLED (JERRY_ES2015) */
VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
@ -305,6 +308,9 @@ typedef enum
VM_OC_REST_INITIALIZER = VM_OC_NONE, /**< create rest object inside an array pattern */
VM_OC_INITIALIZER_PUSH_PROP = VM_OC_NONE, /**< push property for object initializer */
VM_OC_SPREAD_ARGUMENTS = VM_OC_NONE, /**< perform function call/construct with spreaded arguments */
VM_OC_CREATE_GENERATOR = VM_OC_NONE, /**< create a generator object */
VM_OC_YIELD = VM_OC_NONE, /**< yield operation */
VM_OC_CONTINUE_EXEC = VM_OC_NONE, /**< first byte code after a function is resumed */
#endif /* !ENABLED (JERRY_ES2015) */
VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */
@ -388,6 +394,7 @@ typedef enum
VM_EXEC_CALL, /**< invoke a function */
VM_EXEC_SUPER_CALL, /**< invoke a function through 'super' keyword */
VM_EXEC_SPREAD_OP, /**< call/construct operation with spreaded argument list */
VM_EXEC_RETURN, /**< return with the completion value without freeing registers */
VM_EXEC_CONSTRUCT, /**< construct a new object */
} vm_call_operation;
@ -400,6 +407,7 @@ ecma_value_t vm_run_module (const ecma_compiled_code_t *bytecode_p, ecma_object_
ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t this_binding_value,
ecma_object_t *lex_env_p, const ecma_value_t *arg_list_p, ecma_length_t arg_list_len);
ecma_value_t vm_execute (vm_frame_ctx_t *frame_ctx_p);
bool vm_is_strict_mode (void);
bool vm_is_direct_eval_form_call (void);

View File

@ -0,0 +1,74 @@
/* 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.
*/
function check_result(result, value, done)
{
assert(result.value === value)
assert(result.done === done)
}
function * gen1(a) {
return "a: " + (yield a.p)
}
var f = gen1({})
check_result(f.return(4), 4, true)
check_result(f.next(), undefined, true)
f = gen1({ p:"x" })
check_result(f.next(), "x", false)
check_result(f.return(10), 10, true)
check_result(f.next(), undefined, true)
f = gen1({ p:"b" })
check_result(f.next(), "b", false)
check_result(f.next(), "a: undefined", true)
check_result(f.next(), undefined, true)
function*gen2() {
try {
for (let i in { x:1, y:2 })
{
assert((yield i) === "33")
}
assert(false)
} catch (e) {
assert(false)
} finally {
yield "z"
}
}
f = gen2()
check_result(f.return("ret"), "ret", true)
check_result(f.next(), undefined, true)
f = gen2()
check_result(f.next(), "x", false)
check_result(f.return("ret"), "z", false)
check_result(f.next(), "ret", true)
check_result(f.next(), undefined, true)
function* gen3() {
try {
return 8
} finally {
yield 1
}
}
f = gen3()
check_result(f.next(), 1, false)
check_result(f.return(2), 2, true)

View File

@ -0,0 +1,82 @@
/* 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.
*/
function check_result(result, value, done)
{
assert(result.value === value)
assert(result.done === done)
}
function check_throw(str, expected)
{
try {
eval(str)
assert(false);
} catch (e) {
assert(e === expected);
}
}
function * gen1(a) {
return "a: " + (yield a.p)
}
var f = gen1({})
check_throw("f.throw(4)", 4)
check_result(f.next(), undefined, true)
f = gen1({ p:"x" })
check_result(f.next(), "x", false)
check_throw("f.throw(10)", 10)
check_result(f.next(), undefined, true)
f = gen1({ p:"b" })
check_result(f.next(), "b", false)
check_result(f.next(), "a: undefined", true)
check_result(f.next(), undefined, true)
function*gen2() {
try {
for (let i in { x:1, y:2 })
{
assert((yield i) === "33")
}
assert(false)
} finally {
yield "z"
}
}
f = gen2()
check_throw("f.throw('throw')", "throw")
check_result(f.next(), undefined, true)
f = gen2()
check_result(f.next(), "x", false)
check_result(f.throw("throw"), "z", false)
check_throw("f.next()", "throw")
check_result(f.next(), undefined, true)
function* gen3() {
try {
return 8
} finally {
yield 1
}
}
f = gen3()
check_result(f.next(), 1, false)
check_throw("f.throw(2)", 2)

View File

@ -0,0 +1,73 @@
/* 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.
*/
/* This file checks yield syntax errors. */
function check_syntax_error(str)
{
try {
eval(str);
assert(false);
} catch (e) {
assert(e instanceof SyntaxError);
}
}
function * gen()
{
yield , yield
yield
, yield
(yield
)
yield[
1]
}
function*gen2()
{
1 ?
yield
:
yield
}
var gen3 = function*(){
(yield)/[yield]
}
check_syntax_error("function *gen(){ yield % yield }");
check_syntax_error("function *gen(){ (yield) % yield }");
check_syntax_error("function *gen(){ yield % (yield) }");
check_syntax_error("function *gen(){ (yield\n1) }");
check_syntax_error("function *gen(){ function yield() {} }");
check_syntax_error("function *gen(){ (yield)=>1 }");
check_syntax_error("function *gen(){ yield => 1 }");
function *gen4() {
var f = function yield(i) {
if (i = 0)
return yield(i + 1)
return 39
}
return f(0)
}
assert(gen4().next().value === 39);

View File

@ -0,0 +1,199 @@
/* 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.
*/
/* This file checks core generator operations. */
function check_result(result, value, done)
{
assert(result.value === value)
assert(result.done === done)
}
function * gen1(a = (t = 8)) {
var o = { p: 2 }
var x = 3.25
assert((o.p + (yield 10)) === 23)
assert((o.p + (yield 11)) === 24)
return x
}
/* Cannot be invoked with new. */
try {
new gen1
assert(false)
} catch (e) {
assert(e instanceof TypeError)
}
/* Fully read values. */
var t = 0
var g = gen1()
assert(t === 8)
check_result(g.next(20), 10, false)
check_result(g.next(21), 11, false)
check_result(g.next(22), 3.25, true)
check_result(g.next(23), undefined, true)
/* Partly read values (gc needs to free a suspended generator). */
t = 0
g = gen1()
assert(t === 8)
check_result(g.next(20), 10, false)
function * gen2() {
for (i in { x:0, y:1, z:2 })
{
let a = eval("'s'")
var b = yield a + i
assert (b === ++t)
}
}
/* Fully read values. */
t = 0
f = gen2()
check_result(f.next(0), "sx", false)
check_result(f.next(1), "sy", false)
check_result(f.next(2), "sz", false)
check_result(f.next(3), undefined, true)
check_result(f.next(4), undefined, true)
/* Partly read values (gc needs to free a suspended generator). */
f = gen2()
t = 0
check_result(f.next(0), "sx", false)
function *gen3() {
function f(yield) {
return -yield * 2
}
var g = (v) => {
assert(v === 6)
}
g(yield yield f(++t))
return 77
}
/* Fully read values. */
t = 0
f = gen3()
check_result(f.next(0), -2, false)
check_result(f.next(88), 88, false)
check_result(f.next(6), 77, true)
/* Partly read values (gc needs to free a suspended generator). */
t = 0
f = gen3()
check_result(f.next(0), -2, false)
function
/* generator: */ *
/* name: */ gen4() {
let a = eval("5")
with ({a})
{
let a = eval("6")
for (let a = 10; a < 11; a++)
{
let a = eval("7")
yield (a)
}
yield a, !assert(a === 6)
}
assert((yield a) === undefined)
}
/* Fully read values. */
f = gen4()
check_result(f.next(), 7, false)
check_result(f.next(), 6, false)
check_result(f.next(), 5, false)
check_result(f.next(), undefined, true)
/* Partly read values (gc needs to free a suspended generator). */
f = gen4()
check_result(f.next(), 7, false)
function*gen5(a,b,c,d) {
yield a
yield b
yield c
yield d
}
/* Fully read values. */
t = []
for(let i of gen5(1,3,5,7)) {
t.push(i)
}
assert(t.length === 4)
assert(t[0] === 1)
assert(t[1] === 3)
assert(t[2] === 5)
assert(t[3] === 7)
/* Partly read values (gc needs to free a suspended generator). */
t = []
for(let i of gen5(1,3,5,7)) {
t.push(i)
if (i === 3) {
break
}
}
assert(t.length === 2)
assert(t[0] === 1)
assert(t[1] === 3)
/* Recursive generator call. */
function* gen6(a,b,c,d) {
yield f.next()
}
f = gen6()
try {
f.next()
assert(false)
} catch (e) {
assert(e instanceof TypeError)
}
/* Parameterless yield. */
function* gen7() {
yield
}
f = gen7()
check_result(f.next(), undefined, false)
check_result(f.next(), undefined, true)

View File

@ -223,7 +223,7 @@ main (void)
/* Check the snapshot data. Unused bytes should be filled with zeroes */
const uint8_t expected_data[] =
{
0x4A, 0x52, 0x52, 0x59, 0x1F, 0x00, 0x00, 0x00,
0x4A, 0x52, 0x52, 0x59, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,